@import url('https://fonts.googleapis.com/css2?family=Public+Sans:wght@400..700&display=swap');

/* =====================================================================
   Tokens — ver DESIGN.md.
   Os nomes são os do documento (`## Colors`): canvas, ink, surface-card,
   hairline. Eles são lidos direto pelo JS em `style=` inline e pelo
   getComputedStyle do app.js — estender é livre, renomear quebra o app, e o
   tokens.check.js é quem prova que nenhum nome antigo sobrou.

   ── Quatro decisões registradas, para não parecerem descuido ────────────

   1. TEMA CLARO É DERIVADO. O documento é escuro puro e diz "the brand never
      warms to a light surface": ele não descreve tema claro nenhum. O
      vocabulário claro que existe lá é só de texto — `on-light #000000` e
      `on-light-mute rgba(0,0,51,.7)`, usados no cartão de e-mail branco.
      Medi os accents do documento sobre fundo claro e TODOS reprovam:
      blue 2.79:1, orange 2.51:1, red 3.78:1, yellow 1.58:1, green 1.33:1.
      São calibrados para o preto. Onde o documento é silencioso, a regra é
      derivar da lógica dele: aqui, preservar o MATIZ (que é o sinal da marca)
      e baixar a luminosidade até 4.5:1. Foi o que fiz, com os números abaixo.

   2. BORDA DE 1.35:1 É REGRESSÃO CONSCIENTE (decidida em 2026-09-02).
      `hairline-strong` é branco a 14%, que dá 1.35:1 sobre o canvas. O sistema
      anterior sustentava 3:1 em fronteira de controle (WCAG 1.4.11) com o
      `--hairline-strong`. Eu levantei; a decisão foi por fidelidade ao
      documento, que especifica 14% e não tem sombra nenhuma para compensar.
      O que NÃO regride é o foco: o documento manda a borda engrossar para
      `ink` no foco, e ink sobre canvas dá 20.63:1 — navegação por teclado
      continua nítida. O que regride é enxergar um campo em repouso.
      Para reverter, o número é 36% de branco (3.14:1); ver contraste.check.js.
      No ESCURO a borda subiu para 20% (1.86:1) junto com a decisão 4.

   3. SEM BORDA, SÓ EM CAMPO (decidida em 2026-09-23, pelo produto). Nada tem
      borda — cartão, botão, painel, badge, divisor, faixa lateral —, exceto
      campo de digitação (input, select, textarea e o que se comporta como um).
      Contraria o documento, que desenha tudo com hairline: aqui quem separa é
      o FUNDO — --preenchimento em controle e seção, --fundo-* em estado,
      --surface-flutuante + --sombra-flutuante no que flutua sobre a página (a
      única sombra do sistema: sem borda, é o que descola um menu da página).
      Ficam o anel dos spinners, o quadrado dos checkboxes, o anel de foco
      (:focus-visible), que é acessibilidade, não desenho — e DUAS divisórias,
      ambas pedidas de volta no mesmo dia: a linha sob a .menubar (separa a
      navegação das abas de trabalho, que têm o mesmo fundo) e a linha sob a
      .topbar (separa a topbar da menubar logo abaixo, também no mesmo fundo).
      Em 2026-09-26 entrou o separador de coluna das tabelas (.col-redim), que
      é a alça de ajustar a largura.
      E estado ativo NÃO engrossa texto: ativo é fundo e cor, nunca 600/700.
      O estilo.check.js guarda as duas regras.

   4. ESCURO "DIM", NÃO PRETO PURO (decidida em 2026-09-24, pelo produto).
      O documento manda canvas #000000 e "never near-black". Com a decisão 3
      (sem borda), cartão #0a0a0c sobre #000 dava 1.03:1 e a tela virava uma
      mancha preta de pouco contraste. O canvas passou a #121419 e cada camada
      sobe um passo visível; os valores e o porquê estão no bloco do tema
      escuro logo abaixo. O tema claro não mudou.
   ===================================================================== */
:root {
    /* Sem isto o navegador desenha todo controle nativo no tema errado — o
       ícone do calendário do <input type="month">, a seta do <select>. */
    color-scheme: light;

    /* ── Superfície (derivada) ──────────────────────────────────────────
       Espelha a estrutura do documento em vez de inverter cores: lá o canvas é
       o extremo (preto puro) e os cartões dão um passo PARA DENTRO. Aqui o
       canvas é o branco puro e os cartões dão um passo para dentro também,
       guardando o tom frio azulado do `surface-light #f1f7fe` do documento. */
    --canvas: #ffffff;
    --surface-card: #f7f9fd;
    --surface-elevated: #f1f7fe;   /* o próprio surface-light do documento */
    --surface-deep: #eaf0f8;       /* poço de código */
    --surface-hover: #e9eff8;
    /* Camada flutuante (menu de contexto, dropdown, popover, toast). Sem borda
       nenhuma no sistema (ver decisão 3 no topo), quem a descola da página no
       claro é a sombra — então o fundo pode ser o próprio canvas. */
    --surface-flutuante: #ffffff;
    --sombra-flutuante: 0 12px 32px rgba(0, 0, 51, 0.12), 0 2px 8px rgba(0, 0, 51, 0.06);

    /* Hairline espelhada: a tinta do documento é `rgba(0,0,51,…)`, não preto
       puro — o mesmo azul frio que o `on-light-mute` carrega. */
    --hairline: rgba(0, 0, 51, 0.06);
    --hairline-strong: rgba(0, 0, 51, 0.14);
    --divider-soft: rgba(0, 0, 51, 0.04);

    --ink: #000000;                       /* on-light do documento — 21:1 */
    --body: rgba(0, 0, 51, 0.86);
    --charcoal: rgba(0, 0, 51, 0.70);     /* on-light-mute — 7.82:1 */
    --mute: #4a4f57;                      /* 8.2:1 */
    --ash: #5c626b;                       /* 6.1:1 */
    --stone: #9aa0a8;                     /* desabilitado — isento de AA */

    /* Ação: era o retângulo preto-no-claro/branco-no-escuro do DESIGN.md (o
       "âncora" pelo extremo). Trocado por decisão do produto: o app quer um
       CTA azul único, não o preto/branco monocromático do documento — mesmo
       azul de `--link`, que já emparelha com `--primary-on` em dois lugares
       (`.central-toolbar-filter .count`, `.central-filter-actions
       .btn-confirm`). Valor literal (não `var(--link)`): contraste.check.js
       só entende #hex/rgba() ao ler os tokens, var() ficaria de fora da conta. */
    --primary: #006fdc;
    --primary-on: #ffffff;
    --primary-hover: color-mix(in srgb, var(--link) 85%, black);
    --primary-pressed: color-mix(in srgb, var(--link) 70%, black);

    /* ── Accents derivados: matiz do documento, luminosidade do fundo ──── */
    --accent-blue: #006fdc;      /* de #3b9eff — 4.88:1 */
    --accent-orange: #bb5100;    /* de #ff801f — 4.90:1 */
    --accent-yellow: #966900;    /* de #ffc53d — 4.86:1 */
    --accent-green: #00814a;     /* de #11ff99 — 4.95:1 */
    --accent-red: #e20027;       /* de #ff2047 — 4.93:1 */
    --link: #006fdc;

    /* Passo de MARCA (>=3:1): ponto, badge, barra. Objeto gráfico não precisa
       de 4.5:1, e usar o passo de texto em tudo deixa a tela sem cor. */
    --accent-green-vivid: #00a25d;
    --accent-red-vivid: #ec0029;    /* branco por cima a 4.57:1 (o #ff2047 do
                                       documento reprova sob texto no claro) */
    --accent-orange-vivid: #eb6600;
    --accent-blue-vivid: #006fdc;

    /* Glow atmosférico: no claro o wash tem de ser MAIS fraco, senão vira
       mancha suja sobre branco. Mesma ideia, metade da opacidade. */
    --glow-orange: rgba(255, 89, 0, 0.10);
    --glow-blue: rgba(0, 117, 255, 0.12);
    --glow-green: rgba(34, 255, 153, 0.10);
    --glow-red: rgba(255, 32, 71, 0.12);

    /* Fundo tingido de estado. Não está no documento; derivado do accent com o
       mesmo matiz, no grau mais leve que ainda se distingue do canvas. */
    --fundo-ok: #eef8f3;
    --fundo-erro: #fdf3f4;
    --fundo-aviso: #fdf5e8;
    --fundo-info: #f1f7fe;
    --on-red: #ffffff;

    /* Tinta de LINHA INTEIRA, mais forte que a de badge. Duas superfícies e
       não uma porque o texto por cima é outro: numa linha da tabela o texto é
       `--ink` (15:1 aqui, sobra), num badge é `--accent-orange` — e o laranja
       do tema claro (#bb5100) dá 3.74:1 sobre este tom, abaixo do mínimo de
       4.5 do WCAG AA. Usar o mesmo valor nos dois faria a linha aparecer e o
       badge ficar ilegível. Ver contraste.check.js. */
    --fundo-linha-aviso: #f6deb7;

    /* Marca de terceiro: valor fixo, não é paleta nossa. */
    --marca-whatsapp: #25D366;
    /* QR é preto sobre branco nos DOIS temas, ou o celular não lê. */
    --qr-tinta: #000000;
    --qr-papel: #ffffff;
    /* Painel azul do login: fixo nos dois temas (não acompanha claro/escuro).
       Um azul-marinho de base, dois brilhos mais claros que derivam por cima e
       o traço fino das ondas. Texto branco: 11:1 sobre a base. */
    --login-azul: #0a3a8c;
    --login-brilho: #2f7dff;
    --login-brilho-claro: #56b4ff;
    --login-linha: rgba(255, 255, 255, 0.34);
    --login-texto: #ffffff;

    /* ── Séries de gráfico ──────────────────────────────────────────────
       Oito passos derivados dos cinco accents do documento mais três no mesmo
       registro (rosa, teal, roxo). A ORDEM é mecanismo de segurança para
       daltonismo, não estética: azul e laranja adjacentes é o par seguro
       clássico, e foi preservado do sistema anterior. Não reordenar.
       Todos derivados a 4.5:1 sobre o branco — bem acima do mínimo de 2:1 que
       a guarda exige para série. */
    --serie-1: #0074e6;  --serie-2: #c25400;  --serie-3: #00864d;  --serie-4: #9b6d00;
    --serie-5: #e8006c;  --serie-6: #00866b;  --serie-7: #7e55f8;  --serie-8: #ec0029;
    /* 9 e 10 (devolução sem nota, backup): os dois vãos que sobravam no círculo
       de matiz — amarelo-esverdeado e fúcsia —, na mesma faixa de ~4.6:1. Não
       passaram pelo validador de daltonismo do skill dataviz (fora do repo). */
    --serie-9: #5a7d00;  --serie-10: #c23ab5;

    --topbar-bg: #ffffff;
    --overlay-bg: rgb(0 0 0 / 0.40);
}

html[data-theme="dark"] {
    color-scheme: dark;

    /* ESCURO "DIM", e não preto puro (decidido em 2026-09-24, pelo produto).
       O documento pede canvas #000000 e cartão #0a0a0c: 1.03:1 entre os dois,
       e sem borda (decisão 3) nada separava cartão de página — "muito escuro,
       pouco contraste". Agora o canvas é um cinza-azulado muito escuro e cada
       camada dá um passo visível PARA CIMA: canvas → cartão (1.10:1) → hover
       (1.19 sobre o cartão) → flutuante (1.12 sobre o hover). Os accents
       subiram junto para manter 4.5:1 sobre as camadas mais claras. Números
       conferidos no contraste.check.js. */
    --canvas: #121419;
    --surface-card: #1b1e25;
    --surface-elevated: #21252d;
    --surface-deep: #0e1014;
    --surface-hover: #282c35;
    /* Um passo ACIMA do --surface-hover: assim o hover dos itens de um menu
       continua visível dentro dele. A sombra ajuda pouco no escuro. */
    --surface-flutuante: #30343e;       /* erro por cima a 4.55:1 */
    --sombra-flutuante: 0 12px 32px rgba(0, 0, 0, 0.5);

    --hairline: rgba(255, 255, 255, 0.08);
    /* 20% (era 14%): a borda do campo era o que menos se via no escuro. */
    --hairline-strong: rgba(255, 255, 255, 0.20);
    --divider-soft: rgba(255, 255, 255, 0.05);

    --ink: #f3f5f8;                        /* 15.27:1 sobre o cartão */
    --body: rgba(243, 245, 248, 0.88);     /* 12.05:1 */
    --charcoal: rgba(243, 245, 248, 0.74); /*  8.87:1 */
    --mute: #aab1bb;                       /*  7.72:1 */
    --ash: #9198a3;                        /*  5.74:1 */
    --stone: #555b64;                      /* desabilitado, isento */

    /* Mesma troca do tema claro: CTA azul único em vez do branco/preto do
       DESIGN.md, com tinta preta por cima (8.37:1). */
    --primary: #4ea8ff;
    --primary-on: #000000;
    --primary-hover: color-mix(in srgb, var(--link) 85%, white);
    --primary-pressed: color-mix(in srgb, var(--link) 70%, white);

    /* Matiz do documento, um pouco mais claros: o #ff2047 dava 4.41:1 sobre
       o cartão novo, e o verde neon #11ff99 ofuscava em superfície cinza. */
    --accent-blue: #4ea8ff;       /*  6.65:1 */
    --accent-orange: #ff8a33;     /*  7.10:1 */
    --accent-yellow: #ffc53d;
    --accent-green: #2ee8a0;      /* 10.46:1 */
    --accent-red: #ff6b80;        /*  6.09:1 */
    --link: #4ea8ff;

    /* Marca (ponto, barra, botão de perigo): o vermelho vivo fica mais
       saturado que o de texto — preto por cima dele a 6.28:1. */
    --accent-green-vivid: #2ee8a0;
    --accent-red-vivid: #ff4561;
    --accent-orange-vivid: #ff8a33;
    --accent-blue-vivid: #4ea8ff;

    /* Os glows do documento, com os valores dele. Uso: wash radial de baixa
       opacidade no topo de uma seção — NUNCA superfície chapada. */
    --glow-orange: rgba(255, 89, 0, 0.22);
    --glow-blue: rgba(0, 117, 255, 0.34);
    --glow-green: rgba(34, 255, 153, 0.18);
    --glow-red: rgba(255, 32, 71, 0.34);

    /* Tintas de estado: o cartão misturado com o accent (12-13%). As antigas
       eram quase pretas — mais escuras que o próprio cartão, pareciam furo. */
    --fundo-ok: #1d3634;
    --fundo-erro: #392831;
    --fundo-aviso: #362b27;
    --fundo-info: #223041;
    /* Linha inteira em aviso: cartão + 20% de laranja (1.43:1 do cartão),
       texto --ink por cima a 10.65:1. */
    --fundo-linha-aviso: #493428;
    /* Tinta ESCURA sobre o vermelho vivo: branco por cima dele reprova. */
    --on-red: #000000;

    --marca-whatsapp: #25D366;
    --qr-tinta: #000000;
    --qr-papel: #ffffff;
    /* Painel azul do login: fixo nos dois temas (não acompanha claro/escuro).
       Um azul-marinho de base, dois brilhos mais claros que derivam por cima e
       o traço fino das ondas. Texto branco: 11:1 sobre a base. */
    --login-azul: #0a3a8c;
    --login-brilho: #2f7dff;
    --login-brilho-claro: #56b4ff;
    --login-linha: rgba(255, 255, 255, 0.34);
    --login-texto: #ffffff;

    /* Séries: a ordem segura de sempre, nos tons novos dos accents. Todas
       acima de 4.9:1 sobre o cartão. */
    --serie-1: #4ea8ff;  --serie-2: #ff8a33;  --serie-3: #2ee8a0;  --serie-4: #ffc53d;
    --serie-5: #ff7ab8;  --serie-6: #00c8a0;  --serie-7: #a78bfa;  --serie-8: #ff4561;
    --serie-9: #a6d13a;  --serie-10: #e07ad6;

    --topbar-bg: #121419;
    --overlay-bg: rgb(0 0 0 / 0.64);
}

/* =====================================================================
   Escalas globais (iguais nos dois temas) — DESIGN.md
   Espaçamento, raio e tipografia saem das tabelas `## Layout`, `## Shapes` e
   `## Typography` do documento, com os valores dele.
   ===================================================================== */
:root {
    /* Espaçamento do documento: base 4, escala em 4/8/16. Os nomes antigos
       (--space-N) continuam porque são 900+ usos; os valores é que passam a
       ser os da tabela. */
    --space-1: 4px;   /* xs  */
    --space-2: 8px;   /* sm  */
    --space-3: 12px;  /* md  */
    --space-4: 16px;  /* lg  */
    --space-5: 24px;  /* xl  */
    --space-6: 24px;
    --space-8: 32px;  /* xxl */
    --space-10: 48px; /* xxxl */
    --space-12: 48px;
    --space-section: 96px;  /* respiro entre faixas */
    --space-band: 128px;    /* faixa de herói e transição do rodapé */

    /* Raio do documento (`## Shapes`). A escala inteira subiu: o sistema
       anterior ia de 2 a 8px, este vai de 4 a 16. */
    --radius-xs: 4px;
    --radius-sm: 6px;
    --radius-md: 8px;    /* botão e campo */
    --radius-lg: 12px;   /* cartão, poço de código, modal */
    --radius-xl: 16px;   /* painel grande */
    --radius-full: 9999px;
    --radius: var(--radius-md);

    /* ── Tipografia: quatro famílias, faixas estritas ───────────────────
       As duas primeiras do documento são proprietárias e pagas (Domaine
       Display e ABC Favorit). O próprio documento prevê substitutas; as dele
       (Söhne, Tiempos) também são pagas, então entram as livres mais próximas.
       A receita de ajuste é a que ele manda para substituta: line-height
       travado em 1.0 no display e tracking negativo no corpo. */
    /* 2026-09-25: uma família só, a Public Sans (sem serifa, pesos 400–700),
       em todo texto e todo número do sistema. Entrou no lugar da Source Serif 4,
       que durou um dia (24/09) e a equipe não aprovou; antes dela eram três
       faixas (Instrument Serif / Inter Tight / Inter). Os tokens continuam
       separados para uma faixa poder divergir de novo sem caçar declaração
       pelo arquivo. */
    --font-display: 'Public Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-body: 'Public Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-ui: 'Public Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
    /* Mono só onde a fonte é função: QR Code em texto e chave para copiar. */
    --font-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;

    /* Escala do documento (`## Typography` → Hierarchy). Os nomes curtos
       continuam por causa dos ~600 usos; os valores são os da tabela. */
    --fs-xs: 12px;     /* caption   */
    --fs-sm: 14px;     /* body-sm, button */
    --fs-base: 14px;
    --fs-md: 16px;     /* body-md   */
    --fs-lg: 20px;     /* heading-sm, subtitle */
    --fs-xl: 24px;     /* heading-md */
    /* Título de modal, de tela e de ficha (<h2>). Era --fs-lg (20px) espalhado
       por seis regras; um token só para o tamanho acompanhar junto. */
    --fs-h2: 18px;
    --fs-2xl: 56px;    /* display-lg */
    --fs-display: 76.8px;
    --fs-display-xxl: 96px;

    --lh-display: 1.0;   /* "Don't loosen Domaine Display lineHeight past 1.0" */
    --ls-display: -0.01em;
    --ls-body: -0.005em;  /* a compensação que o documento manda na substituta */

    /* Transições */
    --dur-fast: 120ms; --dur-base: 180ms; --dur-slow: 280ms;
    --ease-std: cubic-bezier(.4, 0, .2, 1);

    /* Z-index */
    /* Dropdown ACIMA de sticky: menu suspenso tem de flutuar sobre cabeçalho
       fixo. Estava ao contrário, e o <thead> grudado da tabela de Clientes
       pintava por cima do painel do menu, do popup do sino e do popover de
       período — a mesma falha nos três, visível só quando o menu ficou grande. */
    --z-topbar: 100; --z-sticky: 200; --z-dropdown: 300; --z-banner: 400;
    --z-modal-overlay: 900; --z-modal: 910; --z-toast: 950; --z-tooltip: 980;

    /* Seta dos <select>: com `appearance: none` a nativa some, e cada lugar que
       redefinia o fundo apagava a substituta. Um token só, usado por todos. */
    --seta-select: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23888'%3E%3Cpath fill-rule='evenodd' d='M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06Z' clip-rule='evenodd'/%3E%3C/svg%3E");
    /* Lupa das buscas: mesmo cinza da seta, que vale nos dois temas. As duas
       são o Heroicons 16/solid ("micro"), o conjunto feito para este tamanho. */
    --lupa: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23888'%3E%3Cpath fill-rule='evenodd' d='M9.965 11.026a5 5 0 1 1 1.06-1.06l2.755 2.754a.75.75 0 1 1-1.06 1.06l-2.755-2.754ZM10.5 7a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0Z' clip-rule='evenodd'/%3E%3C/svg%3E");

    /* ── Densidade — ver "Modo compacto" no final do arquivo ────────────
       Só o que muda entre os dois modos: o resto continua vindo dos tokens
       de sempre (--space-N, --fs-N). Padrão aqui = os valores que o app já
       tinha antes de existir modo compacto — ativar o modo não pode mudar
       nada disso, só a REGRA de `body.modo-compacto` mais abaixo. */
    --btn-pad: 8px 16px;
    --btn-min-h: 36px;
    --btn-fs: var(--fs-sm);
    --tabela-td-pad: 6px 10px;
    --tabela-th-pad: 7px 10px;
    --tabela-fs: 13px;
    /* Uma altura para toda linha de tabela; o selo de 20px + a data do Últ. Envio cabem nela. */
    --tabela-linha-h: 40px;
    --selo-h: 20px;
    /* Opaco (o cabeçalho é sticky) e um passo acima da zebra: sem borda, o fundo separa. */
    --tabela-cabecalho: color-mix(in srgb, var(--ink) 5%, var(--surface-card));
    /* Mistura com --ink: funciona nos dois temas sem regra dupla, mesmo
       idioma de .central-tabs/.central-row-obs. 3% é de propósito mais fraco
       que os 5% do trilho de abas — zebra tem que separar, não competir com
       o hairline que já faz esse trabalho. */
    --zebra-tint: color-mix(in srgb, var(--ink) 3%, transparent);
    /* Preenchimento do que antes era desenhado pela borda (botão secundário,
       de ícone, chip, seção de formulário). Tinta translúcida, mesmo idioma do
       zebra: aparece sobre QUALQUER superfície nos dois temas — canvas, cartão
       ou modal —, onde um token opaco sumiria no fundo igual ao dele. */
    --preenchimento: color-mix(in srgb, var(--ink) 6%, transparent);
    --preenchimento-hover: color-mix(in srgb, var(--ink) 11%, transparent);
    --bank-item-pad: 6px 12px;
    --bank-item-min-h: 42px;
    --bank-item-gap: var(--space-3);
    --icon-btn-w: 36px;
    /* O segmento (.central-tab) não cabe em --btn-pad/--btn-min-h: ele é menor
       que um botão de propósito, porque vive DENTRO de um trilho que já tem
       borda e recuo próprios. Tokens separados, com os valores que ele já
       tinha — ligar o modo compacto não muda nada aqui, só a regra do fim. */
    --tab-pad: 5px 14px;
    --tab-fs: 12.5px;
    /* Campo de formulário (a ficha do cliente, os modais): o padrão é o
       tamanho de sempre, e o modo compacto encolhe junto com os botões. */
    --campo-h: 40px;
    --campo-fs: var(--fs-sm);
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

/* Ícones SVG — DESIGN.md (## Components */
.icon {
    display: inline-flex;
    flex-shrink: 0;
    vertical-align: middle;
}
.btn .icon { margin-right: 6px; margin-bottom: -1px; }

body {
    /* A família de UI (--font-ui, Public Sans) do começo ao fim. Algarismos
       de altura de maiúscula: número de tabela não pode descer da linha. */
    font-family: var(--font-ui);
    font-variant-numeric: lining-nums;
    font-size: var(--fs-sm);
    background: var(--canvas);
    color: var(--body);
    height: 100vh;
    overflow: hidden;
    display: flex;
    transition: background 0.25s ease, color 0.25s ease;
}

/* Controle de formulário não herda a fonte do body por padrão do navegador. */
button, input, select, textarea { font-family: inherit; }

::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--hairline); border-radius: var(--radius); }
::-webkit-scrollbar-thumb:hover { background: var(--link); }

#app {
    display: flex;
    flex-direction: column;
    width: 100vw;
    height: 100vh;
}

/* =====================================================================
   Topbar (estilo framework / BookStack)
   ===================================================================== */
.topbar {
    display: flex;
    align-items: center;
    gap: var(--space-5);
    height: 48px;
    padding: 0 var(--space-5);
    /* Sem backdrop-filter: a topbar é irmã do .layout numa coluna flex, nada
       rola por baixo dela. O filtro só borrava o fundo liso da página — custo
       de GPU a cada repaint (os polls de 3s atualizam indicadores aqui dentro)
       sem nenhum efeito visível. */
    background: var(--surface-card);
    /* Segunda divisória do sistema (exceção na decisão 3, no topo): separa a
       topbar da menubar logo abaixo, que tem o mesmo fundo. */
    border-bottom: 1px solid var(--hairline);
    flex-shrink: 0;
    z-index: var(--z-topbar);
    box-shadow: none;
    position: relative;
}

.brand {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}

/* Ícone + "NS Controller" viraram UMA imagem só (nscontroller-long-icon.svg,
   917x243) -- não tem mais <h1> ao lado pra estilizar, então altura fixa +
   largura livre é o que mantém a proporção do arquivo. 28px repete a altura
   do ícone quadrado que existia antes, pra não mudar o ritmo vertical da
   topbar (48px de altura fixa, ver .topbar). */
.brand-logo-long {
    height: 32px;
    width: auto;
    flex-shrink: 0;
}
.logo-escuro, html[data-theme="dark"] .logo-claro { display: none; }
html[data-theme="dark"] .logo-escuro { display: block; }


.header-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}

/* =====================================================================
   Layout — navegação superior, sem sidebar (DESIGN.md)
   ===================================================================== */
.layout {
    flex: 1;
    display: flex;
    min-height: 0;
}

/* Barra de filtro da página Servidores (substitui a antiga sidebar) */
.servidores-filterbar {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    padding: var(--space-3) 0;
}

/* Sem escopo em .servidores-filterbar: a regra estava presa àquela barra, e a
   mesma classe usada em outra tela (a busca da exportação) não recebia estilo
   nenhum. Só o `flex:1` é específico daquele contêiner e fica lá embaixo. */
.filtro-search-input {
    min-width: 200px;
}

.servidores-filterbar .filtro-search-input { flex: 1; }


/* =====================================================================
   Sidebar: servidores
   ===================================================================== */
.server-item {
    background: var(--surface-card);
    border: 0;
    border-radius: var(--radius);
    margin-bottom: 8px;
    overflow: hidden;
}

.server-item:hover {
    background: var(--surface-hover);
}

.server-item.scanning { animation: varrendo-shimmer 2.5s ease-in-out infinite alternate; }

.icon-img { width: 20px; height: 20px; object-fit: contain; vertical-align: middle; }

.icon-fallback {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border-radius: var(--radius);
    color: var(--primary-on);
    font-size: 11px;
    font-weight: 700;
    flex-shrink: 0;
}

.db-item {
    display: flex;
    align-items: center;
    padding: 7px 8px;
    border-radius: var(--radius);
    cursor: pointer;
    gap: 8px;
    min-width: 0;
    border-left: 0;
}

.db-item:hover {
    background: var(--surface-hover);
    padding-left: 10px;
}

.db-item.active {
    background: var(--fundo-info);
}

.db-item .db-icon { font-size: 14px; opacity: 0.6; flex-shrink: 0; }

.db-icon-img { width: 15px; height: 15px; object-fit: contain; vertical-align: middle; }

.db-item .db-pending {
    font-size: 10.5px;
    font-weight: 700;
    padding: 1px 7px;
    border-radius: var(--radius);
    flex-shrink: 0;
}

.db-item .db-pending.danger { color: var(--accent-red); background: var(--fundo-erro); }
.db-item .db-pending.warning { color: var(--accent-orange); background: var(--fundo-aviso); }


/* =====================================================================
   Main
   ===================================================================== */
.main-content {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--canvas);
    min-width: 0;
}

.main-header .breadcrumb span { color: var(--link); }

.main-body {
    flex: 1;
    overflow-y: auto;
    /* O respiro de cima é também o quanto um cabeçalho preso (sticky) sobe para encostar no topo. */
    --main-body-topo: 24px;
    padding: var(--main-body-topo) 26px;
}

/* Indicadores ativos no topo */
#exportActiveIndicator { display: none; }
#exportActiveIndicator.has-active-export { display: flex; align-items: center; }

/* Indicador do topo. Era uma pílula com valores soltos (12px, raio 20px,
   borda 1.5px, transição 0.3s) e a borda pulsando sem parar — destoava de
   tudo. Agora usa os tokens e leva barra de progresso além da porcentagem. */
.export-active-btn {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 210px;
    white-space: nowrap;
    text-align: left;
}

.export-active-btn .ind-ico { display: flex; flex-shrink: 0; color: var(--link); }
.export-active-btn .ind-ico .icon { width: 17px; height: 17px; }
.export-active-btn .ind-corpo { display: flex; flex-direction: column; gap: 3px; flex: 1; min-width: 0; }
.export-active-btn .ind-topo { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-2); }
.export-active-btn .export-label { overflow: hidden; text-overflow: ellipsis; }
.export-active-btn .ind-pct {
    font-size: var(--fs-xs);
    font-weight: 700;
    color: var(--body);
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
}

.export-active-btn .ind-barra {
    height: 3px;
    border-radius: var(--radius-full);
    background: var(--surface-elevated);
    overflow: hidden;
}
.export-active-btn .ind-barra-fill {
    display: block;
    height: 100%;
    width: 0;
    border-radius: inherit;
    background: var(--link);
    transition: width var(--dur-slow) var(--ease-std);
}

/* Só o ícone pulsa enquanto roda — a borda inteira piscando era ruído. */
.export-active-btn:not(.concluido) .ind-ico { animation: pulsarSuave 1.6s ease-in-out infinite; }


@media (prefers-reduced-motion: reduce) {
    .export-active-btn .ind-ico { animation: none; }
    .export-active-btn .ind-barra-fill { transition: none; }
}

/* O indicador de e-mail usa a mesma anatomia do de exportação; só troca a cor
   do ícone e acrescenta a linha de contagem regressiva. */
.export-active-btn.email-btn .ind-ico { color: var(--accent-blue); }
.export-active-btn.email-btn .cooldown-label { display: block; margin-top: 2px; }
/* Vazia, a linha da contagem regressiva ainda ocupava altura e deixava o botão
   de e-mail 5px mais alto que o de exportação, lado a lado. */
.export-active-btn .cooldown-label:empty { display: none; }

.cooldown-label {
    font-size: 10px;
    font-weight: 400;
    color: var(--accent-orange);
    white-space: nowrap;
    letter-spacing: 0.3px;
    padding-left: 2px;
}

.shimmer-dot {
    width: 8px;
    height: 8px;
    background: var(--link);
    border-radius: 50%;
    animation: dot-shimmer 2.5s ease-in-out infinite alternate;
}


.mini-spinner {
    display: inline-block;
    width: 13px;
    height: 13px;
    border: 2px solid var(--hairline);
    border-top-color: currentColor;
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
    vertical-align: -2px;
}

/* =====================================================================
   Home / estados
   ===================================================================== */


.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 40px;
    text-align: center;
}

.empty-state .empty-icon { font-size: 40px; margin-bottom: 12px; opacity: 0.4; }
.empty-state p { color: var(--body); font-size: 14px; line-height: 1.5; }

.loading {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 40px;
    color: var(--body);
    gap: 10px;
    font-size: 13px;
}

.spinner {
    width: 20px;
    height: 20px;
    border: 2px solid var(--hairline);
    border-top-color: var(--link);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

.loading-bar {
    height: 3px;
    background: transparent;
    position: relative;
    overflow: hidden;
    flex-shrink: 0;
}

.loading-bar.active::after {
    content: '';
    position: absolute;
    top: 0;
    left: -30%;
    width: 30%;
    height: 100%;
    background: var(--link);
    animation: loadingBar 1.5s infinite;
}

.scan-banner {
    position: fixed;
    top: 68px;
    left: 50%;
    transform: translateX(-50%);
    padding: 8px 22px;
    background: var(--topbar-bg);
    border: 0;
    border-radius: var(--radius);
    font-size: 13px;
    font-weight: 600;
    color: var(--ink);
    text-align: center;
    display: none;
    letter-spacing: 0.3px;
    white-space: nowrap;
    max-width: 90vw;
    overflow: hidden;
    text-overflow: ellipsis;
    z-index: 999;
    pointer-events: none;
}

.scan-banner.active { display: block; }

/* =====================================================================
   Cards de pendências
   ===================================================================== */
.panel-card {
    background: var(--surface-card);
    border: 0;
    border-radius: var(--radius);
    padding: 22px;
    margin-bottom: 20px;
}

.panel-card h3 { font-size: 18px; margin-bottom: 14px; color: var(--ink); }
.panel-card-saltos { background: var(--fundo-aviso); }

/* `auto-fit` colapsava as trilhas vazias e esticava as que sobravam: um banco
   com uma pendência só ganhava um card de 1506px para exibir um número. Com
   `auto-fill` a largura do card não depende de quantas pendências existem. */
.pending-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: var(--space-3);
    align-items: stretch;
}

.pend-cabecalho {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}

.pend-cabecalho h3 { margin: 0; }

/* Filiais */
.branch-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 8px;
}
/* Nome de filial comprido quebra linha dentro do botão. Com o nowrap e o
   centro da base de botões, ele vazava pelos dois lados e cobria o vizinho. */
/* Pela grade: a base de botões vem depois no arquivo e, com o mesmo peso,
   venceria de volta. */
.branch-grid .branch-btn { justify-content: flex-start; white-space: normal; text-align: left; }
.branch-grid .branch-btn .icon { flex-shrink: 0; }


.tenant-link { text-decoration: none; font-size: 16px; color: var(--link); }

/* Modo de visão */


/* =====================================================================
   Detalhes
   ===================================================================== */
.detail-list { display: flex; flex-direction: column; gap: 4px; }

.detail-item {
    display: flex;
    align-items: center;
    padding: 10px 14px;
    background: var(--surface-card);
    border: 0;
    border-radius: var(--radius);
    gap: 12px;
    font-size: 13px;
}

.detail-item .id { font-weight: 700; color: var(--link); min-width: 60px; }
.detail-item .name { flex: 1; }
.detail-item .status { font-weight: 600; font-size: 11px; padding: 3px 10px; border-radius: var(--radius); }
.detail-item .date { color: var(--body); font-size: 12px; white-space: nowrap; }
/* Segunda linha do item, de ponta a ponta: a origem da devolução, o motivo. */
.detail-item:has(> .detail-sub) { flex-wrap: wrap; row-gap: var(--space-1); }
.detail-item .detail-sub { flex-basis: 100%; font-size: var(--fs-xs); color: var(--body); }

/* Acessos de clientes (Configurações): cada login é a mesma linha de
   Usuários do painel (.usuario-linha) + os chips das empresas vinculadas + a
   busca de vincular — os três leem como UM cartão. A linha interna perde o
   próprio fundo para não duplicar o cartão; as empresas alinham com o texto,
   depois do avatar. */
.acesso-cliente-item {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    background: var(--preenchimento);
    border-radius: var(--radius);
    padding: var(--space-3) var(--space-4);
}
.acessos-lista { gap: var(--space-2); }
.acesso-cliente-item .usuario-linha { background: transparent; padding: 0; }
.acesso-empresas {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding-left: calc(36px + var(--space-3));
}
.acesso-empresas .dlg-chips { margin: 0; align-items: center; }
/* Chip sobre o cartão cinza: o fundo do modal, e não o mesmo cinza do cartão. */
.acesso-cliente-item .dlg-chip { background: var(--surface-flutuante); }
.usuario-novo .dlg-chips { margin: 0; align-items: center; }
.usuario-novo .dlg-chip { background: var(--surface-flutuante); }
/* Dropdown de vincular empresa (acessoAbrirSeletor) e de Contador
   (centralContadorAbrirMenu): o .central-ctx-menu de sempre, com a busca no
   topo e a lista rolando embaixo. */
.central-ctx-menu.acesso-seletor, .central-ctx-menu.contador-seletor {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    width: 360px;
    max-width: calc(100vw - 16px);
}
/* Bloco, e não flex: coluna flex com max-height ESPREMIA os itens para caber
   (com centenas de empresas, um texto por cima do outro) em vez de rolar. */
.acesso-seletor-lista { max-height: 280px; overflow-y: auto; }
.acesso-seletor .central-ctx-menu-item.ativo, .contador-seletor .central-ctx-menu-item.ativo,
.sistema-seletor .central-ctx-menu-item.atual { background: var(--surface-hover); }
.acesso-seletor-vazio { margin: 0; padding: var(--space-3); font-size: var(--fs-sm); color: var(--mute); }
/* Com prefixo: `.modal p` (cor e margem) venceria a classe sozinha. */
.acesso-empresas .acesso-sem-empresa { margin: 0; font-size: var(--fs-xs); color: var(--accent-orange); }
.config-topo .acesso-link, .cli-acesso .acesso-link {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-2);
    margin: var(--space-2) 0 0;
    font-size: var(--fs-sm);
    color: var(--mute);
}
.config-topo .acesso-link a, .cli-acesso .acesso-link a { color: var(--link); word-break: break-all; }
/* Subaba Acesso ao portal (página do cliente): as peças das Configurações
   (.usuario-*, .acesso-cliente-item) dentro de um card. O prefixo .cli-acesso
   vence o `.panel-card h3`, que vem depois no arquivo. */
.cli-acesso .cli-acesso-topo {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-4);
}
.cli-acesso .cli-acesso-topo > div { flex: 1 1 280px; min-width: 0; }
.cli-acesso .cli-acesso-topo > button { flex-shrink: 0; }
.cli-acesso .cli-acesso-topo h3 { margin-bottom: var(--space-1); }
.cli-acesso .cli-acesso-topo p { margin: 0; font-size: var(--fs-sm); color: var(--body); }
.cli-acesso .cli-acesso-topo p.acesso-link { margin-top: var(--space-2); color: var(--mute); }

.mono { font-variant-numeric: tabular-nums; font-size: 12px; }

/* =====================================================================
   Botões / genéricos
   ===================================================================== */
.back-btn {
    margin-bottom: 14px;
}


/* Base da família btn-*: estas classes só definiam COR. Onde apareciam soltas
   (fora de .modal-actions ou .central-filter-actions, que suprem o resto) o
   botão saía com o padrão do navegador — sem padding, raio nem fonte. */
.btn-primary .icon, .btn-confirm .icon,
.btn-secondary .icon, .btn-cancel .icon,
.btn-danger .icon { width: 17px; height: 17px; }

/* `button-primary` do DESIGN.md: o retângulo BRANCO com texto preto — no tema
   claro, o inverso, pelo mesmo motivo. É a assinatura do sistema, e o
   documento é explícito sobre a escassez dela: "Reserve button-primary (white
   pill) as the only solid bright surface. One per viewport at most."
   Era azul aqui, que é o que a marca anterior usava. */

/* `button-ghost`: superfície um degrau acima + hairline. É a ação secundária de
   peso igual que o documento pareia com a primária. */


/* =====================================================================
   Modais
   ===================================================================== */
.modal-overlay,
.xmlfalta-overlay {
    position: fixed;
    inset: 0;
    background: var(--overlay-bg);
    z-index: var(--z-modal-overlay);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
    /* SEM backdrop-filter aqui — ver DESIGN.md ## Components (Modais).
       Um filtro de fundo cobrindo a viewport inteira obriga o navegador a
       reborrar tudo a cada mudança de DOM atrás dele, e a app tem polls de
       3s/5s que atualizam os indicadores da topbar. O resultado era a
       interface travando com qualquer modal aberto. Overlay opaco resolve o
       mesmo problema visual (separar o modal do fundo) de graça. */
    animation: overlayIn var(--dur-base) var(--ease-std);
}

@keyframes overlayIn { from { opacity: 0; } to { opacity: 1; } }

/* Mesma superfície, raio e sombra do .dlg (a ficha): todo modal é a mesma
   família de camada flutuante, e não uma caixa azulada por cima da página. */
.modal {
    position: relative;
    background: var(--surface-flutuante);
    box-shadow: var(--sombra-flutuante);
    border-radius: var(--radius-xl);
    padding: var(--space-5);
    width: 100%;
    max-width: 460px;
    max-height: calc(100vh - var(--space-8));
    overflow-y: auto;
    animation: modalIn var(--dur-base) var(--ease-std);
    color: var(--ink);
    z-index: var(--z-modal);
}

/* O diálogo recebe foco por script (sem campo, o setupModal foca o próprio
   diálogo para o leitor de tela anunciar): um anel no contêiner inteiro não
   ajuda ninguém e desenhava uma moldura preta em volta do modal. O foco dos
   CONTROLES continua com anel. */
.modal:focus, .dlg:focus, .modal-overlay:focus, .xmlfalta-overlay:focus, .top10-popup:focus { outline: none; }

/* Largura: eram DEZ valores inline diferentes (400, 420, 440, 450, 460, 500,
   520, 560, 620, 760), cada modal escolhendo o seu. Quatro degraus, e o modal
   declara em qual cabe — não um número.
   Especificidade dobrada de propósito: regra de componente que também define
   largura e vem depois no arquivo não pode passar por cima do degrau. */
.modal.modal-sm { max-width: 400px; }
.modal.modal-md { max-width: 560px; }
.modal.modal-lg { max-width: 640px; }
.modal.modal-xl { max-width: 760px; }
/* Tabela de dados expandida (Envios por cliente, no Painel): quase a tela toda,
   e só a tabela rola — cabeçalho e filtros ficam onde estão. */
.modal.modal-tabela {
    max-width: 1600px;
    height: calc(100vh - var(--space-8));
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.modal-tabela .central-table-wrap, .modal-tabela .hist-tabela-wrap { flex: 1 1 auto; min-height: 0; }

.modal h2 { font-size: var(--fs-h2); font-weight: 500; letter-spacing: -0.3px; margin-bottom: var(--space-2); }
.modal p { color: var(--charcoal); font-size: var(--fs-sm); margin-bottom: var(--space-4); }
/* Só o parágrafo que FECHA o conteúdo perde a margem. Era `:last-of-type`, e
   pegava também o texto de introdução seguido de campo — que colava no campo. */
.modal p:last-child { margin-bottom: 0; }

/* Nota de rodapé de campo: consequência, ressalva, formato esperado. Era
   `<p style="font-size:12px;color:var(--mute)">` escrito à mão em cada
   modal, com oito combinações diferentes de tamanho e margem. */
.modal .modal-nota {
    font-size: var(--fs-xs);
    color: var(--mute);
    margin: calc(var(--space-2) * -1) 0 var(--space-4);
    line-height: 1.5;
}
.modal .modal-nota-aviso { color: var(--accent-orange); }
.modal .modal-nota-erro { color: var(--accent-red); }
/* Diálogo sem cabeçalho estruturado (confirmação): o h2 é o título, e o ícone
   dele ganha o mesmo quadrado tingido da marca do cabeçalho (.modal-marca). */
/* h3 também: os diálogos da Central (centralDialogo) abrem com <h3>, e o ícone
   ficava solto na linha — o único título de modal sem a marca. */
.modal > h2, .modal > h3 { display: flex; align-items: center; gap: var(--space-3); }
.modal > h2 > .icon:first-child, .modal > h3 > .icon:first-child {
    box-sizing: content-box;
    width: 22px;
    height: 22px;
    padding: 12px;
    flex-shrink: 0;
    border-radius: var(--radius-lg);
    background: color-mix(in srgb, var(--link) 12%, transparent);
    color: var(--link);
}

/* `.field` é componente de formulário (DESIGN.md ## Components), não peça de modal.
   Enquanto estas regras estavam presas a `.modal .field`, o mesmo markup fora
   de um modal saía sem estilo nenhum: label colada no input, tudo em linha. */
.field { margin-bottom: var(--space-4); }
/* Layout do campo dentro do .field (a aparência mora no vocabulário de campos). */
.field input, .field select, .field textarea { width: 100%; }


/* O foco do `text-input` no DESIGN.md: "Focus state thickens the border to
   {colors.ink} (no separate ring colour)." Era anel azul.
   Isto carrega mais peso do que parece: com a borda em repouso a 1.35:1 (ver a
   decisão registrada no topo do arquivo), o foco é o que sustenta a navegação
   por teclado — e ink sobre canvas dá 20.63:1. O "engrossar" é feito com anel
   interno de blur zero para não empurrar o layout em 1px. */

/* Ações: à direita, no tamanho natural — Cancelar e depois a ação principal,
   que é a ordem de todos os templates. */
.modal .modal-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--space-2);
    margin-top: var(--space-6);
}
/* O rodapé DO modal (filho direto — as ações de seção, como as das
   Configurações, ficam de fora): faixa tingida que sangra até as bordas e gruda
   no fundo quando o corpo rola, a mesma do .dlg-rodape das fichas. Opaca (mix
   e não tinta translúcida): o conteúdo passa POR BAIXO dela ao rolar. */
.modal > .modal-actions {
    position: sticky;
    bottom: calc(-1 * var(--space-5));
    z-index: 2;
    margin: var(--space-6) calc(-1 * var(--space-5)) calc(-1 * var(--space-5));
    padding: var(--space-4) var(--space-5);
    background: color-mix(in srgb, var(--ink) 6%, var(--surface-flutuante));
}

/* Modal de confirmação (sem campos): o header e as ações têm cada um sua
   margem e sua borda, e sem nada entre eles sobrava uma faixa vazia de ~40px
   com dois riscos. Vale para qualquer modal só de confirmar. */
.modal .modal-header + .modal-actions { margin-top: var(--space-2); }

/* Só o lugar no rodapé: a aparência é a do vocabulário de botões. Esta regra
   desenhava o botão inteiro com --fs-sm cravado, e o rodapé de todo modal
   ficava fora do Modo compacto. */
.modal .modal-actions button { flex: 0 0 auto; min-width: 104px; }

/* Campo de confirmação: verde quando a palavra confere. Precisa cobrir :focus
   também — o anel azul de foco tem a mesma especificidade e vem depois. */

/* Sem borda, o Cancelar se desenha pelo preenchimento: o --surface-card de
   antes quase some sobre o --surface-elevated do modal. */
/* `.btn-confirm` e `.btn-primary` são o MESMO papel — a ação que fecha o
   diálogo. Metade dos modais escrevia um, metade o outro, e só o primeiro
   recebia estilo aqui: os dois saíam diferentes lado a lado. */
.modal .modal-actions button:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; }

/* =====================================================================
   Diálogo de ficha (.dlg) — cliente, novo cliente e contador (central.js)
   Feito do zero em 2026-09-23. O `.modal` genérico empilhava três gerações de
   regra (padding de 32px, título em negrito, campo no mesmo tom do fundo);
   este é um componente fechado, que não herda nada dele: cabeçalho e rodapé
   fixos e SÓ o corpo rola — o Salvar nunca sai da tela.
   ===================================================================== */
.dlg {
    display: flex;
    flex-direction: column;
    width: 100%;
    max-height: min(88vh, 920px);
    background: var(--surface-flutuante);
    box-shadow: var(--sombra-flutuante);
    border-radius: var(--radius-xl);
    overflow: hidden;
    color: var(--ink);
    animation: modalIn var(--dur-base) var(--ease-std);
}
.dlg-md { max-width: 600px; }
.dlg-lg { max-width: 780px; }

.dlg-cabeca {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-5) var(--space-5) var(--space-4);
}
/* A marca faz o papel da foto: iniciais do cadastro (ou o ícone, no novo). */
.dlg-marca, .modal-marca, .cli-foto {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-lg);
    background: color-mix(in srgb, var(--link) 12%, transparent);
    color: var(--link);
    font-size: var(--fs-md);
    font-weight: 600;
    letter-spacing: 0.02em;
    overflow: hidden;
}
.dlg-marca .icon, .modal-marca .icon, .cli-foto .icon { width: 22px; height: 22px; color: inherit; }
/* A foto do cliente no lugar das iniciais (central.js, clienteMarcaHtml): preenche
   a moldura de quem a hospeda. */
.foto-cliente { display: block; width: 100%; height: 100%; object-fit: cover; }
.dlg-titulos { flex: 1; min-width: 0; }
.dlg-titulos h2 {
    margin: 0;
    font-size: var(--fs-h2);
    font-weight: 600;
    line-height: 1.25;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.dlg-titulos p {
    margin: 2px 0 0;
    font-size: var(--fs-sm);
    color: var(--mute);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.dlg-fechar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    align-self: flex-start;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--mute);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-std), color var(--dur-fast) var(--ease-std);
}
.dlg-fechar:hover { background: var(--preenchimento-hover); color: var(--ink); }
.dlg-fechar:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; }
.dlg-fechar .icon { width: 20px; height: 20px; }

.dlg-corpo {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: var(--space-2) var(--space-5) var(--space-6);
}

/* Seção: o título pequeno em caixa-alta é o mesmo dos quadrados do mega menu. */
.dlg-secao + .dlg-secao { margin-top: var(--space-6); }
.dlg-secao-titulo {
    margin: 0 0 var(--space-3);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--mute);
}
/* Título com uma ação ao lado (Preencher pelo sistema, na ficha do cliente). */
.dlg-secao-topo {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}
.dlg-secao-topo > .dlg-secao-titulo { margin: 0; }
.dlg-secao-nota {
    margin: calc(var(--space-2) * -1) 0 var(--space-3);
    font-size: var(--fs-xs);
    color: var(--mute);
}

.dlg-grade {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-4);
}
.dlg-grade-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.dlg-campo { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.dlg-campo-cheio { grid-column: 1 / -1; }
/* Na linha do texto: o `super` do asterisco deixava o rótulo mais alto e o
   campo obrigatório descia alguns px em relação ao vizinho da grade. */
.dlg-campo > label .central-obrigatorio { vertical-align: baseline; font-size: inherit; }

/* Campo é a única peça com borda do sistema (decisão 3 no topo). */
.dlg-campo > input,
.dlg-campo > select,
.dlg-campo > textarea {
    width: 100%;
    max-width: none;
}
.dlg-campo > .mono { font-variant-numeric: tabular-nums; font-size: 13px; }
/* O copiar fica dentro do campo, centrado na altura dele (--campo-h). */
.dlg-campo-copiar { position: relative; }
.dlg-campo-copiar > .dlg-copiar { position: absolute; right: 6px; bottom: calc((var(--campo-h) - 28px) / 2); }

/* E-mails em tags: a caixa se comporta como um campo (borda, anel de foco). */
:is(.dlg, .cli-pagina) .central-email-tags {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    min-height: var(--campo-h);
    padding: 5px 6px;
    border: 1px solid var(--hairline-strong);
    border-radius: var(--radius-md);
    background: var(--surface-flutuante);
    transition: border-color var(--dur-fast) var(--ease-std), box-shadow var(--dur-fast) var(--ease-std);
}
:is(.dlg, .cli-pagina) .central-email-tags:focus-within {
    border-color: var(--link);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-blue-vivid) 16%, transparent);
}
:is(.dlg, .cli-pagina) .central-email-tag {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 3px 3px 3px 10px;
    border-radius: var(--radius-sm);
    background: var(--preenchimento);
    color: var(--ink);
    font-size: 13px;
}
:is(.dlg, .cli-pagina) .central-email-tag .central-email-x {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    padding: 0;
    border-radius: var(--radius-sm);
    color: var(--mute);
}
:is(.dlg, .cli-pagina) .central-email-tag .central-email-x:hover { background: var(--preenchimento-hover); color: var(--accent-red); }
:is(.dlg, .cli-pagina) .central-email-tag .central-email-x .icon { width: 15px; height: 15px; }
:is(.dlg, .cli-pagina) .central-email-tags .central-email-input {
    flex: 1;
    min-width: 180px;
    height: calc(var(--campo-h) - 12px);
    padding: 0 6px;
    font-size: var(--campo-fs);
    color: var(--ink);
}

/* Ajuste liga/desliga em linha, como em qualquer tela de configurações. */
.dlg-opcoes {
    display: flex;
    flex-direction: column;
    padding: var(--space-1) var(--space-4);
    border-radius: var(--radius-lg);
    background: var(--preenchimento);
}
.dlg-opcao {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-3) 0;
}
.dlg-opcao-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.dlg-opcao-txt strong { font-size: var(--fs-sm); font-weight: 500; color: var(--ink); }
.dlg-opcao-txt span { font-size: var(--fs-xs); color: var(--mute); }

.dlg-acoes-secao { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-3); }
.dlg-msg { margin-top: var(--space-3); font-size: var(--fs-xs); }
.dlg-msg:empty { display: none; }

.dlg-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-3); }
.dlg-chip {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 4px 4px 4px 10px;
    border-radius: var(--radius-sm);
    background: var(--preenchimento);
    color: var(--ink);
    font-size: var(--fs-sm);
}
/* Sem o × (o cliente da página, quando é o único do acesso): o mesmo recuo de
   10px dos dois lados. */
.dlg-chip-fixo { padding-right: 10px; }
.dlg-chip-x {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--mute);
    cursor: pointer;
}
.dlg-chip-x:hover { background: var(--preenchimento-hover); color: var(--accent-red); }
.dlg-chip-x:focus-visible { outline: 2px solid var(--link); outline-offset: 1px; }
.dlg-chip-x .icon { width: 15px; height: 15px; }
.dlg-vazio { margin: 0 0 var(--space-3); font-size: var(--fs-sm); color: var(--mute); }
.dlg-inline { display: flex; align-items: flex-end; gap: var(--space-2); }
.dlg-inline .dlg-campo { flex: 1; }

.dlg .central-envio { padding: 8px 10px; border-radius: var(--radius-md); font-size: 13px; }

/* Rodapé fixo e tingido: separa do corpo que rola por baixo sem precisar de
   linha. Ação destrutiva à esquerda, as de confirmação à direita. */
.dlg-rodape {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-4) var(--space-5);
    background: var(--preenchimento);
}
.dlg-rodape-acoes { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--space-2); margin-left: auto; }

/* Este modal e' denso — 15 impostos por regime — e por isso APERTA a escala,
   sem inventar outra: o passo menor de espacamento no lugar do padrao, e nada
   de tamanho de fonte proprio. As sobrescritas de 11px/13px/7px que havia aqui
   eram uma segunda escala paralela, e era o que fazia o modal destoar do resto
   da tela mesmo com as cores certas. */
.modal.ncm-modal {
    max-height: 88vh;
    overflow-y: auto;
    max-width: 640px;
}
.modal.ncm-modal .field { margin-bottom: var(--space-2); }
.modal.ncm-modal .field label { margin-bottom: var(--space-1); }

/* `sub-nav-pill` do DESIGN.md: pilula de raio full, caption, superficie um
   degrau acima. Era retangulo de raio 8 com peso 600. */


.no-auto-close { }

/* =====================================================================
   Top 10 / sino
   ===================================================================== */
.top10-popup {
    position: fixed;
    inset: 0;
    background: var(--overlay-bg);
    z-index: var(--z-modal-overlay);
    /* Sem backdrop-filter: mesmo motivo do .modal-overlay */
}


.bell-btn .count { font-size: 16px; }

/* === Menus de contexto ===
   Havia duas famílias: estas classes e uma `.context-menu` sem NENHUMA regra,
   montada em estilo inline no JS (raio 8px, padding 4px, sombra fixa em
   rgba(0,0,0,.3) e hover em rgba(255,255,255,.05) — invisível no tema claro).
   Agora é uma regra só, com os tokens.

   z-index alto de propósito: menu de contexto precisa ficar acima de modal, e
   --z-modal já vale 910. */
.bell-context-menu,
.banco-menu-popup,
.tab-context-menu,
.context-menu,
.central-ctx-menu {
    position: fixed;
    z-index: 2100;
    /* Sem borda (decisão 3 no topo), a camada flutuante é o único lugar com
       sombra: é ela que descola o menu da página no tema claro. */
    background: var(--surface-flutuante);
    box-shadow: var(--sombra-flutuante);
    border-radius: var(--radius-lg);
    padding: var(--space-2);
    min-width: 220px;
    max-width: min(300px, calc(100vw - 16px));
    animation: ctxMenuEntra var(--dur-fast) var(--ease-std);
}

@keyframes ctxMenuEntra {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: none; }
}

.bell-context-menu-item,
.banco-menu-item,
.tab-context-menu-item,
.context-menu-item,
.central-ctx-menu-item {
    padding: var(--space-2) var(--space-3);
    cursor: pointer;
    border-radius: var(--radius-sm);
    font-size: var(--fs-sm);
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-family: inherit;
    color: var(--ink);
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: background var(--dur-fast) var(--ease-std), color var(--dur-fast) var(--ease-std);
}

.bell-context-menu-item:hover,
.banco-menu-item:hover,
.tab-context-menu-item:hover,
.context-menu-item:hover,
.central-ctx-menu-item:hover { background: var(--surface-hover); }

/* Ícone acompanha, texto lidera. */
.bell-context-menu-item > .icon,
.banco-menu-item > .icon,
.tab-context-menu-item > .icon,
.context-menu-item > .icon,
.central-ctx-menu-item > .icon {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    color: var(--body);
    transition: color var(--dur-fast) var(--ease-std);
}

.bell-context-menu-item:hover > .icon,
.banco-menu-item:hover > .icon,
.tab-context-menu-item:hover > .icon,
.context-menu-item:hover > .icon,
.central-ctx-menu-item:hover > .icon { color: var(--link); }

@media (prefers-reduced-motion: reduce) {
    .bell-context-menu,
    .banco-menu-popup,
    .tab-context-menu,
    .context-menu,
    .central-ctx-menu { animation: none; }
}

/* =====================================================================
   Relatórios
   ===================================================================== */
.relatorio-categoria { margin-bottom: 8px; }

.relatorio-categoria-title {
    font-size: 13px;
    font-weight: 700;
    color: var(--link);
    padding: 8px 12px;
    background: var(--surface-card);
    border-radius: var(--radius);
    margin-bottom: 8px;
}

.relatorio-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border-radius: var(--radius);
    cursor: pointer;
    transition: background 0.15s;
    font-size: 14px;
    margin-bottom: 4px;
}

.relatorio-item:hover { background: var(--surface-hover); }


.relatorio-upload-item {
    padding: 12px;
    background: var(--surface-card);
    border-radius: var(--radius);
    margin-bottom: 8px;
}

.contato-email-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 12px;
    border-bottom: 0;
    font-size: 13px;
}

.contato-email-item:last-child { border-bottom: none; }


/* =====================================================================
   Exportação XML
   ===================================================================== */
.export-month-picker { display: inline-flex; gap: 4px; align-items: center; }

.export-progress {
    margin-top: 15px;
    padding: 16px;
    background: var(--surface-card);
    border: 0;
    border-radius: var(--radius);
}

.export-progress .progress-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 10px;
}

.export-progress .progress-header h3 { font-size: 14px; }
.export-progress .progress-header span { font-size: 13px; color: var(--body); }

.export-progress .progress-bar {
    height: 6px;
    background: var(--surface-card);
    border-radius: var(--radius);
    overflow: hidden;
    margin-bottom: 10px;
}

.export-progress .progress-bar .progress-fill {
    height: 100%;
    background: var(--link);
    border-radius: var(--radius);
    transition: width 0.3s;
}

.export-progress .progress-header .progress-pct { font-size: 11px; color: var(--body); margin-left: 4px; }

/* Sem shimmer: a barra já cresce, e o brilho correndo por cima era o tipo de
   movimento que faz interface de dado parecer propaganda. */

/* Sem altura fixa. Havia `max-height: 36px` com `line-height: 1.6`: duas linhas
   de 12px ja dao ~38px, entao a ULTIMA mensagem — a que importa — vinha sempre
   cortada ao meio, com uma barra de rolagem de 2px que ninguem ve nem usa. E as
   mensagens de resultado levam badge e botao dentro, entao quebram em mais
   linhas ainda. Nao ha o que rolar: o bloco recebe no maximo duas entradas. */
.export-progress .progress-log {
    font-size: 12px;
    color: var(--body);
    line-height: 1.6;
}

.export-progress .progress-log .log-ok { color: var(--accent-green); }
.export-progress .progress-log .log-error { color: var(--accent-red); }
.export-progress .progress-log .log-warn { color: var(--accent-orange); }
.export-progress .progress-log .log-info { color: var(--link); }
.export-progress .progress-log .log-dimmed { opacity: 0.4; font-size: 11px; }
.export-progress .progress-log .log-current { animation: pulse-log 1.2s ease-in-out infinite; }

/* =====================================================================
   NCM / cClass
   ===================================================================== */
.ncm-master-actions {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 16px;
    padding-bottom: 14px;
    border-bottom: 0;
    flex-wrap: wrap;
}


/* Era verde com !important. E' o CTA da tela, entao e' a primaria — e o
   !important existia justamente porque ele brigava com a classe de baixo. */

.ncm-batch-progress { font-size: 12px; color: var(--body); font-weight: 600; }

.ncm-prod-item {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 10px 12px;
    background: var(--surface-card);
    border: 0;
    border-radius: var(--radius);
    margin-bottom: 6px;
}

.ncm-prod-info { display: flex; align-items: center; gap: 12px; flex: 1; min-width: 200px; }
.ncm-prod-info h3 { font-size: 14px; }
.ncm-prod-info p { font-size: 12px; color: var(--body); }

.ncm-prod-item.applied-row, .cclass-prod-item.applied-row {
    opacity: 0.55;
    background: var(--fundo-ok);
}

/* Comparação NCM */
.ncm-compare-card { border: 0; }
.ncm-compare-card h3 { color: var(--accent-orange); }

.ncm-compare-container {
    display: flex;
    align-items: stretch;
    gap: 16px;
    margin-bottom: 20px;
}

.ncm-compare-side {
    flex: 1;
    padding: 16px;
    border-radius: var(--radius);
    border: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.ncm-original { background: var(--fundo-aviso); }
.ncm-similar-found { background: var(--fundo-ok); }

.ncm-compare-label {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--accent-orange);
    margin-bottom: 4px;
}

.ncm-compare-label.success { color: var(--accent-green); }

.ncm-compare-arrow {
    display: flex;
    align-items: center;
    font-size: 28px;
    color: var(--body);
    font-weight: 700;
    padding: 0 4px;
}

.ncm-compare-id { font-weight: 700; color: var(--link); font-size: 14px; }
.ncm-compare-nome { font-size: 14px; font-weight: 600; color: var(--ink); line-height: 1.3; }

.ncm-compare-ncm {
    font-size: 13px;
    font-weight: 700;
    padding: 3px 8px;
    border-radius: var(--radius);
    display: inline-block;
    margin-top: 4px;
    align-self: flex-start;
}

.ncm-compare-ncm.invalid { background: var(--fundo-aviso); color: var(--accent-orange); }
.ncm-compare-ncm.valid { background: var(--fundo-ok); color: var(--accent-green); }

.ncm-compare-message {
    font-size: 14px;
    color: var(--body);
    padding: 12px 16px;
    background: var(--surface-card);
    border-radius: var(--radius);
    margin-bottom: 16px;
    line-height: 1.5;
    border: 0;
}

.ncm-action-buttons { display: flex; gap: 10px; flex-wrap: wrap; }

.ncm-btn {
    flex: 1;
    min-width: 120px;
}

/* O trio "aplicar? sim / nao / buscar outro" era verde, cinza e azul — tres
   aparencias para tres botoes lado a lado. A cor nao informava nada que o
   rotulo ja nao dissesse, e o DESIGN.md e' explicito: "Semantic colors should
   always convey important information". Agora "sim" e' a primaria do dialogo e
   os outros dois sao secundarios; ver o vocabulario no fim do arquivo. */

.ncm-manual-search { background: var(--fundo-info); }
.ncm-manual-search h3 { color: var(--link); }
.ncm-no-similar { background: var(--fundo-aviso); }
.ncm-no-similar h3 { color: var(--accent-orange); }

.ncm-search-form { display: flex; gap: 8px; margin-bottom: 10px; }

.ncm-search-input {
    flex: 1;
}


/* =====================================================================
   Pendências de exportação
   ===================================================================== */
.pendencia-overlay {
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    background: var(--overlay-bg);
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Mesma anatomia do .dlg das fichas: camada flutuante, cabeçalho com a marca
   à esquerda (aqui na cor do alerta — é um "alert dialog"), título neutro, e
   rodapé tingido. O cabeçalho inteiro tingido de laranja virou só a marca. */
.pendencia-modal {
    background: var(--surface-flutuante);
    box-shadow: var(--sombra-flutuante);
    border-radius: var(--radius-xl);
    overflow: hidden;
    width: 640px;
    max-width: 92vw;
    max-height: 80vh;
    display: flex;
    flex-direction: column;
    animation: modalIn var(--dur-base) var(--ease-std);
}

.pendencia-header {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-5) var(--space-5) var(--space-3);
}

.pendencia-header-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-lg);
    background: var(--fundo-aviso);
    color: var(--accent-orange);
}
.pendencia-header-icon .icon { width: 22px; height: 22px; }
.pendencia-header h3 { margin: 0; color: var(--ink); font-size: var(--fs-lg); font-weight: 600; line-height: 1.25; }
.pendencia-header p { margin: 2px 0 0; font-size: var(--fs-sm); color: var(--mute); }

.pendencia-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    align-self: flex-start;
    width: 32px;
    height: 32px;
    margin-left: auto;
    padding: 0;
    background: transparent;
    border: 0;
    border-radius: var(--radius-md);
    color: var(--mute);
    cursor: pointer;
    font-family: inherit;
}

.pendencia-close:hover { background: var(--preenchimento-hover); color: var(--ink); }

.pendencia-body {
    padding: var(--space-4) var(--space-5);
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.pendencia-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 16px;
    background: var(--fundo-aviso);
    border: 0;
    border-radius: var(--radius);
    transition: all 0.3s;
}

.pendencia-item.ignorado {
    background: var(--fundo-ok);
    opacity: 0.7;
}

.pendencia-item-info strong { font-size: 14px; color: var(--ink); }
.pendencia-item-counts { display: flex; gap: 8px; margin-top: 4px; }

.pendencia-count { font-size: 12px; padding: 2px 8px; border-radius: var(--radius); font-weight: 600; }
.pendencia-count.nfe { background: var(--fundo-erro); color: var(--accent-red); }
.pendencia-count.nfce { background: var(--fundo-aviso); color: var(--accent-orange); }

.pendencia-item-actions { display: flex; gap: 6px; flex-shrink: 0; }


/* Quantos clientes cada escolha atinge, dentro do proprio botao. Sem isto
   as duas opcoes sao simetricas no texto e a pessoa tem de contar a lista
   para saber o que esta escolhendo. */
/* Herda a forma do `badge-pill` do documento; aqui só a tinta, que segue a
   cor do botão em que ele está. */
.pendencia-qtd {
    margin-left: var(--space-2);
    background: color-mix(in srgb, currentColor 16%, transparent);
    color: inherit;
    font-variant-numeric: tabular-nums;
}

.pendencia-footer {
    padding: var(--space-4) var(--space-5);
    justify-content: flex-end;
    gap: var(--space-2);
    display: flex;
    flex-wrap: wrap;
    background: var(--preenchimento);
}


/* =====================================================================
   Vendas
   ===================================================================== */
/* Meses fechados: a linha da Distribuição por tipo do Painel (.tipo-linha),
   sem as colunas de percentual e de seta. */
.tipo-linha.vendas-mes { grid-template-columns: 104px minmax(0, 1fr) auto; }


/* =====================================================================
   Central de XML / Contadores
   ===================================================================== */
.central-wrap { display: flex; flex-direction: column; height: 100%; min-height: 0; }

/* Só na Central: o corpo é uma tabela longa, e 24px de respiro em cima custam
   meia linha numa tela de 768px. As outras telas seguem com o padding padrão. */
.main-body:has(.central-wrap) { --main-body-topo: 12px; padding: var(--main-body-topo) 16px; }

/* O título "Central de XML & Contadores" e o subtítulo saíram: diziam o mesmo
   que o breadcrumb e o botão Central já aceso na topbar, e custavam ~60px de
   altura numa tela cujo conteúdo é uma tabela de 184 linhas. */
.central-header { padding: 0 0 8px 0; }

.central-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* Os grupos da toolbar (busca, filtros, ações) eram divs comuns: o espaço entre
   os botões era o whitespace do HTML — e os filtros, montados por concatenação
   sem separador, saíam grudados. Gap explícito e igual nos três. */
.central-toolbar > div { display: flex; align-items: center; gap: var(--space-2); }

/* Clientes/Contadores trocam o conteúdo da tabela abaixo — são um seletor, não
   duas ações. Eram dois botões soltos, iguais aos de ação. Passam ao mesmo
   trilho da navegação do topo, que já é o idioma de "escolha um" no app:
   fundo comum, segmento aceso, e a borda envolvendo os dois para dizer que
   pertencem ao mesmo grupo. */


.central-search {
    min-width: 240px;
}


.central-search-wrap { position: relative; display: inline-flex; align-items: center; }
.central-search-wrap .central-search { padding-right: 30px; }

.central-search-clear {
    position: absolute;
    right: 7px;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--mute);
    cursor: pointer;
}



/* Regime e Vínculo abrem um menu e restringem a lista — não executam nada.
   O que os distingue de uma ação é a seta, não a casca: já foram tracejados e
   sem fundo, e do lado do campo de busca isso lia como desabilitado. Casca de
   controle secundário; o azul aparece só quando há filtro aplicado. */

.central-toolbar-filter .icon { width: 17px; height: 17px; }


.central-filtro-seta {
    display: inline-flex;
    color: var(--mute);
    margin-left: -1px;
}

.central-filtro-seta .icon { width: 15px; height: 15px; }


.central-toolbar-filter .count {
    display: inline-block;
    margin-left: -1px;      /* o gap do flex já separa */
    padding: 1px 7px;
    border-radius: var(--radius-sm);
    background: var(--link);
    color: var(--primary-on);
    font-size: 11px;
    font-weight: 700;
}

/* Coluna: a tabela fica com o que sobra e rola por dentro; a barra de contagem
   fica presa embaixo, sempre visível. Antes o `max-height` fixo da tabela
   ignorava o espaço real e empurrava a contagem para fora da tela em 1366. */
.central-body { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-height: 0; }
.central-empty { text-align: center; padding: 60px 20px; color: var(--body); }
.central-error { padding: 16px; color: var(--accent-red); text-align: center; }

/* Resultado inline — ao lado de um botão, dentro de um modal. O
   `.central-error` é bloco centralizado com 16px de respiro e não serve aqui;
   por isso cada tela vinha escrevendo `<span style="color:var(--accent-red)">`
   à mão. Tinta publicada (## Colors), não cor solta. */
/* Barra de status do rodapé: a contagem à esquerda e, à direita, os filtros que
   produziram essa contagem. Uma linha só — com muitos filtros ela rola na
   horizontal em vez de crescer e comer altura da tabela. */
.central-count {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 6px 4px 2px;
    font-size: 12px;
    color: var(--body);
    flex: 0 0 auto;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: thin;
}

.central-count-num { flex: 0 0 auto; }

.central-count-flash { animation: centralCountFlash 0.6s ease; }

/* Sem max-height: o flex do .central-body já entrega a altura disponível, e
   qualquer número fixo aqui erra quando a barra de contagem ou os chips mudam
   de tamanho. */
.central-table-wrap {
    flex: 1;
    min-height: 0;
    overflow: auto;
    border-radius: var(--radius);
    border: 0;
    background: var(--surface-card);
}

/* ── TABELA PADRÃO DO APP ──────────────────────────────────────────────
   Uma classe só para toda tabela real do sistema (Clientes, Contadores,
   Pendências do dashboard, cClassTrib/NCM, Servidores, Histórico). Era 3
   blocos espalhados pelo arquivo (um deles com um `background` de cabeçalho
   que nunca aparecia — outros dois, mais abaixo na cascata, sempre
   sobrescreviam de volta) — juntos aqui, um lê o outro sem procurar. */
.central-table {
    width: 100%;
    border-collapse: collapse;
    /* Via token: é a grid de Clientes que o Modo compacto mais aperta — ver
       o fim do arquivo. */
    font-size: var(--tabela-fs);
    /* auto + min-width por coluna: as colunas respiram conforme o conteúdo
       e o wrapper rola na horizontal quando não couber */
    table-layout: auto;
    /* border-collapse não respeita border-radius sozinho — sem este overflow
       (na TABELA, não só no wrap) os cantos da primeira/última linha ficam
       quadrados por dentro da moldura arredondada. Load-bearing também para
       quem usa .central-table sem `.central-table-wrap` (a sub-tabela "Por
       regime" do cClassTrib, app.js) — ali é a única borda/canto que existe. */
    border: 0;
    border-radius: var(--radius);
    overflow: hidden;
}

.central-table th {
    position: sticky;
    top: 0;
    background: var(--tabela-cabecalho);
    color: var(--mute);
    text-align: left;
    padding: var(--tabela-th-pad);
    /* var(--fs-xs) + peso 400: é literalmente {typography.caption} do
       DESIGN.md (12px/400), que a derivação `table-dense` já manda usar no
       cabeçalho (linha 621) — nenhuma das 3 peles antigas batia com isto:
       uma tinha 11px sem token, as outras pesavam 500/600. */
    font-size: var(--fs-xs);
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    border-bottom: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    /* .central-th-acoes soma +1 a este valor (calc(var(--z-sticky) + 1)) pra
       ficar por cima do resto do cabeçalho ao rolar — os dois têm que citar
       o mesmo token, ou a coluna de ações some atrás do cabeçalho normal. */
    z-index: var(--z-sticky);
}

.central-table td { height: var(--tabela-linha-h); padding: var(--tabela-td-pad); border-bottom: 0; vertical-align: middle; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A primeira coluna afasta da borda arredondada do cartão, cabeçalho e linhas juntos. */
.central-table :is(th, td):first-child, .hist-tabela :is(th, td):first-child { padding-left: var(--space-4); }

/* ── Separador de coluna = alça de largura (assets/js/colunas.js). Pedido em 2026-09-26: exceção à decisão 3. ── */
.col-redim {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 9px;
    cursor: col-resize;
    touch-action: none;
}
.col-redim::after {
    content: '';
    position: absolute;
    top: 22%;
    bottom: 22%;
    right: 0;
    width: 1px;
    background: var(--hairline-strong);
}
.col-redim:hover::after, .col-redim.ativa::after { top: 0; bottom: 0; width: 2px; background: var(--link); }
body.col-arrastando { user-select: none; }

.central-row { cursor: default; user-select: text; }
/* A linha de Clientes não é clicável (só o menu de contexto), a de Contadores
   abre o cadastro. Em vez de marcar a tela, o seletor segue o próprio onclick:
   qualquer tabela que passe a ter linha clicável já nasce com a mão. */
.central-row[onclick] { cursor: pointer; }
/* var(--surface-hover): é o token com o nome certo pra isso — antes usava
   --fundo-info (tom de aviso informativo) só porque coincidia no tema claro;
   no escuro os dois divergem. */
.central-row:hover { background: var(--surface-hover); }

/* Zebra: linhas pares recebem um tingimento leve por cima do fundo normal.
   :not(:is(...)) é obrigatório — cada classe da lista já pinta fundo
   próprio, e sem excluí-las a zebra pisca por cima dependendo da paridade da
   linha (ver centralnotas.check.js). Lista central, e não uma por classe: é
   a mesma exclusão repetida em 4 regras (zebra, ações, hover, ações+hover) —
   nome novo aqui é só um lugar a lembrar de atualizar, não quatro. */
.central-table tbody tr:nth-child(even):not(:is(.central-atencao, .central-row-obs)) {
    background: var(--zebra-tint);
}
/* A coluna de ações é sticky e por isso já declara o PRÓPRIO fundo sólido
   (senão mostraria as células rolando por baixo dela) — essa declaração
   vence a zebra do <tr>, então sem esta regra irmã a coluna de ações vira uma
   faixa sólida ao lado de linhas zebradas. Mesmo tom, repintado na célula. */
.central-table tbody tr:nth-child(even):not(:is(.central-atencao, .central-row-obs)) .central-col-acoes {
    background: color-mix(in srgb, var(--ink) 3%, var(--surface-card));
}
/* A zebra acima tem MAIS especificidade que `.central-row:hover`/
   `.central-row:hover .central-col-acoes` sozinhos — sem repetir o mesmo
   seletor aqui, passar o mouse numa linha par não mudaria nada, porque a
   zebra continuaria vencendo por especificidade. */
.central-table tbody tr:nth-child(even):not(:is(.central-atencao, .central-row-obs)):hover {
    background: var(--surface-hover);
}
.central-table tbody tr:nth-child(even):not(:is(.central-atencao, .central-row-obs)):hover .central-col-acoes {
    background: var(--surface-hover);
}

/* ── Selo de célula: UMA forma para todo estado dentro de tabela ── */
.central-status-badge, .central-cert, .central-pend-badge,
.central-vpn-badge, .central-sem-vinculo-badge, .central-table .badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-1);
    height: var(--selo-h);
    padding: 0 var(--space-2);
    border-radius: var(--radius-sm);
    font-size: var(--fs-xs);
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
    vertical-align: middle;
}
:is(.central-status-badge, .central-vpn-badge, .central-sem-vinculo-badge, .central-table .badge) .icon { width: 13px; height: 13px; }
/* Chip é dado, não estado: a mesma altura e raio, fundo neutro e a fonte da tabela. */
.central-chip {
    display: inline-block;
    height: var(--selo-h);
    line-height: var(--selo-h);
    padding: 0 var(--space-2);
    margin: 1px var(--space-1) 1px 0;
    border-radius: var(--radius-sm);
    background: var(--preenchimento);
    color: var(--ink);
    font-size: var(--tabela-fs);
    white-space: nowrap;
    vertical-align: middle;
}
/* O logo já identifica o sistema: sem caixa em volta. */
.central-chip.central-chip-sis {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: 0;
    background: none;
}

/* Certificado digital por filial (app.js, viewCertDetail): a validade no selo
   da grid de Clientes (.central-cert) e a situação com o ícone na cor. A linha
   inteira tingida, junto com os dois, dizia a mesma coisa pela terceira vez. */
.cert-tabela { max-height: 480px; }
.cert-razao, .lixeira-sub { display: block; font-size: var(--fs-xs); color: var(--mute); overflow: hidden; text-overflow: ellipsis; }

/* Lixeira de clientes (central.js, abrirLixeiraClientes): a tabela padrão, a
   razão social e quem mandou para a lixeira em linha menor embaixo. */
.lixeira-tabela { max-height: calc(100vh - 300px); }
.lixeira-acoes { width: 1%; text-align: right; }
.lixeira-obs { margin: 0; white-space: pre-wrap; font-size: var(--fs-sm); color: var(--body); }

/* ─────────── Página do cliente (central.js, centralAbrirCliente) ───────────
   O modal de Editar virou uma aba: o cabeçalho de tela, as subabas no
   controle segmentado e as seções da ficha em cards do Painel — os títulos
   delas são os h3 de .panel-card. */
.cli-subabas { margin-bottom: var(--space-5); }
/* A barra da página: as subabas à esquerda, as ações (Salvar, Relatórios...) à
   direita — a página não tem mais cabeçalho: o nome, a razão social e a foto já
   estão no formulário. */
.cli-barra {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-3) var(--space-4);
    margin-bottom: var(--space-5);
}
.cli-barra .cli-subabas { margin-bottom: 0; min-width: 0; }
.cli-barra .tela-topo-dir { flex-wrap: wrap; justify-content: flex-end; }

/* O <select id="f-sistema"> some da tela: quem aparece é o botão-dropdown
   (central.js, centralSistemaCampoHtml) — o mesmo .central-ctx-menu do menu de
   linha e dos seletores de Acesso/Portal, com o logo do ERP em cada opção, que
   um <select> nativo não tem como mostrar. `.central-select` no botão é quem dá
   a aparência de campo (borda, altura, seta): reaproveita o vocabulário, não
   duplica. O logo é filho de verdade do botão (flex), não um selo por cima —
   por isso NADA de padding reservando espaço para ele: era espaço em dobro
   (padding + o próprio ícone) que sobrava pouco pro nome do sistema.
   `.sem-logo` só tira o gap, senão o span vazio deixava um vão à esquerda. */
.cli-sistema-campo > select { display: none; }
.cli-sistema-campo > .cli-sistema-controle {
    display: flex;
    align-items: center;
    width: 100%;
    max-width: none;
    /* `.central-select` sozinho cai no tamanho de barra (36px): aqui ele mora
       no formulário, na mesma linha de Regime/Situação especial/Validade do
       certificado (40px, --campo-fs) — sem isto o botão saía mais baixo e
       mais estreito que os vizinhos. */
    min-height: var(--campo-h);
    font-size: var(--campo-fs);
    text-align: left;
}
.cli-sistema-campo:not(.sem-logo) > .cli-sistema-controle { gap: var(--space-2); }
.cli-sistema-logo { display: inline-flex; align-items: center; flex-shrink: 0; }
.cli-sistema-logo .icone-sis { width: 18px; height: 18px; }
.cli-sistema-controle-txt { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cli-grade {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-4);
}
.cli-cheio { grid-column: 1 / -1; }
/* Cadastro novo: a ficha sozinha, sem a coluna de resumo (ainda não há o que
   resumir). `.cli-geral.cli-geral-novo` (as duas classes) para vencer o
   `.cli-geral` de cima por especificidade: uma classe só, na mesma força,
   perdia para ele por vir antes no arquivo — sobrava a coluna de 320px da
   lateral (vazia, sem resumo nenhum pra mostrar) e a ficha ficava espremida
   nos 564px que sobravam dela. */
.cli-geral.cli-geral-novo { grid-template-columns: minmax(0, 1fr); max-width: 900px; }
/* A subaba XML do cadastro novo tem o MESMO teto: sem ele, trocar de Geral
   (900px, acima) para XML esticava os cartões até a largura da tela inteira —
   a mesma tela mudando de largura ao trocar de subaba. */
.cli-grade.cli-grade-novo { max-width: 900px; }

/* A foto na ficha (central.js, centralFotoBlocoHtml): o retrato e os botões ao lado. */
.cli-foto-bloco { display: flex; align-items: center; gap: var(--space-4); margin-bottom: var(--space-4); }
.cli-foto { width: 72px; height: 72px; font-size: var(--fs-h2); }
.cli-foto-acoes { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
.cli-foto-botoes { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.cli-foto-dica { font-size: var(--fs-xs); color: var(--mute); }

/* A marca miúda do cliente na grid, na lixeira e no seletor do portal: a foto, ou
   as iniciais. */
.cli-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 24px;
    height: 24px;
    margin-right: var(--space-2);
    vertical-align: middle;
    border-radius: var(--radius-md);
    overflow: hidden;
    background: color-mix(in srgb, var(--link) 12%, transparent);
    color: var(--link);
    font-size: var(--fs-xs);
    font-weight: 600;
    letter-spacing: 0.02em;
}
.lixeira-nome { display: flex; align-items: center; gap: var(--space-2); }
.lixeira-nome .cli-avatar { margin-right: 0; }
.lixeira-nome-txt { min-width: 0; }

/* Aba Geral: a ficha (o que se edita) num card só, e ao lado o resumo (o que se
   consulta) — o "About" do HubSpot, a coluna de detalhes da Stripe. As seções
   da ficha se separam por espaço e título, sem régua (decisão 3). */
.cli-geral {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: var(--space-4);
    align-items: start;
}
/* Fiscal numa linha: quatro campos curtos. No modal de cliente novo continua em duas. */
.cli-ficha .dlg-grade-fiscal { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.cli-fatos { display: flex; flex-direction: column; gap: var(--space-1); }
/* Linha do resumo. A margem negativa alinha o texto à borda do card e deixa o
   fundo do hover respirar para fora dele. */
.cli-fato {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--space-2);
    row-gap: 2px;
    margin: 0 calc(var(--space-3) * -1);
    padding: var(--space-2) var(--space-3);
    border: 0;
    border-radius: var(--radius-md);
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: left;
}
.cli-fato > :not(.cli-fato-ir) { grid-column: 1; }
.cli-fato-ir { grid-column: 2; grid-row: 1 / span 3; align-self: center; color: var(--mute); }
.cli-fato-ir .icon { width: 16px; height: 16px; }
.cli-fato.acionavel { cursor: pointer; }
.cli-fato.acionavel:hover { background: var(--preenchimento); }
.cli-fato.acionavel:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; }
.cli-fato-rotulo { font-size: var(--fs-xs); color: var(--mute); }
.cli-fato-valor { font-size: var(--fs-sm); font-weight: 500; color: var(--ink); overflow-wrap: anywhere; }
.cli-fato-sub { font-size: var(--fs-xs); color: var(--body); overflow-wrap: anywhere; }
.cli-fato-vazio { color: var(--mute); font-weight: 400; }
.cli-fato-valor .central-cert { margin-left: var(--space-1); vertical-align: 1px; }
.cli-fato-erro { color: var(--accent-red); }
/* Os interruptores já estão num card: o fundo próprio do modal virava card
   dentro de card. */
.cli-pagina .dlg-opcoes { padding: 0; background: none; }
.cli-sujo {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--fs-sm);
    color: var(--body);
}
.cli-sujo[hidden] { display: none; }
.cli-sujo .icon { width: 16px; height: 16px; color: var(--accent-orange); }
/* A barra do Histórico de envios logo abaixo das subabas: a margem de cima
   dela dobrava o respiro que as subabas já dão. O par de classes vence o
   .hist-xml-barra, que vem depois no arquivo. A do Resumo, a mesma coisa. */
.hist-xml-barra.cli-envios-barra, .hist-xml-barra.cli-vendas-barra { margin-top: 0; }
.cli-vendas-datas { font-size: var(--fs-xs); color: var(--mute); }
/* O display: flex de .central-toolbar > div vence o [hidden] no empate: sem
   isto o "Só fiscal" aparecia para o cliente sem vendas (GDOOR, sem vínculo). */
.cli-vendas-fiscal[hidden] { display: none; }

/* =====================================================================
   Ícones animados — página do cliente (teste, 2026-09-28)
   O desenho se mexe por PARTES, como os ícones do claude.ai: o ponteiro do
   relógio volta no tempo, a tampa da lixeira abre, as barras sobem uma a
   uma. Os desenhos (Lucide) moram em icones_animados.js, e cada peça que se
   mexe tem uma classe ia-*; aqui cada peça ganha o seu movimento (--ia-anim)
   e, quando precisa, o ponto em torno do qual gira. O movimento só roda
   quando o botão, a aba ou o card do ícone recebe o mouse ou o foco do
   teclado, uma vez; o botão em si não se mexe. Quem pediu ao sistema menos
   movimento não vê nada (o gatilho mora no no-preference, lá embaixo).
   ===================================================================== */
@keyframes iaDesenha { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes iaAceno { 0%, 100% { transform: none; } 40% { transform: translateY(-1.5px); } 70% { transform: translateY(.5px); } }
@keyframes iaAbreEsq { 0%, 100% { transform: none; } 45% { transform: translateX(-2px); } }
@keyframes iaAbreDir { 0%, 100% { transform: none; } 45% { transform: translateX(2px); } }
@keyframes iaDestranca { 0%, 100% { transform: none; } 35% { transform: translateY(-2.5px); } 60% { transform: translateY(-2.5px) rotate(-16deg); } 85% { transform: translateY(-.5px); } }
@keyframes iaRebobina { from { transform: none; } to { transform: rotate(-360deg); } }
@keyframes iaRecua { 0%, 100% { transform: none; } 45% { transform: rotate(-30deg); } }
@keyframes iaVoa { 0%, 100% { transform: none; opacity: 1; } 40% { transform: translate(7px, -7px); opacity: 0; } 41% { transform: translate(-7px, 7px); opacity: 0; } }
@keyframes iaEtiqueta { 0%, 100% { transform: none; } 40% { transform: translateY(.8px); } }
@keyframes iaJanela { 0%, 100% { transform: none; } 50% { transform: translateX(2.5px); } }
@keyframes iaTampa { 0%, 100% { transform: none; } 40%, 60% { transform: translateY(-1px) rotate(14deg); } }
@keyframes iaGira { from { transform: none; } to { transform: rotate(360deg); } }
@keyframes iaSobe { 0%, 100% { transform: none; } 45% { transform: translateY(-3px); } 70% { transform: translateY(.5px); } }
@keyframes iaDesce { 0%, 100% { transform: none; } 45% { transform: translateY(3px); } 70% { transform: translateY(-.5px); } }
@keyframes iaOlha { 0%, 60%, 100% { transform: none; } 20% { transform: translateX(-2.5px); } 42% { transform: translateX(2.5px); } }
@keyframes iaPisca { 0%, 62%, 100% { transform: none; } 75% { transform: scaleY(.1); } }
@keyframes iaSaiDeTras { from { transform: translate(-4px, -4px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes iaGiraX { from { transform: none; } to { transform: rotate(90deg); } }
@keyframes iaEncaixaA { from { transform: translate(2.5px, -2.5px); } to { transform: none; } }
@keyframes iaEncaixaB { from { transform: translate(-2.5px, 2.5px); } to { transform: none; } }
@keyframes iaSoltaA { 0%, 100% { transform: none; } 45% { transform: translate(1.5px, -1.5px); } }
@keyframes iaSoltaB { 0%, 100% { transform: none; } 45% { transform: translate(-1.5px, 1.5px); } }
@keyframes iaFaisca { 0%, 100% { opacity: 1; transform: none; } 30% { opacity: 0; transform: scale(.4); } 55% { opacity: 1; transform: scale(1.3); } }
@keyframes iaQuarto { 0% { transform: none; } 45% { transform: rotate(60deg) scale(.75); } 100% { transform: rotate(90deg); } }
@keyframes iaPonto { 0% { transform: scale(0); } 60% { transform: scale(1.8); } 100% { transform: none; } }
@keyframes iaEmpurra { 0%, 50%, 100% { transform: none; } 25%, 75% { transform: translateX(2px); } }
@keyframes iaBalanca { 0%, 100% { transform: none; } 20% { transform: rotate(-16deg); } 40% { transform: rotate(13deg); } 60% { transform: rotate(-8deg); } 80% { transform: rotate(4deg); } }
@keyframes iaVira { from { transform: none; } to { transform: rotateY(360deg); } }
@keyframes iaArgola { 0%, 100% { transform: none; } 40% { transform: translateY(-2px); } }
@keyframes iaRola { 0%, 100% { transform: none; } 35% { transform: translateX(2px); } 65% { transform: translateX(-1px); } }
@keyframes iaCesta { 0%, 100% { transform: none; } 35% { transform: rotate(-5deg); } 65% { transform: rotate(3deg); } }
@keyframes iaRecuaPonta { 0%, 100% { transform: none; } 40% { transform: translateX(-2.5px); } }

/* Cada peça gira ou escala em torno do próprio centro, salvo quando diz outro
   ponto (em coordenadas do desenho, que é 24x24). O que sai dos 24 aparece. */
.ia { overflow: visible; --ia-mola: cubic-bezier(.34, 1.56, .64, 1); }
.ia [class^="ia-"] { transform-box: fill-box; transform-origin: center; }
.ia [pathLength] { stroke-dasharray: 1; }

.ia .ia-barra-1 { --ia-anim: iaDesenha; }
.ia .ia-barra-2 { --ia-anim: iaDesenha; --ia-atraso: .08s; }
.ia .ia-barra-3 { --ia-anim: iaDesenha; --ia-atraso: .16s; }
.ia .ia-cabeca { --ia-anim: iaAceno; }
.ia .ia-linha-1 { --ia-anim: iaDesenha; --ia-atraso: .1s; }
.ia .ia-linha-2 { --ia-anim: iaDesenha; --ia-atraso: .2s; }
.ia .ia-abre { --ia-anim: iaAbreEsq; }
.ia .ia-fecha { --ia-anim: iaAbreDir; }
.ia .ia-arco { --ia-anim: iaDestranca; transform-box: view-box; transform-origin: 7px 10px; --ia-dur: .7s; }
.ia .ia-ponteiros { --ia-anim: iaRebobina; transform-box: view-box; transform-origin: 12px 12px; --ia-dur: .7s; }
.ia .ia-volta { --ia-anim: iaRecua; transform-box: view-box; transform-origin: 12px 12px; }
.ia .ia-aviao { --ia-anim: iaVoa; --ia-dur: .7s; }
.ia .ia-etiqueta { --ia-anim: iaEtiqueta; }
.ia .ia-janela { --ia-anim: iaJanela; }
.ia .ia-tampa { --ia-anim: iaTampa; transform-box: view-box; transform-origin: 21px 6px; }
.ia .ia-gira { --ia-anim: iaGira; transform-box: view-box; transform-origin: 12px 12px; --ia-dur: .7s; }
.ia .ia-sobe { --ia-anim: iaSobe; }
.ia .ia-desce { --ia-anim: iaDesce; }
.ia .ia-olho { --ia-anim: iaPisca; --ia-dur: .9s; }
.ia .ia-pupila { --ia-anim: iaOlha; --ia-dur: .9s; }
.ia .ia-folha { --ia-anim: iaSaiDeTras; }
.ia .ia-xis { --ia-anim: iaGiraX; transform-box: view-box; transform-origin: 12px 12px; --ia-curva: var(--ia-mola); }
.ia .ia-elo-1 { --ia-anim: iaEncaixaA; --ia-curva: var(--ia-mola); }
.ia .ia-elo-2 { --ia-anim: iaEncaixaB; --ia-curva: var(--ia-mola); }
.ia .ia-metade-1 { --ia-anim: iaSoltaA; }
.ia .ia-metade-2 { --ia-anim: iaSoltaB; }
.ia .ia-faisca { --ia-anim: iaFaisca; transform-box: view-box; transform-origin: 12px 12px; }
.ia .ia-mais { --ia-anim: iaQuarto; transform-box: view-box; transform-origin: 12px 12px; --ia-curva: var(--ia-mola); }
.ia .ia-ponto-1 { --ia-anim: iaPonto; }
.ia .ia-ponto-2 { --ia-anim: iaPonto; --ia-atraso: .08s; }
.ia .ia-ponto-3 { --ia-anim: iaPonto; --ia-atraso: .16s; }
.ia .ia-item-1 { --ia-anim: iaDesenha; }
.ia .ia-item-2 { --ia-anim: iaDesenha; --ia-atraso: .08s; }
.ia .ia-item-3 { --ia-anim: iaDesenha; --ia-atraso: .16s; }
.ia .ia-seta { --ia-anim: iaEmpurra; }
.ia .ia-exclama { --ia-anim: iaBalanca; transform-box: view-box; transform-origin: 12px 17px; --ia-dur: .7s; }
.ia .ia-moeda { --ia-anim: iaVira; --ia-dur: .7s; }
.ia .ia-divisa { --ia-anim: iaDesenha; --ia-atraso: .1s; }
.ia .ia-argola-1 { --ia-anim: iaArgola; }
.ia .ia-argola-2 { --ia-anim: iaArgola; --ia-atraso: .08s; }
.ia .ia-carrinho { --ia-anim: iaRola; }
.ia .ia-cesta { --ia-anim: iaCesta; transform-box: view-box; transform-origin: 6px 14px; }
.ia .ia-ponta { --ia-anim: iaRecuaPonta; }
.ia .ia-curva { --ia-anim: iaDesenha; --ia-atraso: .1s; }

/* O gatilho é um só. O "Alterações não salvas" anima uma vez quando aparece
   (sai de display: none). */
@media (prefers-reduced-motion: no-preference) {
    .cli-pagina :is(button:not(:disabled), a, summary):is(:hover, :focus-visible) .ia [class^="ia-"],
    .cli-pagina .kpi-card:hover .ia [class^="ia-"],
    .cli-sujo:not([hidden]) .ia [class^="ia-"] {
        animation: var(--ia-anim) var(--ia-dur, .6s) var(--ia-curva, var(--ease-std)) var(--ia-atraso, 0s) both;
    }
}

/* Histórico de eventos: três números e a linha do tempo por mês, no idioma da
   Atividade do Painel (.timeline) — sem régua entre os itens. */
.cli-resumo { margin-bottom: var(--space-5); }
.cli-eventos { display: flex; flex-direction: column; gap: var(--space-5); }
.cli-mes h3 {
    margin: 0 0 var(--space-2);
    font-size: var(--fs-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--mute);
}
.cli-linha { padding-top: var(--space-2); padding-bottom: var(--space-2); }
.cli-evento {
    display: grid;
    grid-template-columns: 32px minmax(0, 1fr) auto;
    align-items: start;
    gap: var(--space-3);
    padding: var(--space-3) 0;
}
.cli-evento .kpi-ico .icon { width: 17px; height: 17px; }
.cli-evento-txt { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.cli-evento-txt strong { font-size: var(--fs-sm); font-weight: 600; color: var(--ink); }
.cli-evento-meta { font-size: var(--fs-xs); color: var(--body); }
.cli-evento-chips { display: flex; flex-wrap: wrap; gap: var(--space-1); }
.cli-evento-chips span {
    padding: 2px 8px;
    border-radius: var(--radius-sm);
    background: var(--preenchimento);
    color: var(--ink);
    font-size: var(--fs-xs);
}
.cli-evento-detalhe { font-size: var(--fs-xs); color: var(--mute); overflow-wrap: anywhere; }
/* Antes e depois de cada campo que o painel corrigiu. O antes riscado e
   apagado, o depois na cor do texto: a leitura é "estava assim, ficou assim". */
.cli-evento-mudancas { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px;
    font-size: var(--fs-xs); color: var(--body); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.cli-evento-mudancas del { color: var(--mute); }
.cli-evento-mudancas ins { text-decoration: none; color: var(--ink); font-weight: 600; }
.cli-mud-ref { color: var(--mute); }
.cli-evento-mais summary { font-size: var(--fs-xs); color: var(--link); cursor: pointer; }
.cli-resolucao { margin-bottom: var(--space-5); }
/* Falha: o título e o motivo em vermelho — é o que se procura aqui. */
.cli-evento.erro .cli-evento-txt strong,
.cli-evento.erro .cli-evento-detalhe { color: var(--accent-red); }
.cli-evento-lado { display: flex; align-items: center; gap: var(--space-2); }
.cli-evento-quando { font-size: var(--fs-xs); color: var(--mute); font-variant-numeric: tabular-nums; white-space: nowrap; }
.cert-situacao { display: inline-flex; align-items: center; gap: var(--space-1); color: var(--ink); }
.cert-situacao .icon { width: 18px; height: 18px; flex-shrink: 0; }
.cert-situacao.ok .icon { color: var(--accent-green); }
.cert-situacao.proximo .icon { color: var(--accent-orange); }
.cert-situacao.expirado .icon { color: var(--accent-red); }

.central-row-inativo { opacity: 0.45; filter: grayscale(0.6); }
.central-row-inativo:hover { opacity: 0.7; }

/* Cliente de Uniplus Desktop sem VPN: esmaecido e marcado como indisponível.
   Distinto do inativo (que é escolha do usuário) — este é estado de conexão,
   por isso mantém a cor e ganha o selo. */
.central-row-offline { opacity: 0.55; }
.central-row-offline:hover { opacity: 0.75; }
.central-row-offline .central-cliente-nome,
.central-row-offline .central-col-razao { text-decoration: none; }

.central-vpn-badge {
    margin-left: var(--space-2);
    background: var(--fundo-erro);
    color: var(--accent-red);
    cursor: help;
}

/* Item de menu indisponível: visível, mas claramente inerte. */
.central-ctx-menu-item.desabilitado {
    opacity: 0.4;
    cursor: not-allowed;
}
.central-ctx-menu-item.desabilitado:hover { background: none; }
.central-ctx-menu-item.desabilitado:hover > .icon { color: var(--body); }
.mono { font-variant-numeric: tabular-nums; font-size: 12px; }

/* Chip de sistema: o logo do ERP antes do nome (a forma do .central-chip está junto da tabela). */
.central-chip-sis .icone-sis { width: 16px; height: 16px; }
.central-chip-sis span.icon-fallback.icone-sis { font-size: 9px; }

/* Campo obrigatório do cadastro. O asterisco só aparece quando a obrigação
   existe de verdade — Uniplus Web —, porque um asterisco permanente em campo
   que às vezes é opcional deixa de significar coisa alguma. */
.central-obrigatorio {
    color: var(--accent-red);
    font-weight: 600;
    margin-left: 2px;
    vertical-align: super;
    font-size: var(--fs-xs);
}

.central-sem-vinculo-badge {
    margin-left: var(--space-2);
    background: var(--fundo-erro);
    color: var(--accent-red);
}

.central-email-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    padding: 6px;
    border-radius: var(--radius);
    border: 1px solid var(--hairline);
    background: var(--surface-card);
    min-height: 38px;
    align-items: center;
}

.central-email-tags:focus-within { border-color: var(--link); }

.central-email-tag {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 9px;
    border-radius: var(--radius-sm);
    background: var(--fundo-info);
    border: 0;
    color: var(--ink);
    font-size: 12px;
    max-width: 100%;
    white-space: nowrap;
}

.central-email-tag .central-email-x {
    background: none;
    border: none;
    color: var(--body);
    cursor: pointer;
    font-size: 12px;
    line-height: 1;
    padding: 0 2px;
    flex-shrink: 0;
    font-family: inherit;
}

.central-email-tag .central-email-x:hover { color: var(--accent-red); }

.central-email-tags .central-email-input {
    flex: 1;
    min-width: 150px;
    width: auto !important;
    background: transparent !important;
    border: none !important;
    box-shadow: none;
    padding: 3px 4px;
    outline: none;
    color: var(--ink);
    font-size: 12px;
}

.central-email-tags .central-email-input::placeholder { color: var(--body); opacity: 0.6; }

.central-msg { font-size: 12px; color: var(--body); }
/* O par de erro do .central-msg. Existia como `style=` repetido em quatro
   pontos do central.js, com a medida cravada. */
.central-msg-erro { font-size: var(--fs-xs); color: var(--accent-red); }


.central-envios { display: flex; flex-direction: column; gap: 6px; }

.central-envio {
    display: flex;
    gap: 10px;
    align-items: center;
    font-size: 12px;
    padding: 6px 8px;
    background: var(--surface-card);
    border-radius: var(--radius);
    flex-wrap: wrap;
}

.central-envio.erro { background: var(--fundo-erro); }
.central-envio.enviado { background: var(--fundo-ok); }
.central-envio.nao_emitiu, .central-envio.sem_emissao { background: var(--fundo-aviso); }

/* Atenção */
.central-atencao-badge { display: inline-block; margin-left: 6px; cursor: default; font-size: 12px; }

.central-atencao-tooltip {
    position: fixed;
    z-index: 3000;
    max-width: 320px;
    background: var(--surface-flutuante);
    box-shadow: var(--sombra-flutuante);
    border-radius: var(--radius);
    padding: 8px 10px;
    pointer-events: none;
    font-size: 12px;
    line-height: 1.4;
}

.central-atencao-tooltip-text { color: var(--ink); white-space: pre-wrap; }

/* Balão combinado: o Ponto de Atenção lidera, em destaque; a Observação vem
   abaixo, em tom secundário e sem alarde. */
.central-balao-atencao {
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-sm);
    background: var(--fundo-aviso);
}
.central-balao-atencao .central-atencao-tooltip-text { font-weight: 600; }
.central-balao-atencao .icon { width: 15px; height: 15px; color: var(--accent-yellow); vertical-align: -2px; }

.central-balao-obs { margin-top: var(--space-2); }
/* Separador só quando os dois blocos aparecem juntos. */
.central-balao-atencao + .central-balao-obs {
    padding-top: var(--space-2);
    border-top: 0;
}
.central-balao-rotulo {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: var(--fs-xs);
    font-weight: 700;
    color: var(--body);
    text-transform: uppercase;
    letter-spacing: .03em;
    margin-bottom: 3px;
}
.central-balao-rotulo .icon { width: 14px; height: 14px; }
.central-balao-texto { color: var(--ink); white-space: pre-wrap; }

.central-atencao-tooltip-exp {
    margin-top: 6px;
    padding-top: 6px;
    border-top: 0;
    color: var(--body);
    font-size: 11px;
}

/* O campo e o rótulo do padrão (os do .dlg-campo das fichas). */
.central-atencao-modal textarea,
.central-atencao-modal input[type="date"] {
    width: 100%;
    margin-bottom: var(--space-4);
}

.central-atencao-label {
    display: block;
    margin-bottom: 6px;
}

.central-row.central-atencao { animation: centralAtencaoShimmer 2.2s ease-in-out infinite; }

.central-row-foco {
    animation: centralFocoPulse 1.2s ease-in-out 3;
}

/* Switch: trilho em pílula, desligado em cinza e ligado na cor de ação — o
   padrão de qualquer ajuste liga/desliga. Era vermelho quando desligado, e
   "desligado" não é erro: é só um cliente que não entra na varredura. */
.central-switch { position: relative; display: inline-block; width: 40px; height: 22px; flex-shrink: 0; cursor: pointer; }
.central-switch input[type="checkbox"] { position: absolute; opacity: 0; width: 0; height: 0; }
.central-switch .slider {
    position: absolute; inset: 0; border-radius: var(--radius-full);
    background: color-mix(in srgb, var(--ink) 22%, transparent);
    transition: background var(--dur-fast) var(--ease-std);
}
.central-switch .slider::before {
    content: ""; position: absolute; height: 16px; width: 16px; left: 3px; top: 3px;
    background: var(--primary-on); border-radius: 50%; transition: transform var(--dur-fast) var(--ease-std);
}
.central-switch input:checked + .slider { background: var(--primary); }
.central-switch input:checked + .slider::before { transform: translateX(18px); }
.central-switch input:focus-visible + .slider { outline: 2px solid var(--link); outline-offset: 2px; }

/* Log */
.central-log-success {
    flex-basis: 100%;
    margin-top: 8px;
    padding: 8px 12px;
    border-radius: var(--radius);
    color: var(--accent-green);
    font-size: 12px;
    font-weight: 600;
    background: var(--fundo-ok);
    border: 0;
    position: relative;
    overflow: hidden;
    animation: centralLogIn 0.28s ease;
    transition: opacity 0.45s ease;
}

.central-log-success.saindo { opacity: 0; }


.central-log-working {
    color: var(--accent-orange);
    background: var(--fundo-aviso);
}

/* Diálogo */
.central-dialogo-overlay { z-index: 1200; }
/* Padding, título e alinhamento vêm do .modal — o diálogo genérico é só mais
   um modal (texto à esquerda, como todos). */
.central-dialogo h2 { margin: 0 0 var(--space-3); }
.central-dialogo p { margin: 0 0 var(--space-1); line-height: 1.5; }

.central-dialogo input[type="text"] {
    margin-top: var(--space-3);
    width: 100%;
}

.central-dialogo h3 { margin: 0 0 var(--space-3); font-size: var(--fs-lg); font-weight: 600; line-height: 1.25; }

/* Status badges */
.central-status-cell { display: flex; align-items: center; gap: var(--space-1); min-width: 160px; }

.central-status-badge { letter-spacing: 0.02em; cursor: default; }
.central-status-badge[onclick] { cursor: pointer; }

.central-status-enviado { color: var(--accent-green); background: var(--fundo-ok); }
.central-status-nao-emitiu { color: var(--accent-red); background: var(--fundo-erro); }
.central-status-pendente { color: var(--accent-yellow); background: var(--fundo-aviso); }
.central-status-no-drive { color: var(--accent-blue); background: var(--fundo-info); }
/* Neutro de propósito: não é pendência nem erro — o cliente simplesmente não
   está no fluxo de envio (os dois switches desligados). Sem cursor de clique:
   não há status do mês a editar. */
.central-status-nao-envia { color: var(--mute); background: var(--preenchimento); cursor: default; }
.central-status-obs { color: var(--serie-7); background: color-mix(in srgb, var(--serie-7) 12%, transparent); }
/* Observacao longa (PROBLEMAS AO EXPORTAR XML) empurrava a ultima coluna
   para fora da area visivel em 1366px. Corta com reticencias; o texto
   inteiro continua no title do badge. */
.central-status-obs { display: inline-block; max-width: 120px; line-height: var(--selo-h); overflow: hidden; text-overflow: ellipsis; }

/* Grid filters */
.central-th-filter { position: relative; white-space: nowrap; }
.central-th-filter > span { display: inline-flex; align-items: center; gap: 4px; max-width: 100%; vertical-align: middle; }
/* Coluna estreita: o rótulo encolhe com reticências e a seta de filtro continua lá. */
.central-th-rotulo { min-width: 0; overflow: hidden; text-overflow: ellipsis; }

.central-filter-btn {
    flex-shrink: 0;
}


/* Mesmo raio, elevação e animação dos menus de contexto — era raio 12px com a
   sombra achatada de card, destoando de todo painel flutuante do app. */
.central-filter-dropdown {
    position: fixed;
    z-index: 2000;
    background: var(--surface-flutuante);
    box-shadow: var(--sombra-flutuante);
    border-radius: var(--radius-lg);
    padding: var(--space-3);
    min-width: 200px;
    max-width: min(280px, calc(100vw - 16px));
    max-height: 400px;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    animation: ctxMenuEntra var(--dur-fast) var(--ease-std);
}

@media (prefers-reduced-motion: reduce) {
    .central-filter-dropdown { animation: none; }
}

.central-filter-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 12px;
    font-weight: 600;
    color: var(--ink);
    padding-bottom: 6px;
    border-bottom: 0;
}

.central-filter-search input {
    width: 100%;
}


.central-sort-btn {
    flex: 1;
}


.central-filter-select-all { display: flex; gap: 4px; padding-bottom: 6px; }

/* `.central-select-btn` existia no HTML e não no CSS: "Todos"/"Nada" saíam com
   o botão cru do navegador dentro de um painel estilizado — o mesmo defeito
   que a família btn-* já teve. São atalhos de seleção, então discretos NÃO
   podia virar INVISÍVEL: `.central-select-btn` sozinho cai na lista
   compartilhada do vocabulário de botões (grupo "Plain", mais abaixo no
   arquivo) e essa entrada zera a borda (`border-color: transparent`) --
   discreto virou "parece só texto". O seletor composto aqui (dois níveis)
   tem mais especificidade que a entrada solta da lista e ganha a cascata de
   volta, sem mexer no vocabulário compartilhado. */
.central-filter-select-all .central-select-btn {
    flex: 1;
}


.central-filter-options {
    max-height: 220px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.central-msg-sort { font-size: 11px; color: var(--body); padding: 2px 4px; opacity: 0.85; }

.central-filter-option {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    cursor: pointer;
    border-radius: var(--radius);
    transition: background 0.1s;
    font-size: 12px;
}

.central-filter-option:hover { background: var(--surface-hover); }


.central-filter-actions {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
    padding-top: 6px;
    border-top: 0;
}


/* `border: none` ali em cima zera até o ESTILO da borda (não só a cor) --
   por isso as duas linhas abaixo reafirmam o `border` inteiro, e não só
   `border-color`: um `border-color` sozinho não desenha nada sobre um
   `border-style: none` que ficou pra trás.
   Cancelar usava `var(--surface-card)`, a MESMA cor de fundo do próprio
   painel (`.central-filter-dropdown`) -- ficava com a cara de texto solto. */

/* Colunas fixas da tabela central */
/* CNPJ, IE e telefone no tamanho do resto da linha: o .mono solto é 12px. */
.central-table .mono { font-size: inherit; }
/* Larguras por min-width com rolagem horizontal, em vez de percentuais fixos:
   com 9 colunas, os percentuais espremiam tudo em telas menores. */
.central-table.tabela-clientes th:nth-child(1), .central-table.tabela-clientes td:nth-child(1) { min-width: 190px; }
.central-table.tabela-clientes th:nth-child(2), .central-table.tabela-clientes td:nth-child(2) { min-width: 70px; }
.central-table.tabela-clientes th:nth-child(3), .central-table.tabela-clientes td:nth-child(3) { min-width: 220px; }
.central-table.tabela-clientes th:nth-child(4), .central-table.tabela-clientes td:nth-child(4) { min-width: 150px; }
.central-table.tabela-clientes th:nth-child(5), .central-table.tabela-clientes td:nth-child(5) { min-width: 110px; }
.central-table.tabela-clientes th:nth-child(6), .central-table.tabela-clientes td:nth-child(6) { min-width: 130px; }
.central-table.tabela-clientes th:nth-child(7), .central-table.tabela-clientes td:nth-child(7) { min-width: 130px; }
.central-table.tabela-clientes th:nth-child(8), .central-table.tabela-clientes td:nth-child(8) { min-width: 150px; }
.central-table.tabela-clientes th:nth-child(9), .central-table.tabela-clientes td:nth-child(9) { min-width: 160px; }

/* Alinhamento por classe, nao por posicao: a coluna declara `estreita` na sua
   definicao e vale para qualquer aba. */
.central-table th.estreita, .central-table td.estreita { min-width: 70px; text-align: center; }

.central-col-pendencias { text-align: center; }
/* Célula de duas linhas (selo + último envio, filial + razão social): sem respiro vertical, cabe na altura da linha. */
.central-table td.central-col-envio,
.central-table td:has(.cert-razao, .lixeira-sub) { padding-top: 0; padding-bottom: 0; }
.central-ultimo-envio { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; }
.central-envio-cell {
    display: inline-flex;
    align-items: baseline;
    gap: var(--space-1);
    font-size: var(--fs-xs);
    line-height: 1.2;
    color: var(--mute);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.central-envio-badge::before { content: '·'; margin-right: var(--space-1); }
.central-envio-badge.erro { color: var(--accent-red); font-weight: 600; }

.central-cert { font-variant-numeric: tabular-nums; }

.central-cert.ok { color: var(--accent-green); background: var(--fundo-ok); }
.central-cert.proximo { color: var(--accent-orange); background: var(--fundo-aviso); }
.central-cert.expirado { color: var(--accent-red); background: var(--fundo-erro); }

/* Certificado digital (central.js, _certCorpoHtml). A marca é a .dlg-marca; o
   formulário cai na grade de 4 colunas do Fiscal, então Arquivo e Senha ficam
   embaixo de Sistema e Regime. Campo e botão são os do vocabulário. */
.cert-bloco { display: flex; align-items: flex-start; gap: var(--space-4); }
.cert-marca { color: var(--mute); background: var(--surface-hover); }
.cert-marca.ok { color: var(--accent-green); background: var(--fundo-ok); }
.cert-corpo { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding-top: 2px; }
.cert-nome { font-weight: 600; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cert-dica { font-size: var(--fs-xs); color: var(--mute); }
.cert-botoes { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); }
.cert-senha-ver { width: min(100%, 320px); margin-top: var(--space-3); }
.cert-form { margin-top: var(--space-4); }
/* Duas classes: a base de botões vem depois no arquivo e centralizaria o texto. */
.cert-form .cert-arquivo { width: 100%; justify-content: flex-start; }
.cert-arquivo > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cert-form-acoes { display: flex; align-items: flex-end; gap: var(--space-2); }

/* =====================================================================
   Keyframes
   ===================================================================== */
@keyframes spin { to { transform: rotate(360deg); } }

@keyframes pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.5; }
}

@keyframes pulse-log {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.6; }
}

@keyframes modalIn {
    from { opacity: 0; transform: scale(0.95) translateY(10px); }
    to { opacity: 1; transform: scale(1) translateY(0); }
}

@keyframes fadeIn {
    from { opacity: 0; transform: translateY(-8px); }
    to { opacity: 1; transform: translateY(0); }
}

@keyframes dot-shimmer {
    0% { background: var(--link); }
    100% { background: var(--accent-green); }
}

/* Servidor varrendo: era a borda que piscava azul↔verde; sem borda (decisão 3
   no topo), pisca o fundo, na tinta das mesmas duas cores. */
@keyframes varrendo-shimmer {
    0% { background: var(--fundo-info); }
    100% { background: var(--fundo-ok); }
}

@keyframes loadingBar {
    0% { left: -30%; }
    100% { left: 100%; }
}

@keyframes shimmer {
    0% { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}


/* Só cor: peso de fonte mudando no pisca era estado engrossando texto. */
@keyframes centralCountFlash {
    0% { color: var(--link); }
    100% { color: var(--body); }
}

/* A pulsação do ponto de atenção, DENTRO da família do aviso.
   Ela pulsava entre verde e azul. Como declaração de animação vence declaração
   normal, o `background: var(--fundo-linha-aviso)` da linha nunca aparecia: a
   linha de ponto de atenção — a mais grave da tela — piscava verde e azul,
   enquanto a de observação era amarela. Era essa a inconsistência do amarelo,
   e não a intensidade dele. */
/* Ponto de atenção: shimmer verde↔azul, e é assim de propósito.
   Eu troquei isto para amarelo por achar que "atenção deveria parecer aviso" —
   estava errado, e a decisão é do produto: o que distingue o ponto de atenção
   das outras linhas é o MOVIMENTO, não o matiz. O amarelo é a linguagem da
   observação; se os dois fossem amarelos, a linha de atenção viraria uma
   observação mais forte, que é justamente a confusão a evitar. */
@keyframes centralAtencaoShimmer {
    0%, 100% { background: var(--fundo-ok); }
    50% { background: var(--fundo-info); }
}

/* Movimento infinito é preferência do usuário, não decisão nossa: sem isto a
   linha pulsa para sempre para quem pediu para o sistema parar de animar. Para
   quem desligou a animação fica o estado de repouso do shimmer — o fundo
   verde, que nenhuma outra linha da tabela usa. */
@media (prefers-reduced-motion: reduce) {
    .central-row.central-atencao,
    .bank-item.bank-travado {
        animation: none;
        background: var(--fundo-ok);
    }
}

@keyframes centralFocoPulse {
    0%, 100% { background: var(--fundo-linha-aviso); }
    50% { background: color-mix(in srgb, var(--accent-orange-vivid) 34%, transparent); }
}

@keyframes centralShimmer {
    0% { left: -100%; }
    100% { left: 160%; }
}

@keyframes centralLogIn {
    from { transform: translateY(-6px); opacity: 0; }
    to { transform: translateY(0); opacity: 1; }
}

/* NOTA: o bloco "Responsivo" fica no FIM do arquivo (ver DESIGN.md ## Layout),
   para que as media queries vençam a cascata sobre os refinamentos de
   componente declarados depois desta linha. */

/* =====================================================================
   Componentes genéricos (tabs, stat-box, regime, relatório, cclass)
   ===================================================================== */
.tabs {
    display: flex;
    gap: 4px;
    margin-bottom: 12px;
    flex-wrap: wrap;
}

/* `.tab-btn` era um quarto jeito de desenhar "escolha uma seção" — quatro
   botões soltos em que o ativo virava azul cheio e os outros ficavam com casca
   de ação. O app já tem o idioma disso: `.central-tabs` (DESIGN.md ## Components). */
.tab-content[hidden] { display: none; }

/* Mesmo problema, três classes que também têm `display` próprio e por isso
   também vencem [hidden] no empate de especificidade — ver a nota em
   .login-split[hidden] (portal.html/portal.js as usa desse jeito). Aqui,
   e não junto da nota do portal, porque as três são globais: qualquer tela
   que fizer `elemento.hidden = true` num `.loading`/`.empty-state`/
   `.btn-plain` cai no mesmo silêncio. */
.loading[hidden], .empty-state[hidden], .btn-plain[hidden] { display: none; }

/* Quatro números em 2x2 dentro de uma coluna estreita, com o resto da tela
   vazio. `auto-fit` põe os quatro lado a lado quando há largura e recolhe
   sozinho quando não há. */
.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: var(--space-2);
    margin-bottom: var(--space-5);
}

.stat-box {
    background: var(--surface-card);
    padding: var(--space-4);
    border-radius: var(--radius);
    border: 0;
}
/* Cifra neutra (DESIGN.md ## Colors): quatro totais não são quatro alertas. */
.stat-val {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    font-size: 24px;
    font-weight: 600;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.02em;
}
.stat-pct { font-size: var(--fs-xs); font-weight: 600; color: var(--mute); }
.stat-rotulo { margin-top: var(--space-1); font-size: var(--fs-xs); color: var(--body); }
.stat-titulo { margin: 0 0 var(--space-2); font-size: var(--fs-sm); color: var(--body); }
.stat-vazio { color: var(--mute); font-size: var(--fs-sm); }

.relatorio-file-input {
    max-width: 260px;
}

.relatorio-upload-status {
    font-size: 12px;
    margin-top: 4px;
    color: var(--body);
}

.cclass-banco-e,
.cclass-servidor-e,
.cclass-tipo-e {
    width: 100%;
    min-width: 0;
}

.cclass-secoes { margin-bottom: var(--space-4); }
.cclass-regime-tabs { flex-wrap: wrap; }

/* Um banco modelo. Os três campos formam UMA linha: estavam em dois grids de
   duas colunas, então o Tipo ficava sozinho embaixo com o botão de remover
   flutuando ao lado dele. */
.cclass-modelo {
    background: var(--preenchimento);
    border-radius: var(--radius);
    padding: var(--space-3);
    margin-bottom: var(--space-2);
}

.cclass-modelo-topo {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-2);
}

.cclass-modelo-campos {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 170px auto;
    gap: var(--space-2);
    align-items: end;
}
.cclass-modelo-acoes { display: flex; gap: var(--space-1); }
/* Alinha com os campos, que têm rótulo por cima. */
.cclass-modelo-acoes .icon-btn { width: 40px; }

@media (max-width: 900px) {
    .cclass-modelo-campos { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
    .cclass-modelo-acoes { grid-column: 1 / -1; justify-content: flex-end; }
}

.cclass-prod-info { flex: 1; }

.cclass-modelo-num {
    font-weight: 600;
    color: var(--link);
}

/* Regime só aparece depois de detectado: vazio, o "Regime: --" antigo ocupava
   o canto do cartão para não dizer nada. */
.cclass-modelo-regime {
    margin-left: auto;
    font-size: var(--fs-xs);
    color: var(--body);
}
.cclass-modelo-regime:empty { display: none; }
.cclass-regime-cnpj { margin-left: var(--space-2); color: var(--mute); }

.cclass-barra-acoes {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
    margin-top: var(--space-3);
}
/* Adicionar modelo fica à esquerda (edita a lista acima); pré-visualizar e
   confirmar fecham o fluxo, à direita. */
.cclass-barra-fim { display: flex; gap: var(--space-2); margin-left: auto; }

#cclass-sinc-result:not(:empty) { margin-top: var(--space-3); }

.cclass-ncms-topo {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-bottom: var(--space-2);
}
.cclass-busca { width: 100%; margin-bottom: var(--space-3); }

.cclass-resumo-modelo {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
    padding: var(--space-2) var(--space-3);
    margin-bottom: var(--space-2);
    border: 0;
    border-radius: var(--radius);
    font-size: var(--fs-xs);
    color: var(--body);
}
.cclass-resumo-modelo strong { color: var(--ink); }

.cclass-preview { max-height: 340px; }
.cclass-ncms-tabela { max-height: 420px; }
.cclass-ncms-tabela tbody tr { cursor: pointer; }
.cclass-ncms-tabela tbody tr:focus-visible { outline: 2px solid var(--link); outline-offset: -2px; }
.cclass-col-trib { color: var(--body); }

.cclass-paginacao {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-left: auto;      /* a contagem fica à esquerda, as setas à direita */
}
.cclass-paginacao span { font-size: var(--fs-xs); color: var(--body); font-variant-numeric: tabular-nums; }

/* =====================================================================
   Refinamentos de componentes — DESIGN.md (ver DESIGN.md)
   Usa os tokens canônicos definidos no topo do arquivo (## Overview).
   ===================================================================== */


/* ─────────── Barra de menus (DESIGN.md ## Layout) ─────────── */
/* Duas linhas em vez de uma: a marca e o estado do sistema ficam na topbar, a
   navegação inteira mora aqui embaixo. Os destinos deixaram de ser 3 botões e
   um menu escondido em clique-direito — cabem numa barra só porque o painel
   os agrupa por assunto em vez de empilhar tudo lado a lado. */
.menubar-wrap {
    position: relative;
    z-index: var(--z-dropdown);
    flex-shrink: 0;
}

.menubar {
    display: flex;
    align-items: stretch;
    gap: 2px;
    height: 36px;
    padding: 0 var(--space-5);
    background: var(--surface-card);
    /* Primeira das duas divisórias do sistema (exceção na decisão 3, no
       topo): separa a navegação da faixa de abas de trabalho, que tem o
       mesmo fundo. */
    border-bottom: 1px solid var(--hairline);
    overflow-x: auto;
    scrollbar-width: none;
}
.menubar::-webkit-scrollbar { display: none; }

.menubar-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0 var(--space-3);
    border: 0;
    background: transparent;
    color: var(--body);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
    transition: color var(--dur-fast) var(--ease-std),
                background var(--dur-fast) var(--ease-std);
}

.menubar-item:hover { background: var(--surface-hover); color: var(--ink); }

/* Item só de ícone (o Painel de Controle). Quadrado em vez de retangular: sem
   texto ao lado, o padding lateral de 12px deixava o ícone deslocado dentro de
   uma área larga demais para o que ele é. O nome vive no title/aria-label. */
.menubar-item-icone {
    padding: 0;
    width: 36px;
    justify-content: center;
    gap: 0;
}

/* O icon() crava width/height 18 no SVG; numa barra de 36px isso pesa. */
.menubar-item .icon { width: 17px; height: 17px; }

.menubar-item:focus-visible,
.menu-link:focus-visible { outline: 2px solid var(--link); outline-offset: -2px; }

/* Só existe o estado "aberto" (o painel deste menu está à vista). Marcar tela
   ativa aqui competia com a barra de abas, que já diz onde o usuário está. */
.menubar-item.aberto { background: var(--surface-hover); color: var(--ink); }

/* Seletor com o pai para empatar a especificidade de `.menubar-item .icon`
   acima — a seta também é `.icon`, e sem isso herdaria os 15px dele. */
.menubar-item .menubar-seta { width: 14px; height: 14px; opacity: 0.6; }
.menubar-item.aberto .menubar-seta { transform: rotate(180deg); }

/* Painel: largura total, ancorado sob a barra. Sobrepõe o conteúdo em vez de
   empurrá-lo — empurrar faria a página inteira pular a cada abrir/fechar.
   Mesmo fundo da topbar e da menubar: o painel é a continuação da barra. */
.menu-panel {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: var(--surface-card);
    border-bottom: 0;
}
.menu-panel.aberto { display: block; }

/* Grid, não flex: os quadrados repartem a largura inteira em partes IGUAIS.
   Quando não cabem numa linha, a de baixo mantém a mesma largura em vez de
   esticar o que sobrou. */
.menu-panel-cols {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--space-3);
    padding: var(--space-4) var(--space-5) var(--space-5);
}

/* Cada grupo é um quadrado só de fundo: sem borda e sem divisor sob o título.
   O cinza é o mesmo do .menubar-item aberto — o painel continua o tom do item
   que o abriu. */
.menu-col {
    padding: var(--space-2);
    background: var(--surface-hover);
    border-radius: var(--radius-lg);
}

/* 10px de lado = o padding do .menu-link: o título alinha com os ícones. */
.menu-col h4 {
    margin: 0;
    padding: var(--space-2) 10px;
    color: var(--mute);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.menu-link {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    width: 100%;
    padding: 6px 10px;
    border: 0;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--ink);
    font-family: inherit;
    font-size: var(--fs-sm);
    text-align: left;
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-std);
}

.menu-link:hover { background: var(--surface-hover); color: var(--link); }
/* No quadrado o fundo JÁ é --surface-hover: o hover de sempre sumiria. Sobe
   para o canvas — e o azul do texto ganha contraste em vez de perder. */
.menu-col .menu-link:hover { background: var(--canvas); }
.menu-link .icon { color: var(--mute); flex-shrink: 0; }
.menu-link:hover .icon { color: var(--link); }

/* O ícone num quadradinho próprio. */
.menu-link-icone {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    flex-shrink: 0;
    border: 0;
    border-radius: var(--radius-md);
    background: var(--canvas);
    transition: border-color var(--dur-fast) var(--ease-std);
}
.menu-link-icone .icon { width: 17px; height: 17px; }
.menu-link-icone .icone-sis { width: 16px; height: 16px; }
/* No hover a linha vira canvas: o quadradinho troca para o cinza do quadrado,
   senão some junto (sem borda, é só o fundo que o desenha). */
.menu-col .menu-link:hover .menu-link-icone { background: var(--surface-hover); }

/* Empurra as ações para a direita: a barra da marca só tem marca e ações. */
.header-actions {
    margin-left: auto;
}

/* ─────────── Header actions ─────────── */
.icon-btn {
    flex-shrink: 0;
}


/* Tema: os dois estados lado a lado, o ativo destacado — diz ONDE se está,
   não só para onde ia trocar (o botão único de antes mostrava o ícone do
   PRÓXIMO tema, e isso lia ao contrário na primeira olhada). */

/* Avatar: iniciais sobre a cor de ação — mesmo par usado no CTA (--primary/
   --primary-on), já provado acessível nos dois temas, em vez de inventar
   uma cor por usuário. */
.user-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border: 0;
    border-radius: var(--radius-full);
    background: var(--primary);
    color: var(--primary-on);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.02em;
    cursor: pointer;
    flex-shrink: 0;
}

/* A conta no topo: avatar + nome de exibição + seta, um botão só. Sem fundo em
   repouso (é identidade, não ação); o fundo aparece no hover e com o menu aberto. */
.user-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    max-width: 240px;
    padding: 3px var(--space-2) 3px 3px;
    border: 0;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--ink);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: 500;
    cursor: pointer;
}
.user-chip:hover, .user-chip[aria-expanded="true"] { background: var(--preenchimento); }
.user-chip:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; }
.user-chip-nome { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-chip-nome:empty { display: none; }
.user-chip-seta { color: var(--mute); }
.user-chip[aria-expanded="true"] .user-chip-seta { transform: rotate(180deg); }
@media (max-width: 760px) {
    .user-chip-nome, .user-chip-seta { display: none; }
    .user-chip { padding: 3px; }
}

/* Tema dentro do menu do usuário: rótulo à esquerda, o controle segmentado
   de sempre (.theme-switch) à direita. */
.user-menu-tema {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: 4px 4px 4px 10px;
    font-size: var(--fs-sm);
    color: var(--ink);
}
.user-avatar-lg { width: 36px; height: 36px; font-size: 14px; cursor: default; }

/* Posição (fixed, top/right) vem de app.js, igual .top10-panel: calculada
   contra a borda do avatar, não fixa em CSS. */
.user-menu-panel {
    width: 240px;
    padding: var(--space-2);
    background: var(--surface-flutuante);
    box-shadow: var(--sombra-flutuante);
    border-radius: var(--radius-lg);
    z-index: var(--z-dropdown);
}
.user-menu-header {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2);
}
.user-menu-quem {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
}
.user-menu-quem strong {
    font-size: var(--fs-sm);
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.user-menu-quem span { font-size: var(--fs-xs); color: var(--mute); }
.user-menu-sep { height: 1px; background: var(--hairline); margin: var(--space-2) 0; }

/* Sair é destrutivo o bastante (encerra a sessão) para o hover de perigo do
   resto do app — mesmo par --fundo-erro/--accent-red do .btn-danger. */
.menu-link-perigo:hover { background: var(--fundo-erro); color: var(--accent-red); }
.menu-link-perigo:hover .icon { color: var(--accent-red); }

/* Sino: botão de ícone discreto com contador flutuante. O pill vermelho
   grande competia com a marca lime e gritava mesmo sem nada urgente. */
.bell-btn {
    position: relative;
    flex-shrink: 0;
}


.bell-btn .count {
    position: absolute;
    top: -6px;
    right: -6px;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: var(--radius-full);
    background: var(--accent-red);
    color: var(--primary-on);
    font-size: 10px;
    font-weight: 700;
    line-height: 18px;
    text-align: center;
    /* O recorte do badge vem do anel de 2px na cor do canvas, que ja existe
       acima. A sombra colorida que havia aqui era elevacao, e o DESIGN.md nao
       tem elevacao por sombra. */
    border: 0;
}

/* Sem pendência não há badge para mostrar */
.bell-btn.zerado .count { display: none; }

.status-label {
    font-size: var(--fs-xs);
    padding: 5px 12px;
    border-radius: var(--radius-sm);
    font-weight: 600;
    letter-spacing: 0.02em;
    border: 0;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}

/* Ponto de status antes do texto */
.status-label::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    flex-shrink: 0;
}

.status-label:empty { display: none; }
.status-label.idle { background: color-mix(in srgb, var(--ink) 6%, transparent); color: var(--mute); }
.status-label.done { background: var(--fundo-ok); color: var(--accent-green); }
.status-label.scanning {
    background: var(--fundo-info);
    color: var(--link);
    animation: pulse 1.5s infinite;
}
.status-label.error { background: var(--fundo-erro); color: var(--accent-red); }

/* Separador entre a navegação e as ações */
.server-item {
    border-radius: var(--radius);
    border: 0;
    background: var(--surface-card);
}

.server-item:hover {
    transform: none;
}

.db-item {
    border-radius: var(--radius);
}

.db-item.active {
    background: var(--fundo-info);
    border-left: 0;
    box-shadow: none;
}

/* ─────────── Main ─────────── */
.main-content {
    background: var(--canvas);
}

/* Esta faixa virou a barra de abas: antes gastava 52px para escrever uma
   palavra ("PAINEL"). As abas ficam à esquerda; o breadcrumb, que só interessa
   quando se desce dentro de uma aba, recuou para a direita em tom secundário. */
.main-header {
    background: var(--surface-card);
    border-bottom: 0;
    min-height: 42px;
    padding: 0 26px;
    gap: var(--space-4);
    display: flex;
    align-items: center;
    justify-content: space-between;
    position: relative;
}

.main-header .breadcrumb {
    font-size: 12px;
    color: var(--mute);
    white-space: nowrap;
    font-weight: 600;
    letter-spacing: 0.02em;
}
/* Separador do breadcrumb. Era `style="color:var(--mute)"` repetido em
   onze pontos — e o breadcrumb inteiro já é dessa cor. */
.bc-sep { opacity: 0.6; }

/* ─────────── Abas de tela (DESIGN.md ## Layout) ─────────── */
/* Pastilhas, não abas recortadas: o recorte só se paga quando as abas grudam
   numa borda, e aqui elas dividem a linha com o breadcrumb. */
.tabbar {
    display: flex;
    align-items: center;
    gap: 4px;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
}
.tabbar::-webkit-scrollbar { display: none; }

.tab-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 8px 5px 10px;
    /* Aba inativa também é pastilha. O preenchimento aparece sobre a barra; o
       --surface-elevated de antes ficava a um passo dela e a aba sumia. */
    background: var(--preenchimento);
    border-radius: var(--radius-sm);
    color: var(--body);
    font-size: var(--fs-sm);
    white-space: nowrap;
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-std),
                color var(--dur-fast) var(--ease-std);
}

.tab-item:hover { background: var(--preenchimento-hover); color: var(--ink); }

/* Ativa: o azul cheio da ação, mesmo par da aba ativa de Clientes/Contadores
   (.central-tab.active). O --fundo-info de antes era o MESMO tom da inativa no
   tema claro — só a cor do texto dizia qual era a aba aberta. */
.tab-item.ativa {
    background: var(--primary);
    color: var(--primary-on);
}
.tab-item.ativa:hover { background: var(--primary-hover); }

/* Marca do ERP (web.ico / desktop.ico / mrp.ico) no lugar do ícone de traço.
   Acompanha o tamanho do ícone vizinho em cada contexto. */
.icone-sis {
    width: 18px;
    height: 18px;
    border-radius: var(--radius);
    object-fit: contain;
    flex-shrink: 0;
}
.menubar-item .icone-sis { width: 15px; height: 15px; }
.tab-item .icone-sis { width: 14px; height: 14px; }
.tab-item .tab-foto { width: 16px; height: 16px; border-radius: var(--radius-sm); object-fit: cover; flex-shrink: 0; }
span.icon-fallback.icone-sis { font-size: 10px; border-radius: var(--radius); }
.tab-item span.icon-fallback.icone-sis { font-size: 9px; }

.tab-item .icon { width: 16px; height: 16px; color: var(--body); }
.tab-item.ativa .icon { color: inherit; }

.tab-fechar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: inherit;
    opacity: 0.65;
    cursor: pointer;
}
/* Com o pai no seletor para empatar `.tab-item.ativa .icon`, senão o × herdaria
   o lime do ícone da aba ativa. */
.tab-item .tab-fechar .icon { width: 14px; height: 14px; color: inherit; }
.tab-fechar:hover { opacity: 1; background: var(--preenchimento-hover); color: var(--accent-red); }
/* No azul da aba ativa o vermelho some: o × fica na cor do texto da aba. */
.tab-item.ativa .tab-fechar:hover { background: color-mix(in srgb, var(--primary-on) 22%, transparent); color: var(--primary-on); }
.tab-fechar:focus-visible { outline: 2px solid var(--link); outline-offset: -2px; }

/* ─────────── Telas de formulário/config (ex-modais) ─────────── */
/* Configuração, listagem, escolha: coisas que o usuário quer deixar abertas
   numa aba. Como modal, obrigavam a fechar antes de olhar qualquer outra
   coisa. Largura limitada porque formulário esticado em 1900px não se lê. */
.tela-form {
    max-width: 760px;
    padding: var(--space-6);
}

/* Ferramenta, não formulário: tabela e grade de números não sofrem do problema
   que o teto de 760px resolve (campo esticado não se lê). */
.tela-form.tela-larga { max-width: 1180px; }

.tela-form > h2 {
    margin: 0 0 var(--space-2);
    font-size: var(--fs-md);
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.tela-form > p.subtitle {
    margin: 0 0 var(--space-5);
    font-size: 13px;
    color: var(--body);
}

/* `.modal-actions` só tem layout dentro de `.modal`; aqui a linha de botões
   precisa do próprio. */
.tela-form .modal-actions {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: 0;
}

/* ─────────── Tela de pendências do banco — leitura corporativa ─────────── */
/* Era uma pilha de cards com barra colorida, hover que levanta e um card
   solitário de 300px anunciando "nada pendente" num vão de 1600px. Agora:
   cabeçalho que diz de quem são os números, seções com régua, e uma grade
   densa de indicadores alinhados. Nada se mexe ao passar o mouse. */
.tela-topo {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-6);
    padding-bottom: var(--space-4);
    border-bottom: 0;
}

.tela-topo-esq { display: flex; align-items: center; gap: var(--space-4); min-width: 0; }
.tela-topo-esq .back-btn { margin-bottom: 0; flex-shrink: 0; }
.tela-topo-dir { display: flex; align-items: center; gap: var(--space-2); flex-shrink: 0; }

.tela-topo-id { min-width: 0; }

.tela-topo-id h2 {
    margin: 0;
    font-size: var(--fs-h2);
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tela-topo-id p {
    margin: 2px 0 0;
    font-size: var(--fs-sm);
    color: var(--body);
}
/* --mute e não --hairline: na cor de linha fina o "·" sumia no tema escuro e
   "SEDFILIAL  NEXT 01" lia como um nome só. */
.tela-topo-id p span { color: var(--mute); margin: 0 2px; }
/* O logo do sistema ao lado do título (detalhe do servidor). */
.tela-topo-esq > .servidores-card-icon { width: 36px; height: 36px; }

/* Telas de detalhe (servidor, banco, certificado, vendas): o cabeçalho de
   tela, e embaixo os cards de número do Painel ao lado de um painel de dados —
   a mesma grade no servidor e nas vendas. Os tamanhos dos cards vêm da escala
   do Painel (.dash / .tela-detalhe, no bloco "Home — escala desktop-first"). */
.detalhe-corpo {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr)) minmax(0, 2fr);
    gap: var(--space-3);
}
.detalhe-aviso { margin-bottom: var(--space-3); }
.tela-detalhe .panel-card { margin-bottom: 0; }

/* Rótulo → valor (Instalação do servidor). */
.dados {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: var(--space-2) var(--space-5);
    margin: 0;
    font-size: var(--fs-sm);
}
.dados dt { color: var(--body); }
.dados dd { margin: 0; color: var(--ink); overflow-wrap: anywhere; }
.dados .vazio, .dados-sep { color: var(--mute); }

/* Seção de filial: régua em cima, sem moldura de card. Card dentro de card era
   o que dava o aspecto de painel de brinquedo. */
.pend-secao { margin-bottom: var(--space-8); }
.pend-secao:last-child { margin-bottom: 0; }

.pend-filial { display: flex; align-items: center; gap: var(--space-3); min-width: 0; }

/* O nome da filial no título de seção do Painel (.panel-card h3): é rótulo do
   que vem embaixo, não um segundo título de tela competindo com o h2. */
.pend-filial h3 {
    margin: 0;
    font-size: var(--fs-xs);
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--body);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.pend-filial h3 .icon { color: var(--mute); vertical-align: -5px; margin-right: var(--space-1); }

.pend-filial-num {
    flex-shrink: 0;
    padding: 2px 8px;
    border-radius: var(--radius-sm);
    background: var(--surface-elevated);
    color: var(--body);
    font-size: var(--fs-xs);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

/* "Nada pendente" ocupa a linha inteira em vez de virar um card perdido na
   grade — é uma afirmação sobre a filial toda, não mais um indicador. */
.pend-ok,
.pend-erro {
    grid-column: 1 / -1;
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    padding: var(--space-3) var(--space-4);
    border: 0;
    border-radius: var(--radius);
    background: var(--fundo-ok);
}

/* Mesma caixa do "Nada pendente", cor invertida: as duas ocupam a linha
   inteira porque as duas falam da filial toda. A diferença é só o veredito —
   e ela precisa ser óbvia, senão o erro passa por "está tudo certo". */
.pend-erro {
    background: var(--fundo-erro);
}

.pend-erro-marca {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--accent-red);
}
.pend-erro-marca .icon { width: 18px; height: 18px; }

.pend-ok-marca {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--accent-green);
}
.pend-ok-marca .icon { width: 18px; height: 18px; }
.pend-ok-lista { font-size: var(--fs-xs); color: var(--body); }

/* QR do WhatsApp: preto sobre branco nos DOIS temas. Não é decoração — o
   leitor do celular precisa do contraste máximo, e um QR invertido não lê. */
.qr-caixa {
    display: inline-block;
    padding: var(--space-2);
    border: 0;
    border-radius: var(--radius);
    background: var(--qr-papel);
}

.qr-ascii {
    margin: 0;
    padding: var(--space-2);
    max-width: 300px;
    overflow: hidden;
    font-family: var(--font-mono);
    font-size: 10px;
    line-height: 1;
    color: var(--qr-tinta);
    background: var(--qr-papel);
    border-radius: var(--radius);
}

/* ─────────── Cards (panel) ─────────── */
.panel-card {
    background: var(--surface-card);
    border: 0;
    border-radius: var(--radius);
    padding: 20px;
}

.panel-card h3 {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--fs-sm);
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--body);
    text-transform: uppercase;
    margin-bottom: var(--space-4);
}
.panel-card h3 .icon { color: var(--mute); }

.tela-topo-id h2 .icon { color: var(--link); vertical-align: -3px; margin-right: 4px; }


/* ─────────── Modais (regra base única na seção Modais acima) ─────────── */

/* Cabeçalho: marca + título/subtítulo + fechar — a anatomia do .dlg-cabeca
   das fichas. O normalizador (app.js) monta isto em todo modal de conteúdo,
   inclusive a marca, que é o ícone do título tirado de dentro do <h2>. */
.modal-header {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}
.modal-header > div { flex: 1; min-width: 0; }
/* No topo do modal: sangra até as bordas e gruda quando o corpo rola. */
.modal > .modal-header {
    position: sticky;
    top: calc(-1 * var(--space-5));
    z-index: 2;
    margin: calc(-1 * var(--space-5)) calc(-1 * var(--space-5)) var(--space-4);
    padding: var(--space-5) var(--space-5) var(--space-3);
    background: var(--surface-flutuante);
}

.modal-header h2 { margin: 0; }
.modal-header .modal-sub {
    margin: 2px 0 0;
    font-size: var(--fs-sm);
    color: var(--mute);
    font-weight: 400;
}

.modal-close {
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    align-self: flex-start;
    border-radius: var(--radius-md);
    border: 0;
    background: transparent;
    color: var(--mute);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: inherit;
}
/* Fechar não é destrutivo: hover neutro, como o .dlg-fechar da ficha. */
.modal-close:hover {
    background: var(--preenchimento-hover);
    color: var(--ink);
}

.modal h2 {
    font-size: var(--fs-h2);
    font-weight: 600;
    line-height: 1.25;
    color: var(--ink);
    letter-spacing: 0;
}

/* Diálogo genérico: conteúdo é HTML livre do chamador, então o X flutua
   no canto em vez de viver num .modal-header estruturado. */
.central-dialogo { position: relative; }
.modal-close.central-dlg-x {
    position: absolute;
    top: var(--space-3);
    right: var(--space-3);
    z-index: 1;
}


/* Mesmo campo do .dlg (a ficha): fundo da própria camada, borda de campo e
   anel azul no foco — os outros modais e telas de formulário ficam iguais. */


/* O fundo de repouso: a animacao acima vence isto no uso normal, e este
   valor e o que aparece com prefers-reduced-motion. */
.central-row.central-atencao { background: var(--fundo-ok); }

/* Observação: amarelo LEVE. A linha de atenção acima usa o tom cheio e ainda
   pulsa; esta fica a ~40% dele, o suficiente para a linha se destacar na
   varredura da tabela sem competir com quem tem ponto de atenção de verdade.
   As duas classes nunca convivem — o JS só aplica esta quando não há atenção. */
.central-row.central-row-obs {
    background: color-mix(in srgb, var(--fundo-linha-aviso) 40%, var(--surface-card));
}
.central-row.central-row-obs:hover { background: var(--fundo-linha-aviso); }

.central-row-inativo { opacity: 0.55; }

/* Sem pendência mas vinculado: atalho para Consultar Vendas. */
.central-pend-vendas {
    min-width: 26px;
    height: var(--selo-h);
    vertical-align: middle;
    border-radius: var(--radius-sm);
    border: 0;
    background: var(--preenchimento);
    color: var(--mute);
    font: inherit;
    font-size: var(--fs-xs);
    font-weight: 700;
    cursor: pointer;
}
.central-pend-vendas:hover {
    color: var(--link);
    background: var(--fundo-info);
}

/* ─────────── Badge de pendências (grid de clientes) ─────────── */
.central-pend-badge {
    min-width: 26px;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
    transition: filter var(--dur-fast) var(--ease-std);
}

.central-pend-badge.danger { background: var(--fundo-erro); color: var(--accent-red); }
.central-pend-badge.warning { background: var(--fundo-aviso); color: var(--accent-orange); }
.central-pend-badge.ok { background: var(--fundo-ok); color: var(--accent-green); }

.central-pend-badge:hover { filter: brightness(0.94); }

/* =====================================================================
   HOME / DASHBOARD v2 — DESIGN.md
   ===================================================================== */
.dash { display: flex; flex-direction: column; }

/* ─── Hero ─── */
/* Saudação + o envio do mês. Era o número de pendências em 38px, chips e um
   medidor de meia-lua que dividia só por quem já tinha status no mês (no
   começo do mês dizia "sem dados"). O total foi para os KPIs; aqui fica o
   que o escritório persegue no mês: quantos clientes já receberam o XML. */
.hero {
    position: relative;
    border-radius: var(--radius);
    border: 0;
    background: var(--surface-card);
}

.hero-content {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    padding: var(--space-5) var(--space-6);
}

.hero-topo { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; }
.hero-greet { display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; min-width: 0; }
.hero-hello { font-size: var(--fs-md); font-weight: 600; color: var(--ink); }
.hero-date { font-size: var(--fs-sm); color: var(--body); }
/* Quando o número foi lido: a varredura automática é de 3 em 3h. */
.hero-varredura { display: inline-flex; align-items: center; gap: 4px; font-size: var(--fs-xs); color: var(--mute); }
.hero-varredura .icon { width: 14px; height: 14px; }
.hero-actions { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
/* O filtro de mês do Envio de XML, na fila dos botões; o display:flex do
   .export-competencia venceria o [hidden] na aba Pendências. */
.dash-mes { margin-right: var(--space-2); }
.dash-mes[hidden] { display: none; }

/* Envio do mês: barra segmentada, na ordem Enviado / No Drive / Não emitiu, e
   o resto do trilho vazio é o Pendente — progresso lê como "falta encher". */
.fech { display: flex; flex-direction: column; gap: var(--space-2); }
.fech-topo { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap; }
.fech-titulo { font-size: var(--fs-xs); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--body); }
.fech-resumo { font-size: var(--fs-sm); color: var(--body); }
.fech-resumo strong { font-size: var(--fs-lg); font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.fech-barra {
    display: flex;
    height: 12px;
    border-radius: var(--radius-full);
    overflow: hidden;
    background: color-mix(in srgb, var(--ink) 9%, transparent);
}
/* Clica só no mês atual (a grid de Clientes lê só ele): nos outros não há onclick. */
.fech-seg { height: 100%; transition: filter var(--dur-fast) var(--ease-std); }
.fech-seg[onclick] { cursor: pointer; }
.fech-seg[onclick]:hover { filter: brightness(1.12); }
.fech-seg.enviado, .fech-dot.enviado { background: var(--accent-green); }
.fech-seg.no_drive, .fech-dot.no_drive { background: var(--accent-blue); }
.fech-seg.nao_emitiu, .fech-dot.nao_emitiu { background: var(--mute); }
.fech-dot.pendente { background: color-mix(in srgb, var(--ink) 18%, transparent); }
.fech-legenda { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-2); margin-left: calc(-1 * var(--space-2)); }
.fech-leg {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px var(--space-2);
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    font: inherit;
    font-size: var(--fs-xs);
    color: var(--body);
    cursor: pointer;
}
span.fech-leg { cursor: default; }
button.fech-leg:hover:not(:disabled) { background: var(--preenchimento); color: var(--ink); }
.fech-leg:focus-visible { outline: 2px solid var(--link); outline-offset: 1px; }
.fech-leg:disabled { cursor: default; opacity: .55; }
.fech-leg strong { color: var(--ink); font-variant-numeric: tabular-nums; }
.fech-dot { width: 8px; height: 8px; border-radius: var(--radius-full); flex-shrink: 0; }
.fech-esq { height: 12px; }
.fech-vazio { margin: 0; font-size: var(--fs-sm); color: var(--mute); }

/* ─── Precisa de atenção ───
   Só o que tem contagem: cada linha é uma fila de trabalho com o destino de
   um clique. Nada para mostrar vira "Nada pendente para hoje", não um vazio. */
.area-atencao { grid-area: atencao; }
.atencao-lista { display: flex; flex-direction: column; gap: 2px; }
.atencao-item {
    display: grid;
    grid-template-columns: 28px 1fr auto;
    align-items: center;
    gap: var(--space-3);
    width: 100%;
    padding: var(--space-2);
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    font: inherit;
    text-align: left;
    color: var(--mute);
    cursor: pointer;
}
.atencao-item:hover { background: var(--surface-hover); color: var(--ink); }
.atencao-item:focus-visible { outline: 2px solid var(--link); outline-offset: -2px; }
.atencao-item > .icon { width: 18px; height: 18px; }
.atencao-txt { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.atencao-txt strong { font-size: var(--fs-sm); font-weight: 600; color: var(--ink); }
.atencao-txt span { font-size: var(--fs-xs); color: var(--mute); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.atencao-lista .atencao-esq { height: 40px; margin: 2px 0; }
.atencao-vazio { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-2); }
.atencao-vazio > .icon { width: 30px; height: 30px; flex-shrink: 0; color: var(--accent-green); }
.atencao-vazio div { display: flex; flex-direction: column; gap: 2px; }
.atencao-vazio strong { font-size: var(--fs-sm); color: var(--ink); }
.atencao-vazio span { font-size: var(--fs-xs); color: var(--mute); }
.atencao-barra { background: var(--surface-hover); border-radius: var(--radius); padding: var(--space-3); margin-top: var(--space-2); }
.atencao-barra:empty { display: none; }
.atencao-resumo { font-size: var(--fs-sm); color: var(--mute); margin-bottom: var(--space-2); }
.atencao-resumo-num { font-weight: 600; color: var(--ink); font-size: var(--fs-base); }

/* Esqueletos do Painel (os gráficos e a atividade nasciam em branco). O
   canvas fica escondido até o esqueleto sair — senão os dois somavam altura. */
.dash .dash-esq { height: 200px; }
.dash-esq + .chart-wrap { display: none; }
.kpi-row > .dash-empty { grid-column: 1 / -1; }
/* Painel: saudação maior e cifras em peso 500 — número grande não precisa de
   negrito para mandar na tela. */
.dash .hero-hello { font-size: var(--fs-lg); font-weight: 500; letter-spacing: -0.01em; }
/* "Processamento", com o ponto de cor ao lado, não cabe numa coluna de 96px. */
.dash .tipo-linha { grid-template-columns: 124px 1fr 72px 46px 16px; }
.dash .kpi-val, .tela-detalhe .kpi-val, .dash .fech-resumo strong, .dash .tipos-total strong {
    font-weight: 500;
    font-variant-numeric: lining-nums tabular-nums;
}
.dash-esq-linhas { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-2) 0; }


/* ─── KPIs ─── */
.kpi-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--space-4);
}

.kpi-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-5);
    /* Altura do card ja carregado (icone+label 20 + valor 34 + sub 16 + 2 gaps).
       Sem isto o card de loading nasce so com o spinner e a Home inteira salta
       quando os dados chegam. */
    min-height: 118px;
    justify-content: center;
    background: var(--surface-card);
    border: 0;
    border-radius: var(--radius);
    position: relative;
    overflow: hidden;
    transition: background var(--dur-fast) var(--ease-std);
}
/* Só o card que abre alguma coisa responde ao mouse: o hover em card parado
   prometia um clique que não existia. */
.kpi-card.acionavel { width: 100%; font: inherit; color: inherit; text-align: left; cursor: pointer; }
.kpi-card.acionavel:hover { background: var(--surface-hover); }
.kpi-card.acionavel:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; }
.kpi-ir { margin-left: auto; display: inline-flex; color: var(--mute); transition: color var(--dur-fast) var(--ease-std); }
.kpi-ir .icon { width: 18px; height: 18px; }
.kpi-card.acionavel:hover .kpi-ir { color: var(--link); }

/* Estado crítico: brilho difuso no canto + valor em vermelho. Comunica o
   alerta pelo corpo inteiro do card, sem barra lateral nem borda tingida. */
.kpi-destaque {
    background: var(--surface-card);
}
.kpi-destaque .kpi-val { color: var(--accent-red); }

.kpi-head { display: flex; align-items: center; gap: var(--space-2); }
.kpi-ico {
    width: 32px; height: 32px;
    border-radius: var(--radius-md);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.kpi-ico.red { background: var(--fundo-erro); color: var(--accent-red); }
.kpi-ico.blue { background: var(--fundo-info); color: var(--accent-blue); }
.kpi-ico.green { background: var(--fundo-ok); color: var(--accent-green); }
.kpi-ico.orange { background: var(--fundo-aviso); color: var(--accent-orange); }
.kpi-ico.yellow { background: var(--fundo-aviso); color: var(--accent-yellow); }
.kpi-ico.purple { background: color-mix(in srgb, var(--serie-7) 14%, transparent); color: var(--serie-7); }
/* Sem dado para afirmar nada ("Não verificado"): nem verde nem alerta. */
.kpi-ico.cinza { background: var(--preenchimento); color: var(--mute); }
.kpi-label { font-size: var(--fs-sm); color: var(--body); font-weight: 500; }

.kpi-body { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--space-3); }
.kpi-val { font-size: var(--fs-lg); font-weight: 600; font-variant-numeric: tabular-nums; color: var(--ink); line-height: 1; letter-spacing: -0.02em; }
.spark { flex-shrink: 0; opacity: 0.9; }

.kpi-foot { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; min-height: 18px; }
.kpi-delta { font-size: var(--fs-xs); font-weight: 700; }
.kpi-delta.up { color: var(--accent-green); }
.kpi-delta.down { color: var(--accent-red); }
.kpi-delta.flat { color: var(--mute); }
.kpi-sub { font-size: var(--fs-xs); color: var(--mute); }

/* Pé do KPI (Painel): a composição do número — uma barra de proporção com
   legenda, ou a tendência dos últimos meses. Fica colado embaixo: o card
   estica até a altura de "Precisa de atenção" e o vão fica entre o número e o
   pé, não em cima e embaixo do conteúdo. */
.kpi-rodape { margin-top: auto; display: flex; flex-direction: column; gap: 6px; padding-top: var(--space-2); }
.kpi-barra {
    display: flex;
    gap: 2px;
    height: 8px;
    border-radius: var(--radius-full);
    overflow: hidden;
    background: color-mix(in srgb, var(--ink) 9%, transparent);
}
/* 3px no mínimo: 1.147 fiscais contra 257.878 de cadastro é 0,4% — sem piso,
   a fatia que mais importa sumia. */
.kpi-barra .kpi-seg { height: 100%; min-width: 3px; }
.kpi-leg { display: flex; flex-wrap: wrap; gap: 2px var(--space-3); font-size: var(--fs-xs); color: var(--mute); font-variant-numeric: tabular-nums; }
.kpi-leg span { display: inline-flex; align-items: center; gap: 5px; }
.kpi-dot { width: 8px; height: 8px; border-radius: var(--radius-full); flex-shrink: 0; }
.kpi-seg.critico, .kpi-dot.critico { background: var(--accent-red); }
.kpi-seg.fiscal, .kpi-dot.fiscal { background: var(--accent-orange); }
.kpi-seg.cadastro, .kpi-dot.cadastro { background: color-mix(in srgb, var(--ink) 28%, transparent); }
.kpi-rodape .spark { width: 100%; height: 34px; }
.kpi-eixo { display: flex; justify-content: space-between; font-size: var(--fs-xs); color: var(--mute); }

/* ─── Donut ─── */

/* Donut à esquerda, legenda à direita: centralizado com a legenda embaixo
   sobrava vazio nas laterais e o painel ficava alto à toa. */
/* justify-content: center + legenda com largura limitada: antes ela esticava
   por todo o painel e abria um vao enorme entre o nome e o numero. */

.lg-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }

/* ─── Distribuição por tipo: lista com barras ───
   Substituiu o donut. Com um tipo concentrando 97%, as fatias dos demais
   ficavam menores que um pixel (0,1% = 0,36 grau) — invisíveis e impossíveis
   de passar o mouse. Em lista, toda categoria aparece e é legível. */
.tipos-total {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
}
.tipos-total strong {
    font-size: var(--fs-xl);
    font-weight: 600;
    color: var(--ink);
    letter-spacing: -0.02em;
}
.tipos-total span { font-size: var(--fs-xs); color: var(--body); }

.tipos-lista { display: flex; flex-direction: column; gap: var(--space-2); }

.tipo-linha {
    display: grid;
    grid-template-columns: 96px 1fr 72px 46px 16px;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--fs-sm);
}

.tipo-nome {
    display: flex;
    align-items: center;
    gap: 6px;
    color: var(--body);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tipo-barra {
    height: 8px;
    border-radius: var(--radius-full);
    background: color-mix(in srgb, var(--ink) 8%, transparent);
    overflow: hidden;
}
.tipo-preenchida {
    display: block;
    height: 100%;
    border-radius: var(--radius-full);
    min-width: 3px;
    /* scaleX em vez de width: a largura final vem de style inline calculado no
       JS, e o keyframe nao a conhece. transform-origin prende o pe na esquerda. */
    transform-origin: left center;
    animation: tipoCrescer var(--dur-slow) var(--ease-std) backwards;
}
@keyframes tipoCrescer { from { transform: scaleX(0); } }

/* Escalonamento por posicao: sao no maximo 8 tipos, entao 8 regras custam
   menos que passar um --i inline por linha no JS. */
.tipo-linha:nth-child(1) .tipo-preenchida { animation-delay: 0ms; }
.tipo-linha:nth-child(2) .tipo-preenchida { animation-delay: 45ms; }
.tipo-linha:nth-child(3) .tipo-preenchida { animation-delay: 90ms; }
.tipo-linha:nth-child(4) .tipo-preenchida { animation-delay: 135ms; }
.tipo-linha:nth-child(5) .tipo-preenchida { animation-delay: 180ms; }
.tipo-linha:nth-child(6) .tipo-preenchida { animation-delay: 225ms; }
.tipo-linha:nth-child(7) .tipo-preenchida { animation-delay: 270ms; }
.tipo-linha:nth-child(8) .tipo-preenchida { animation-delay: 315ms; }

@media (prefers-reduced-motion: reduce) {
    .tipo-preenchida { animation: none; }
}

/* Linha do grafico que abre o drill-down do tipo */
.tipo-linha.acionavel {
    cursor: pointer;
    border-radius: var(--radius-sm);
    padding: 2px 4px;
    margin: 0 -4px;
    transition: background var(--dur-fast) var(--ease-std);
}
.tipo-linha.acionavel:hover { background: color-mix(in srgb, var(--ink) 5%, transparent); }
.tipo-ir { display: inline-flex; color: transparent; }
.tipo-ir .icon { width: 16px; height: 16px; }
.tipo-linha.acionavel:hover .tipo-ir { color: var(--link); }

.tipo-val { font-weight: 700; color: var(--ink); text-align: right; }
.tipo-pct { color: var(--mute); text-align: right; font-size: var(--fs-xs); }

/* ─── Ranking (barras verticais em cápsula) ─── */
/* Os cards de uma mesma linha do grid esticam para a altura do mais alto.
   Os painéis da Home viram coluna flex para o gráfico ocupar a sobra em vez
   de deixar área morta embaixo. */
.dash .panel-card { display: flex; flex-direction: column; }
.dash .chart-wrap { flex: 1 1 auto; height: auto; min-height: 240px; }
.dash .chart-wrap-lg { min-height: 300px; }

/* ─── Timeline de atividade ─── */
.timeline { display: flex; flex-direction: column; }
.tl-item {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    border-bottom: 0;
}
.tl-item:last-child { border-bottom: none; }

.tl-dot {
    width: 30px; height: 30px;
    border-radius: var(--radius-md);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.tl-dot.envio { background: var(--fundo-ok); color: var(--accent-green); }
.tl-dot.export { background: var(--fundo-info); color: var(--accent-blue); }
.tl-dot.erro { background: var(--fundo-erro); color: var(--accent-red); }
.tl-dot .icon { width: 17px; height: 17px; }

.tl-body { flex: 1; min-width: 0; }
.tl-titulo {
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.tl-sub { font-size: var(--fs-xs); color: var(--mute); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tl-quando { font-size: var(--fs-xs); color: var(--mute); flex-shrink: 0; }

/* Contagem ao lado do título de um painel */
.painel-contagem {
    margin-left: auto;
    font-size: var(--fs-xs);
    font-weight: 700;
    color: var(--body);
    background: color-mix(in srgb, var(--ink) 8%, transparent);
    border-radius: var(--radius-sm);
    padding: 2px 9px;
    letter-spacing: 0;
}

/* Banco cujo servidor perdeu a VPN: nao da para exportar sem conexao, entao o
   card fica desabilitado em vez de aceitar um clique que falharia depois. */

/* ─── Seletor de escolha em cartões (escolhaSistemasHtml, app.js) ───
   "Novo servidor" (qual tipo) e "Exportar XML" (de qual sistema). Era uma
   lista de linhas com o fundo IGUAL ao do painel — só a linha com hover
   aparecia —, e o quadrado do logo tinha o tom do hover, então sumia justo na
   linha apontada. Agora: cartões em grade (duas colunas na tela, uma no
   modal), preenchimento que aparece sobre qualquer superfície e o logo num
   quadrado de canvas, o mesmo dos ícones do mega menu. Sem rodapé: em tela de
   escolha a saída é o X (ou a aba). */
.escolha-grade {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: var(--space-3);
}

.escolha {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    width: 100%;
    min-height: 72px;
    padding: var(--space-3) var(--space-4) var(--space-3) var(--space-3);
    text-align: left;
    font: inherit;
    color: var(--ink);
    background: var(--preenchimento);
    border: 0;
    border-radius: var(--radius-lg);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-std);
}
.escolha:hover { background: var(--preenchimento-hover); }
.escolha:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; }

.escolha-marca {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-lg);
    background: var(--canvas);
}
.escolha-marca img { width: 24px; height: 24px; }
.escolha-marca .icon-fallback {
    width: 26px; height: 26px; font-size: 13px; border-radius: 50%;
    align-items: center; justify-content: center; color: var(--primary-on); font-weight: 700;
}

.escolha-txt { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.escolha-txt strong { font-size: var(--fs-sm); font-weight: 600; color: var(--ink); }
.escolha-txt small { font-size: var(--fs-xs); color: var(--mute); }

/* A seta só aparece no hover: em repouso seria ruído repetido em todo cartão. */
.escolha > .icon {
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    color: transparent;
    transition: color var(--dur-fast) var(--ease-std);
}
.escolha:hover > .icon, .escolha:focus-visible > .icon { color: var(--link); }

/* Tokens por filial (modal MeuERP). Bloco secundario: separado por linha
   tracejada para nao competir com os campos de conexao acima. */
.modal-filiais-tokens {
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: 0;
}
.modal-filiais-titulo {
    font-size: var(--fs-xs);
    font-weight: 700;
    letter-spacing: .04em;
    color: var(--ink);
    margin-bottom: var(--space-1);
}
.modal-filiais-ajuda {
    font-size: var(--fs-xs);
    line-height: 1.5;
    color: var(--body);
    margin-bottom: var(--space-3);
}
.modal-filiais-id { font-weight: 400; opacity: .6; }

/* --- Alerta: notas faturadas sem XML na API do MeuERP ---
   Mesmo esqueleto do .pendencia-*, com acento vermelho: aqui o operador nao
   esta liberando uma pendencia conhecida, esta decidindo o que a contabilidade
   vai receber. Todo texto usa os tokens de tema — a primeira versao fixou uma
   cor escura e o corpo do card ficava ilegivel no tema escuro. */
/* A regra do overlay é a de `.modal-overlay`, acima — este bloco era uma cópia
   dela com `z-index: 1100`/`1200` cravados, fora da escala (## Colors) e portanto
   acima até dos toasts. Empilhamento de diálogo sobre diálogo não precisa de
   número: mesmo z-index, quem entra depois no DOM pinta por cima. */

/* Mesma anatomia do .pendencia-modal logo acima, com a marca na cor de erro. */
.xmlfalta-modal {
    background: var(--surface-flutuante);
    box-shadow: var(--sombra-flutuante);
    border-radius: var(--radius-xl);
    overflow: hidden;
    width: 640px;
    max-width: 92vw;
    max-height: 84vh;
    display: flex;
    flex-direction: column;
    animation: modalIn var(--dur-base) var(--ease-std);
}

.xmlfalta-header {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-5) var(--space-5) var(--space-3);
}
.xmlfalta-header-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-lg);
    background: var(--fundo-erro);
    color: var(--accent-red);
}
.xmlfalta-header-icon .icon { width: 22px; height: 22px; }
.xmlfalta-header h3 { margin: 0 0 2px; font-size: var(--fs-lg); font-weight: 600; line-height: 1.25; color: var(--ink); }
.xmlfalta-header p { margin: 0; font-size: var(--fs-sm); line-height: 1.5; color: var(--mute); }

.xmlfalta-body {
    padding: var(--space-4) var(--space-5);
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.xmlfalta-item {
    padding: var(--space-4);
    border: 0;
    border-radius: var(--radius-lg);
    background: var(--fundo-erro);
    transition: border-color var(--dur-base) var(--ease-std), background var(--dur-base) var(--ease-std);
}
.xmlfalta-item.decidido.incluir {
    background: var(--fundo-ok);
}
.xmlfalta-item.decidido.ignorar {
    background: var(--surface-hover);
}

.xmlfalta-item-nome {
    font-size: var(--fs-base);
    font-weight: 700;
    color: var(--ink);
    margin-bottom: var(--space-2);
}
.xmlfalta-item-texto {
    margin: 0;
    font-size: var(--fs-sm);
    line-height: 1.6;
    color: var(--ink);
}
.xmlfalta-item-texto b { color: var(--accent-red); }
.xmlfalta-item.decidido .xmlfalta-item-texto b { color: inherit; }
.xmlfalta-item-amostra {
    margin: var(--space-2) 0 0;
    font-size: var(--fs-xs);
    line-height: 1.5;
    color: var(--body);
    word-break: break-word;
}

.xmlfalta-item-acoes {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-3);
}

.xmlfalta-btn .icon { width: 17px; height: 17px; }
.xmlfalta-btn:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; }

.xmlfalta-escolha {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: var(--fs-sm);
    font-weight: 600;
}
.xmlfalta-escolha .icon { width: 17px; height: 17px; }
.xmlfalta-escolha.ok { color: var(--accent-green); }
.xmlfalta-escolha.nao { color: var(--body); }
.xmlfalta-escolha-obs {
    flex-basis: 100%;
    font-size: var(--fs-xs);
    color: var(--body);
}

/* ─── Painel de pendências críticas (sino) ───
   Antes: números crus sem separador, `min-width:36px` que não cabia 5 dígitos
   (nomes desalinhavam em zigue-zague), 950px de altura para 10 itens e tudo
   no mesmo vermelho — 27.415 e 7.009 pareciam igualmente graves. */
.top10-panel {
    display: flex;
    flex-direction: column;
    width: 400px;
    max-width: calc(100vw - 24px);
    /* max-height vem de showTop10 (até o pé da tela); o corpo é quem rola. */
    background: var(--surface-flutuante);
    box-shadow: var(--sombra-flutuante);
    border-radius: var(--radius-lg);
    z-index: var(--z-dropdown);
    overflow: hidden;
}

.sino-header {
    flex-shrink: 0;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-4) var(--space-4) var(--space-3);
    border-bottom: 0;
}
.sino-header h3 { font-size: var(--fs-md); font-weight: 700; color: var(--ink); }
.sino-sub { font-size: var(--fs-xs); color: var(--body); margin-top: 2px; }

.sino-body { max-height: 420px; overflow-y: auto; padding: var(--space-2); }
.top10-panel .sino-body { min-height: 0; }
.top10-panel .sino-footer { flex-shrink: 0; }

/* Mais críticas | Novidades: o controle segmentado de sempre. */
.sino-abas { flex-shrink: 0; margin: 0 var(--space-4) var(--space-2); }
.sino-aba-badge {
    margin-left: 6px;
    padding: 0 6px;
    border-radius: var(--radius-full);
    background: color-mix(in srgb, currentColor 16%, transparent);
    font-size: var(--fs-xs);
    font-variant-numeric: tabular-nums;
}

/* Grid fixo: a coluna do número tem largura própria, então todos os nomes
   comecam no mesmo x. Era o que o min-width nao garantia. */
.sino-item {
    display: grid;
    grid-template-columns: 1fr 72px 68px;
    align-items: center;
    gap: var(--space-3);
    width: 100%;
    padding: 9px 10px;
    border: 0;
    border-radius: var(--radius-sm);
    background: none;
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-std);
}
.sino-item:hover { background: var(--surface-hover); }
.sino-item:focus-visible { outline: 2px solid var(--link); outline-offset: -2px; }

.sino-nome {
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sino-barra { height: 5px; border-radius: var(--radius-full); background: var(--surface-hover); overflow: hidden; }
.sino-barra i { display: block; height: 100%; border-radius: var(--radius-full); }

.sino-qtd { font-size: var(--fs-sm); font-weight: 700; text-align: right; font-variant-numeric: tabular-nums; }

/* Gravidade relativa ao maior da lista, nao um limiar absoluto. */
.sino-barra i.alto,  .sino-qtd.alto  { background-color: var(--accent-red); }
.sino-barra i.medio, .sino-qtd.medio { background-color: var(--accent-orange); }
.sino-barra i.baixo, .sino-qtd.baixo { background-color: var(--accent-yellow); }
.sino-qtd.alto  { background: none; color: var(--accent-red); }
.sino-qtd.medio { background: none; color: var(--accent-orange); }
.sino-qtd.baixo { background: none; color: var(--body); }

.sino-item.atencao { grid-template-columns: 20px 1fr auto; }
.sino-ico { display: inline-flex; color: var(--accent-yellow); }
.sino-ico .icon { width: 17px; height: 17px; }
.sino-tag {
    font-size: var(--fs-xs); font-weight: 600; padding: 2px 8px;
    border-radius: var(--radius-sm);
    background: var(--fundo-aviso);
    color: var(--accent-yellow);
}

.sino-vazio { padding: var(--space-8) var(--space-4); text-align: center; color: var(--body); }
.sino-vazio .icon { width: 30px; height: 30px; color: var(--accent-green); margin-bottom: var(--space-2); }
.sino-vazio p { font-size: var(--fs-sm); }
/* Sem novidade não é "tudo certo" (o check verde): é só silêncio. */
.sino-vazio-neutro .icon { color: var(--mute); }

/* Era texto morto ("+89 outros bancos"); agora leva para Servidores. */
.sino-footer {
    display: flex; align-items: center; gap: var(--space-2);
    width: 100%; padding: 11px var(--space-4);
    border: 0; border-top: 0;
    background: var(--surface-card);
    font: inherit; font-size: var(--fs-xs); color: var(--body);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-std), color var(--dur-fast) var(--ease-std);
}
.sino-footer:hover { background: var(--surface-hover); color: var(--ink); }
.sino-footer .icon { width: 16px; height: 16px; flex-shrink: 0; }
.sino-footer .icon:last-child { margin-left: auto; }

/* Esqueleto do sino: só aparece na primeira abertura, antes de haver cache. */
.sino-skel {
    height: 34px;
    margin: 4px 0;
    border-radius: var(--radius-sm);
    background: var(--surface-hover);
    animation: sinoPulse 1.1s ease-in-out infinite;
}
.sino-skel:nth-child(2) { animation-delay: .1s; }
.sino-skel:nth-child(3) { animation-delay: .2s; }
.sino-skel:nth-child(4) { animation-delay: .3s; }
.sino-skel:nth-child(5) { animation-delay: .4s; }
@keyframes sinoPulse { 0%, 100% { opacity: .45; } 50% { opacity: .9; } }
@media (prefers-reduced-motion: reduce) { .sino-skel { animation: none; } }

/* Marca de regime/alerta antes do nome (substitui o emoji que vinha da API). */
.sino-nome .icon { width: 15px; height: 15px; margin-right: 5px; vertical-align: -2px; color: var(--body); }

/* Aba Novidades: o que mudou nas varreduras automáticas. Linha neutra, como
   as do ranking — o fundo laranja em cada uma fazia 25 avisos parecerem 25
   alarmes. A cor fica só no ícone do tipo. */
.sino-notif-item {
    display: grid;
    grid-template-columns: 28px 1fr auto auto;
    align-items: center;
    gap: var(--space-3);
    padding: 6px 6px 6px 10px;
    border-radius: var(--radius-sm);
}
.sino-notif-item:hover { background: var(--surface-hover); }
.sino-notif-ico {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-md);
    background: var(--fundo-info);
    color: var(--accent-blue);
}
.sino-notif-ico.regime { background: var(--fundo-aviso); color: var(--accent-orange); }
.sino-notif-ico .icon { width: 17px; height: 17px; }
.sino-notif-msg { min-width: 0; font-size: var(--fs-sm); font-weight: 500; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sino-notif-quando { font-size: var(--fs-xs); color: var(--mute); font-variant-numeric: tabular-nums; white-space: nowrap; }
.sino-notif-ativar {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-2);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
    background: var(--preenchimento);
    font-size: var(--fs-xs);
    color: var(--body);
}
.sino-notif-ativar > .icon { width: 17px; height: 17px; flex-shrink: 0; color: var(--link); }
.sino-notif-ativar > span { flex: 1; }

/* === Exportar XML ===
   Três passos na ordem em que se decide: sistema e competência num cartão, a
   lista de clientes como tabela (cabeçalho com "marcar todos"), e as ações numa
   barra presa ao rodapé — a contagem e o Gerar XML à vista de qualquer ponto da
   lista. A página rola inteira: sem a rolagem interna, o cabeçalho da tabela e
   a barra de ações ficam presos à janela. */
.export-panel { display: flex; flex-direction: column; gap: var(--space-4); }
.export-panel > .tela-topo { margin-bottom: 0; padding-bottom: 0; }

.export-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-4) var(--space-8);
    padding: var(--space-4) var(--space-5);
    background: var(--surface-card);
    border: 0;
    border-radius: var(--radius-lg);
}
.export-passo { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
.export-rotulo {
    font-size: var(--fs-xs);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--mute);
}
.export-competencia { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.export-competencia .export-month-picker input[type="month"] { width: 180px; }
.export-competencia > .central-tabs { margin-left: var(--space-2); }
.central-tab .icone-sis { width: 16px; height: 16px; }

.export-dica { display: flex; align-items: center; gap: var(--space-2); font-size: var(--fs-xs); color: var(--mute); }
.export-dica .icon { width: 15px; height: 15px; flex-shrink: 0; }
.export-dica[hidden], .export-nodrive[hidden] { display: none; }
.export-nodrive { align-items: center; }
.export-nodrive > span { flex: 1; min-width: 0; }

.export-barra-lista { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.export-busca { display: flex; flex: 1 1 280px; max-width: 420px; }
.export-busca .filtro-search-input { width: 100%; }
.export-contagem { margin-left: auto; font-size: var(--fs-xs); color: var(--mute); white-space: nowrap; }

.export-panel .bank-list { display: flex; flex-direction: column; gap: var(--space-3); }

/* A tabela: um cartão, linhas sem vão, zebra, e o cabeçalho preso ao topo da
   janela. `overflow: clip` corta os cantos sem virar rolagem — com `hidden` o
   cabeçalho grudaria no próprio cartão, e não na janela. */
.bank-tabela { background: var(--surface-card); border-radius: var(--radius-lg); overflow: clip; }
.bank-cabecalho, .export-panel .bank-item {
    display: grid;
    /* Caixa | Cliente (nome, filial e notas) | Servidor | Banco | Situação */
    grid-template-columns: 16px minmax(0, 2.6fr) minmax(0, 1fr) minmax(0, 1.3fr) 150px;
    align-items: center;
    gap: var(--bank-item-gap);
    padding: var(--bank-item-pad);
    padding-left: var(--space-4);
}
.bank-cabecalho {
    position: sticky;
    /* O sticky conta a partir do respiro do .main-body: sem subir o mesmo tanto, as linhas
       passavam visíveis no vão acima do cabeçalho preso. */
    top: calc(var(--main-body-topo) * -1);
    z-index: 2;
    min-height: 36px;
    background: var(--tabela-cabecalho);
    font-size: var(--fs-xs);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--mute);
}
.export-panel .bank-wrapper { display: flex; flex-direction: column; }
.bank-tabela > .bank-wrapper:nth-child(odd) { background: var(--zebra-tint); }

.export-panel .bank-item {
    width: 100%;
    /* Via token: é a lista de Exportar XML que o Modo compacto aperta — ver o fim do arquivo. */
    min-height: var(--bank-item-min-h);
    background: transparent;
    border: 0;
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-std);
}
.export-panel .bank-item:hover { background: var(--surface-hover); }
.export-panel .bank-item:focus-visible { outline: 2px solid var(--link); outline-offset: -2px; }
/* Marcada: um tom da cor de ação — o --fundo-info do claro some ao lado da zebra. */
.export-panel .bank-item.checked { background: color-mix(in srgb, var(--accent-blue-vivid) 10%, var(--surface-card)); }
.export-panel .bank-item.checked:hover { background: color-mix(in srgb, var(--accent-blue-vivid) 16%, var(--surface-card)); }

/* Cliente: o nome encolhe por último — a filial e as notas cedem espaço antes dele. */
.bank-cliente { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.export-panel .bank-name {
    flex: 0 1 auto;
    min-width: 0;
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.export-panel .bank-server,
.export-panel .bank-db     { font-size: var(--fs-xs); color: var(--body); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.export-panel .bank-db     { color: var(--mute); font-variant-numeric: tabular-nums; }

/* A filial vinculada, discreta ao lado do apelido: e identidade da linha, nao
   um controle. Sem ela, dois clientes do mesmo banco ficam indistinguiveis. */
.export-panel .bank-filial-nome {
    flex: 0 3 auto;
    min-width: 0;
    font-size: var(--fs-xs);
    font-weight: 400;
    color: var(--mute);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* O rodapé: flutua sobre a lista (a única sombra do sistema é a do que flutua). */
.export-rodape {
    position: sticky;
    bottom: calc(var(--space-3) - var(--main-body-topo));
    z-index: 3;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-3) var(--space-3) var(--space-5);
    background: var(--surface-flutuante);
    box-shadow: var(--sombra-flutuante);
    border-radius: var(--radius-lg);
}
.export-acoes { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.export-resumo { display: flex; flex-direction: column; gap: 2px; min-width: 0; margin-right: auto; }
.export-resumo strong { font-size: var(--fs-sm); font-weight: 600; color: var(--ink); }
.export-resumo strong.tem-selecao { color: var(--link); }
.export-resumo > span { font-size: var(--fs-xs); color: var(--mute); }
.export-resumo #lastExportInfo:not(:empty)::before { content: ' · '; }
.export-rodape .export-progress { margin: 0; padding: 0; background: none; }
.export-rodape .export-progress .progress-bar { background: var(--preenchimento); }

/* Banco que nenhum cliente referencia. Nao exporta — existe na lista como
   lembrete de que falta cadastrar, e some em silencio seria pior. */
.export-panel .bank-item.bank-sem-cadastro {
    opacity: 0.55;
    cursor: default;
}
.export-panel .bank-item.bank-sem-cadastro .bank-check {
    border-style: dashed;
}
.export-panel .bank-status.sem-cadastro { background: var(--fundo-erro); color: var(--accent-red); }
/* Cliente sem vinculo cujo XML chegou por importacao. Cinza como o sem
   cadastro, mas por outro motivo: aqui NAO ha o que gerar, e a linha vai
   marcada de proposito — o destino dela e o disparo de e-mail. */
.export-panel .bank-status.importado { background: var(--fundo-info); color: var(--link); }
.export-panel .bank-status.contrato-parcial { background: var(--fundo-aviso); color: var(--accent-yellow); }

/* Aviso de que marcar CANCELAMENTO leva a exclusao do cadastro. Fica no
   proprio dialogo e so aparece com a opcao escolhida: um aviso permanente
   sobre uma consequencia que quase nunca se aplica deixa de ser lido. */
.central-aviso-exclusao {
    margin-top: var(--space-3);
}

/* A lista do que foi excluido, no aviso de login. Excluir cadastro e
   irreversivel: a pessoa precisa poder LER os nomes e anotar. */
.aviso-exclusao-lista {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    max-height: 320px;
    overflow-y: auto;
    margin: var(--space-3) 0;
}
.aviso-exclusao-item {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    background: var(--preenchimento);
    border-radius: var(--radius-md);
    font-size: var(--fs-sm);
}
.aviso-exclusao-quando { font-size: var(--fs-xs); color: var(--mute); margin-left: auto; }
.export-panel .bank-item.bank-importado {
    opacity: 0.72;
    cursor: default;
}
/* O check fica cheio, e nao tracejado como o do sem-cadastro: aquele diz
   "nao da para marcar", este diz "ja esta marcado e nao sai". */
.export-panel .bank-item.bank-importado .bank-check {
    background: var(--accent-blue-vivid);
    border-color: var(--accent-blue-vivid);
}

.export-panel .bank-status-col { display: flex; justify-content: flex-end; }
.export-panel .bank-status {
    display: inline-flex; align-items: center; gap: 4px;
    font-size: var(--fs-xs); padding: 2px 8px; border-radius: var(--radius-sm);
    white-space: nowrap;
}
.export-panel .bank-status .icon { width: 14px; height: 14px; }
.export-panel .bank-status.pending     { background: var(--fundo-aviso); color: var(--accent-yellow); }
.export-panel .bank-status.done        { background: var(--fundo-ok);  color: var(--accent-green); }
.export-panel .bank-status.error       { background: var(--fundo-erro);    color: var(--accent-red); }
.export-panel .bank-status.hold        { background: var(--fundo-aviso); color: var(--accent-yellow); }
.export-panel .bank-status.no-emission { background: var(--fundo-aviso); color: var(--accent-orange); }
.export-panel .bank-status.offline     { background: var(--fundo-erro);    color: var(--accent-red); }
.export-panel .bank-status.problema    { background: var(--fundo-erro);    color: var(--accent-red); }
/* Nao exportado por decisao: o operador escolheu deixar pendente no
   dialogo de pendencias. Nao e erro — e uma pendencia conhecida. */
.export-panel .bank-status.pendente    { background: var(--fundo-aviso); color: var(--accent-orange); }

.export-panel .bank-item.offline { opacity: .55; cursor: not-allowed; background: var(--surface-hover); }
.export-panel .bank-item.offline .bank-check { border-style: dashed; }

.export-panel .bank-ultima-msg {
    font-size: var(--fs-xs);
    line-height: 1.35;
    /* Alinhada ao nome: recuo da linha + caixa + vão. */
    padding: 0 var(--space-4) var(--space-2) calc(var(--space-4) + 16px + var(--bank-item-gap));
    word-break: break-word;
}
.export-panel .bank-ultima-msg.done        { color: var(--accent-green); }
.export-panel .bank-ultima-msg.error       { color: var(--accent-red); }
.export-panel .bank-ultima-msg.hold,
.export-panel .bank-ultima-msg.pending     { color: var(--accent-yellow); }
.export-panel .bank-ultima-msg.no-emission { color: var(--accent-orange); }
.export-panel .bank-ultima-msg .icon { width: 14px; height: 14px; vertical-align: -2px; }

/* --- Gdoor (Slim/Pro) --- */
/* Cliente sem PDF+ZIP na pasta do mes: fica visivel, mas fora de alcance. Some
   da lista seria pior — o operador precisa VER quem esta faltando arquivo. */
.export-panel .bank-item.gdoor-missing {
    opacity: .55;
    background: var(--surface-card);
    cursor: not-allowed;
}
.export-panel .bank-item.gdoor-missing:hover {
    background: var(--surface-card);
}
.export-panel .bank-item.gdoor-missing .bank-check {
    background: var(--surface-card);
    border-color: var(--hairline);
    color: var(--body);
}

.gdoor-check-info {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: 10px 14px;
    border-radius: var(--radius-lg);
    font-size: var(--fs-xs);
    font-weight: 500;
    background: var(--fundo-aviso);
    color: var(--accent-yellow);
    border: 0;
}
.gdoor-check-info .icon { width: 16px; height: 16px; flex-shrink: 0; }
.gdoor-check-info.done {
    background: var(--fundo-ok);
    color: var(--accent-green);
}
.gdoor-check-info.checking { animation: gdoorCheckPulse 1.4s ease-in-out infinite; }
@keyframes gdoorCheckPulse {
    0%, 100% { opacity: 1; }
    50% { opacity: .55; }
}

/* Janela de importacao manual */
.gdoor-import-cliente {
    font-size: var(--fs-base);
    font-weight: 700;
    color: var(--link);
    margin: 0 0 6px 0;
}
.gdoor-import-ajuda {
    font-size: var(--fs-xs);
    line-height: 1.5;
    color: var(--body);
    margin: 0 0 14px 0;
}
.gdoor-import-obrig { color: var(--accent-red); }
.gdoor-import-mes {
    display: flex;
    gap: 6px;
    align-items: center;
    flex-wrap: wrap;
    margin-bottom: var(--space-4);
}
.gdoor-import-file {
    width: 100%;
    margin-bottom: 10px;
}
.gdoor-import-result { font-size: var(--fs-xs); line-height: 1.5; margin-top: 8px; }
.gdoor-import-result .icon { width: 16px; height: 16px; vertical-align: -3px; }
.gdoor-import-erro { color: var(--accent-red); }
.gdoor-import-ok { color: var(--accent-green); word-break: break-all; }


/* ── Planilha da Central: baixar e importar ─────────────────────────────────
   A previa e' a razao de ser desta tela: a planilha real tem 186 linhas e
   linha torta (e-mail na coluna Sistema, "NAO INFORMADO" como escritorio).
   Por isso a lista de mudancas rola dentro do modal em vez de esticar a
   janela para fora da viewport. */
.planilha-body {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
    padding: var(--space-5);
    max-height: 62vh;
    overflow-y: auto;
}
.planilha-secao h3 {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--ink);
    margin: 0 0 4px 0;
}
.planilha-secao h3 .icon { width: 17px; height: 17px; }
.planilha-ajuda {
    font-size: var(--fs-xs);
    line-height: 1.5;
    color: var(--body);
    margin: 0 0 10px 0;
}
.planilha-baixar { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.planilha-file {
    width: 100%;
}

.planilha-previa:not(:empty) { margin-top: var(--space-3); }
.planilha-erro { font-size: var(--fs-xs); color: var(--accent-red); line-height: 1.5; }
.planilha-erro .icon, .planilha-ok .icon { width: 16px; height: 16px; vertical-align: -3px; }
.planilha-ok {
    font-size: var(--fs-xs);
    line-height: 1.5;
    color: var(--accent-green);
    background: var(--fundo-ok);
    border-radius: var(--radius-md);
    padding: 8px 10px;
    margin-bottom: var(--space-3);
}
.planilha-nada { font-size: var(--fs-xs); color: var(--body); margin: var(--space-3) 0 0 0; }

/* Os numeros do que vai acontecer. Ficam em cima porque sao a resposta que a
   pessoa procura antes de decidir se confirma. */
.planilha-resumo {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: var(--space-3);
}
.planilha-conta {
    font-size: var(--fs-xs);
    padding: 3px 8px;
    border-radius: var(--radius-md);
    background: var(--surface-elevated);
    color: var(--body);
}
.planilha-conta b { color: var(--ink); }
.planilha-conta.novo { background: var(--fundo-ok); color: var(--accent-green); }
.planilha-conta.novo b { color: var(--accent-green); }
.planilha-conta.muda { background: var(--fundo-info); color: var(--accent-blue); }
.planilha-conta.muda b { color: var(--accent-blue); }

.planilha-avisos {
    background: var(--fundo-aviso);
    border-radius: var(--radius-md);
    padding: 8px 10px;
    margin-bottom: var(--space-3);
}
.planilha-avisos h4 {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--fs-xs);
    font-weight: 600;
    color: var(--ink);
    margin: 0 0 4px 0;
}
.planilha-avisos h4 .icon { width: 16px; height: 16px; }
.planilha-avisos ul { margin: 0; padding-left: 0; list-style: none; }
.planilha-avisos li {
    font-size: var(--fs-xs);
    line-height: 1.6;
    color: var(--ink);
}

.planilha-lista { margin-bottom: var(--space-3); }
.planilha-lista h4 {
    font-size: var(--fs-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--mute);
    margin: 0 0 4px 0;
}
.planilha-lista ul { margin: 0; padding: 0; list-style: none; }
.planilha-linha {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 6px;
    padding: 4px 0;
    border-bottom: 0;
    font-size: var(--fs-xs);
    line-height: 1.5;
}
.planilha-linha:last-child { border-bottom: 0; }
.planilha-acao {
    flex: 0 0 auto;
    min-width: 38px;
    text-align: center;
    padding: 1px 6px;
    border-radius: var(--radius-sm);
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .03em;
}
.planilha-linha.criar .planilha-acao { background: var(--fundo-ok); color: var(--accent-green); }
.planilha-linha.atualizar .planilha-acao { background: var(--fundo-info); color: var(--accent-blue); }
.planilha-nome { font-weight: 600; color: var(--ink); }
.planilha-ref { color: var(--mute); font-variant-numeric: tabular-nums; }
.planilha-detalhe { display: flex; flex-wrap: wrap; gap: 4px; }
.planilha-mud {
    background: var(--surface-elevated);
    border-radius: var(--radius-sm);
    padding: 1px 6px;
    color: var(--body);
}
.planilha-mud b { color: var(--ink); font-weight: 600; }
.planilha-mud s { color: var(--mute); }
.planilha-mais { font-size: var(--fs-xs); color: var(--mute); margin: 4px 0 0 0; }

@media (max-width: 700px) {
    .planilha-body { max-height: none; }
}


.export-vazio { padding: var(--space-10) var(--space-4); text-align: center; color: var(--body); }
.export-vazio .icon { width: 32px; height: 32px; color: var(--mute); margin-bottom: var(--space-2); }
.export-vazio p { font-size: var(--fs-sm); margin-bottom: var(--space-3); }

/* A dica embaixo do estado vazio: diz o que fazer, então é secundária ao fato,
   não a repetição dele em outro tamanho. */
.export-vazio-dica {
    max-width: 46ch;
    margin: 0 auto;
    color: var(--mute);
    font-size: var(--fs-xs);
    line-height: 1.5;
}

/* Telas estreitas: o banco some primeiro, depois o servidor. */
@media (max-width: 1180px) {
    .bank-cabecalho, .export-panel .bank-item { grid-template-columns: 16px minmax(0, 2fr) minmax(0, 1fr) 130px; }
    .export-panel .bank-db, .bank-cabecalho > :nth-child(4) { display: none; }
}
@media (max-width: 720px) {
    .bank-cabecalho, .export-panel .bank-item { grid-template-columns: 16px minmax(0, 1fr) 110px; }
    .export-panel .bank-server, .bank-cabecalho > :nth-child(3) { display: none; }
}

/* Logos de marca (simple-icons): preenchidas, nao tracadas. Herdam a cor da
   marca em vez de currentColor — o verde do WhatsApp e parte do identificador,
   um WhatsApp cinza nao e reconhecido. */
.icon-marca { fill: currentColor; }
.icon-whatsapp { color: var(--marca-whatsapp); }

/* Em botao primario/superficie colorida a marca volta a herdar, senao o verde
   brigaria com o fundo. */
.export-btn.primary .icon-marca,
.btn-primary .icon-marca { color: currentColor; }

/* === Selects: uma regra so ===
   Havia tres definicoes concorrentes (.filtro-select, .export-sort-select,
   .central-select) com raio 8px vs 10px, fundo --surface-card vs --surface-card, fonte
   12px/600 vs 13px e anel de foco em apenas uma. Mesma aparencia agora, com os
   tokens; o que e realmente especifico de cada tela fica nos ajustes abaixo. */
.central-select { max-width: 180px; }

/* === Popover de periodo personalizado ===
   Substituiu um modal de tela cheia com estilo inline: escolher duas datas nao
   justifica bloquear a tela inteira. Ancorado ao botao que o abriu. */
.data-popover {
    position: fixed;
    z-index: var(--z-dropdown);
    width: 300px;
    max-width: calc(100vw - 24px);
    background: var(--surface-flutuante);
    box-shadow: var(--sombra-flutuante);
    border-radius: var(--radius-lg);
    overflow: hidden;
}
.data-popover-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    border-bottom: 0;
}
.data-popover-head h4 { font-size: var(--fs-sm); font-weight: 700; color: var(--ink); }

.data-popover-campos { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-4); }
.data-popover-campos label { display: flex; flex-direction: column; gap: 5px; }
.data-popover-campos span { font-size: var(--fs-xs); color: var(--body); font-weight: 600; }
.data-popover-campos input[type="date"] {
    width: 100%;
}

.data-popover-erro {
    display: none;
    padding: 0 var(--space-4) var(--space-2);
    font-size: var(--fs-xs);
    color: var(--accent-red);
}
.data-popover-erro.visivel { display: block; }

.data-popover-acoes {
    display: flex; justify-content: flex-end; gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    border-top: 0;
    background: var(--surface-card);
}

/* Corpo da Home: uma grade por aba (Pendências | Envio de XML), cada uma
   com a sua forma. O que a aba escondida ocupa é nada: [hidden] vence o
   display: grid daqui. */
.dash-corpo { display: grid; gap: var(--space-5); }
.dash-corpo[hidden] { display: none; }
/* A troca de aba, no alto do Painel: o trilho segmentado de sempre, sem esticar
   até a largura toda (o Painel é uma coluna flex). */
.dash-abas { align-self: flex-start; }

/* Pendências: atenção em cima, tipos e ranking embaixo. */
.dash-corpo-pend {
    grid-template-columns: minmax(0, 1fr) minmax(0, 2.4fr);
    grid-template-areas:
        "atencao atencao"
        "tipos   ranking";
}

/* Envio de XML: o fechamento do mês, os três números e o gráfico à esquerda;
   a atividade recente na coluna da direita, de ponta a ponta. */
.dash-corpo-xml {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 320px;
    grid-template-rows: auto auto 1fr;
    grid-template-areas:
        "fech   fech     atividade"
        "kpis   kpis     atividade"
        "envios clientes atividade";
}
/* O card dos e-mails (com a sparkline) ocupa a esquerda de cima a baixo; os
   dois números curtos se empilham na direita. Os três lado a lado esticavam os
   dois curtos até a altura do card da sparkline, com um vão vazio embaixo. */
.dash-corpo-xml .kpi-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.dash-corpo-xml .kpi-row > :first-child { grid-row: 1 / span 2; }
/* A sparkline ocupa o que sobra na altura do card, em vez de deixar um vão
   acima dela. Base 0 (height: 0 + flex-grow): com height: auto o SVG pediria a
   altura da própria proporção e o card passaria a mandar na altura da linha.
   O traço não deforma (vector-effect: non-scaling-stroke). */
.dash-corpo-xml .kpi-row > :first-child .kpi-rodape { flex: 1 1 auto; }
.dash-corpo-xml .kpi-row > :first-child .kpi-rodape .spark { flex: 1 1 0; height: 0; min-height: 34px; }

.dash-corpo > .panel-card { margin-bottom: 0; }
.dash-corpo .kpi-row { grid-area: kpis; }
.area-fech { grid-area: fech; }
.area-tipos { grid-area: tipos; }
.area-ranking { grid-area: ranking; }
.area-envios { grid-area: envios; }
.area-atividade { grid-area: atividade; min-height: 0; display: flex; flex-direction: column; }
/* Envios por cliente (app.js, renderDashClientes): o card, ao lado do gráfico
   de e-mails, e o modal expandido. A linha inteira abre o detalhe; no modal o
   botão › é o caminho do teclado.
   Meia largura: os valores do modo compacto, só dentro do card. */
.area-clientes {
    grid-area: clientes;
    display: flex;
    flex-direction: column;
    min-width: 0;
    --btn-min-h: 28px;
    --btn-fs: var(--fs-xs);
    --icon-btn-w: 28px;
    --tabela-td-pad: 2px 8px;
    --tabela-th-pad: 3px 8px;
    --tabela-fs: 12px;
    --tabela-linha-h: 30px;
    --selo-h: 18px;
}
/* A altura vem do grid (a do gráfico ao lado), nunca da lista: sem o contain,
   180 clientes esticariam a linha inteira do Painel. */
#dashClientes { flex: 1 1 200px; min-height: 0; display: flex; flex-direction: column; contain: size; }
/* Busca e os dois selects numa linha a partir de 1280px: o <select> mede pela
   opção mais comprida ("Uniplus Desktop"), então o teto é dele. */
.area-clientes .central-search { min-width: 0; flex: 1 1 96px; }
.area-clientes .central-select { max-width: 130px; }
.dash-cli-filtros { gap: var(--space-2); margin-bottom: var(--space-3); }
.dash-cli-tabela tbody tr, .dash-cli-tabela-modal tbody tr { cursor: pointer; }
/* O nome encolhe com reticências: a coluna toma o que sobra das outras. */
.dash-cli-cliente { width: 100%; max-width: 1px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dash-cli-logo { display: inline-flex; vertical-align: -2px; margin-right: 6px; }
.dash-cli-logo .icone-sis { width: 14px; height: 14px; }
/* O modal: o miolo ocupa a altura toda e só a tabela rola. */
[data-dash-cli-corpo], #dashCliModalLista { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
/* Os selos numa linha só: quem encolhe é o nome do cliente, não a linha que dobra. */
.dash-cli-selos { display: flex; gap: var(--space-1); white-space: nowrap; }
.dash-cli-quando { white-space: nowrap; color: var(--body); font-variant-numeric: tabular-nums; }
.dash-cli-nome { display: block; }
.dash-cli-linha2 {
    display: block;
    max-width: 280px;
    margin-top: 2px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--fs-xs);
    color: var(--mute);
}
.dash-cli-nada { color: var(--mute); }
.dash-cli-acao { width: 1%; text-align: right; }
.dash-cli-detalhe-topo { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-3); }
.dash-cli-detalhe-topo .dash-cli-cadastro { margin-left: auto; }

/* A atividade é a única coluna que rola: as demais têm altura previsível, ela
   cresce com o número de eventos. */
.area-atividade #dashAtividade {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}


/* Container de canvas do Chart.js.
   O canvas fica ABSOLUTO de propósito: com ele no fluxo normal e o container
   em flex:1, forma-se um laço (canvas preenche o container -> Chart.js grava
   a altura no canvas -> container cresce -> repete) que inflava o painel para
   bem mais que o pedido. Absoluto, o canvas não contribui para a altura. */
.chart-wrap { position: relative; height: 240px; width: 100%; min-width: 0; }
.chart-wrap canvas { position: absolute; inset: 0; max-width: 100%; }

/* Chave de instalação do agente — aparece uma única vez, então tem de ser
   fácil de ler e de selecionar. Mesma forma do `.segredo` do painel
   administrativo: monoespaçada, quebrando em qualquer ponto (a chave não tem
   espaço para quebrar sozinha) e com borda tracejada, que diz "isto é para
   copiar" sem precisar de um rótulo a mais. */
.chave-agente {
    font-family: var(--font-mono);
    font-size: 13px;
    line-height: 1.5;
    word-break: break-all;
    user-select: all;
    background: var(--preenchimento);
    color: var(--ink);
    border: 0;
    border-radius: var(--radius);
    padding: var(--space-3);
    margin: var(--space-4) 0 var(--space-2);
}

/* Botão solto no corpo do modal, fora do rodapé. O `.modal-actions` do rodapé
   tem borda superior e alinha à direita; uma ação que pertence ao conteúdo
   (gerar chave nova) ali pareceria a confirmação do formulário. */
.modal-actions-inline {
    margin: var(--space-3) 0 var(--space-4);
}

/* O aviso de que todo usuário criado é superusuário. Não é decoração: sem
   papéis, quem cadastra está dando acesso total, e isso não pode estar só no
   commit. Cor de atenção, e não de erro — a ação é legítima. */
.aviso-superusuario {
    margin-bottom: var(--space-5);
}


/* =====================================================================
   TELA DE LOGIN
   Dividida: marca à esquerda, formulário à direita — o arranjo de painel
   administrativo mais usado hoje. O que NÃO copiamos do padrão de mercado é o
   gradiente no painel de marca: ## Do's and Don'ts proíbe, e a profundidade aqui vem de
   sombra e raio (## Overview). Cor chapada, e a hierarquia se faz por tamanho.
   ===================================================================== */
/* Desfaz o body da tela do app, que e' `display:flex; height:100vh;
   overflow:hidden` para o layout de abas. Herdando aquilo, o .login-split vira
   item flex — e item flex nasce `flex: 0 1 auto`, do tamanho do conteudo. As
   colunas 1fr 1fr se dividiam dentro dessa largura encolhida e sobrava meia
   viewport vazia a direita. O overflow:hidden ainda cortaria o cartao em tela
   baixa, sem barra de rolagem para alcanca-lo. */
body.tela-login {
    display: block;
    height: auto;
    min-height: 100vh;
    overflow: auto;
    margin: 0;
    background: var(--canvas);
}

/* Tela de erro (erro.html): o código, o que houve e a saída, centrados. */
body.tela-erro {
    display: grid;
    place-items: center;
    height: auto;
    min-height: 100vh;
    overflow: auto;
    margin: 0;
    padding: var(--space-5);
    background: var(--canvas);
}
.erro-caixa {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
    max-width: 420px;
    text-align: center;
}
.erro-logo { margin-bottom: var(--space-6); }
.erro-caixa a.btn-primary { text-decoration: none; }
.erro-codigo {
    margin: 0;
    font-size: var(--fs-2xl);
    font-weight: 500;
    line-height: 1;
    letter-spacing: -0.02em;
    color: var(--mute);
    font-variant-numeric: lining-nums tabular-nums;
}
.erro-caixa h1 { margin: 0; font-size: var(--fs-xl); font-weight: 600; color: var(--ink); }
.erro-msg { margin: 0 0 var(--space-3); font-size: var(--fs-sm); color: var(--body); line-height: 1.5; }

.login-split {
    display: grid;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    min-height: 100vh;
}

/* ── Esquerda: painel azul animado (2026-09-25) ─────────────────────────
   Antes eram fotos com uma frase por cima; a direção pediu algo simples e
   moderno, sem imagem. Só CSS: três brilhos (radiais, sem blur) derivam
   devagar sobre a base azul, e três ondas — traços finos de SVG — se abrem do
   centro em sequência. Nada de linear-gradient (estilo.check.js): o brilho é
   radial, como os glows do documento. Movimento só em transform/opacity, que
   não força relayout. */
.login-marca { display: flex; min-height: 0; }
.login-fundo {
    position: relative;
    flex: 1;
    overflow: hidden;
    background: var(--login-azul);
    color: var(--login-texto);
}
.login-orbe {
    position: absolute;
    /* Sem border-radius: o radial some (transparent) antes da borda da caixa. */
    background: radial-gradient(closest-side, var(--login-brilho), transparent);
    opacity: .7;
    will-change: transform;
}
.login-orbe.a { width: 90%; aspect-ratio: 1; left: -30%; top: -25%; animation: loginDeriva 26s ease-in-out infinite alternate; }
.login-orbe.b { width: 80%; aspect-ratio: 1; right: -30%; bottom: -20%; animation: loginDeriva 32s ease-in-out -9s infinite alternate-reverse; }
.login-orbe.c {
    width: 45%; aspect-ratio: 1; left: 38%; top: 30%;
    background: radial-gradient(closest-side, var(--login-brilho-claro), transparent);
    opacity: .5;
    animation: loginDeriva 20s ease-in-out -5s infinite alternate;
}
@keyframes loginDeriva {
    from { transform: translate3d(0, 0, 0) scale(1); }
    to   { transform: translate3d(14%, 10%, 0) scale(1.18); }
}
.login-ondas {
    position: absolute;
    left: 50%;
    top: 50%;
    width: min(120%, 120vh);
    aspect-ratio: 1;
    transform: translate(-50%, -50%);
    pointer-events: none;
}
.login-ondas circle {
    fill: none;
    stroke: var(--login-linha);
    stroke-width: 1;
    vector-effect: non-scaling-stroke;   /* o traço não engorda com o scale */
    transform-box: fill-box;
    transform-origin: center;
    opacity: 0;
    animation: loginOnda 15s ease-out infinite;
}
.login-ondas circle:nth-child(2) { animation-delay: -5s; }
.login-ondas circle:nth-child(3) { animation-delay: -10s; }
@keyframes loginOnda {
    0%   { transform: scale(.15); opacity: 0; }
    15%  { opacity: 1; }
    100% { transform: scale(1); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
    .login-orbe, .login-ondas circle { animation: none; }
    .login-ondas circle:nth-child(1) { opacity: 1; transform: scale(.45); }
    .login-ondas circle:nth-child(2) { opacity: .7; transform: scale(.7); }
    .login-ondas circle:nth-child(3) { opacity: .4; transform: scale(.95); }
}
.login-mensagem {
    position: absolute;
    z-index: 1;
    left: var(--space-12);
    right: var(--space-12);
    bottom: var(--space-10);
}
.login-frase {
    margin: 0 0 var(--space-5);
    max-width: 24ch;
    font-size: calc(var(--fs-xl) * 1.25);
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: -0.01em;
}
.login-frase-quem { display: flex; flex-direction: column; gap: 2px; margin: 0; font-size: var(--fs-base); }
.login-frase-quem strong { font-weight: 600; }

/* ── Direita: logo no topo, formulário no meio, rodapé embaixo ─────────
   Os três na MESMA coluna (400px, centralizada): o logo solto no canto e o
   formulário no meio da tela não se alinhavam com nada. */
.login-form-lado {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: var(--space-10) var(--space-10) var(--space-8);
}
.login-topo, .login-card, .login-rodape { width: 100%; max-width: 400px; }
.login-topo { display: flex; align-items: center; }
/* Sem `display` aqui: quem mostra um e esconde o outro é .logo-claro/.logo-escuro. */
.login-logo { height: 40px; width: auto; }
.login-card {
    margin: auto 0;
    padding: var(--space-10) 0;
    background: none;
    border: 0;
}
.login-card h2 {
    margin: 0 0 var(--space-2);
    font-size: var(--fs-xl);
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: -0.02em;
    color: var(--ink);
}
.login-sub {
    margin: 0 0 var(--space-8);
    font-size: var(--fs-base);
    color: var(--mute);
}
.login-campo { display: block; margin-bottom: var(--space-5); }
.login-campo span {
    display: block;
    margin-bottom: var(--space-1);
}
.login-campo input {
    width: 100%;
    box-sizing: border-box;
}
/* A caixa da senha também é um <span> dentro do <label>: sem isto herdaria
   a margem do rótulo. O olho fica por cima do campo, à direita. */
.login-campo .login-senha { position: relative; margin-bottom: 0; }
.login-senha .icon-btn {
    position: absolute;
    top: 50%;
    right: 8px;
    transform: translateY(-50%);
}
.login-btn {
    width: 100%;
    margin-top: var(--space-3);
}
.login-btn-sso {
    display: flex;
    align-items: center;
    justify-content: center;
    text-decoration: none;
    background: var(--preenchimento);
    color: var(--ink);
}
.login-btn-sso:hover { background: var(--preenchimento-hover); }
/* O display do botão vence o [hidden] no empate: sem isto o SSO aparecia com o OIDC desligado. */
.login-btn-sso[hidden], .login-divisor[hidden] { display: none; }
/* Sem as réguas dos lados (decisão 3): só o "ou" entre os dois botões. */
.login-divisor {
    margin-top: var(--space-3);
    color: var(--mute);
    font-size: var(--fs-sm);
    text-align: center;
}
.login-erro {
    margin-bottom: var(--space-4);
    padding: 9px 12px;
    border: 0;
    border-radius: var(--radius-md);
    background: var(--fundo-erro);
    color: var(--accent-red);
    font-size: var(--fs-sm);
}
/* Aviso à esquerda, direitos à direita; em tela estreita o segundo desce. */
.login-rodape {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: var(--space-1) var(--space-4);
    margin: 0;
    font-size: var(--fs-xs);
    color: var(--mute);
}

/* Tablet: painel mais estreito. Celular: só o formulário — o painel
   roubaria a tela de quem só quer entrar. */
@media (max-width: 1100px) {
    .login-split { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
    .login-form-lado { padding: var(--space-8) var(--space-6); }
    .login-mensagem { left: var(--space-8); right: var(--space-8); bottom: var(--space-8); }
}
@media (max-width: 760px) {
    .login-split { grid-template-columns: 1fr; min-height: 100dvh; }
    .login-marca { display: none; }
    .login-form-lado { min-height: 100dvh; padding: var(--space-6) var(--space-5); box-sizing: border-box; }
    .login-card { padding: var(--space-8) 0; }
}

/* Pendências de NFC-e agrupadas. O bloco é o que separa "falta transmitir, tem
   prazo" de "número a inutilizar" — numa lista única os dois pareciam um só. */
.nfce-grupo {
    margin-bottom: var(--space-5);
}

.nfce-grupo h4 {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: 0 0 var(--space-1);
    font-size: 14px;
    color: var(--ink);
}

.nfce-qtd {
    padding: 1px 8px;
    border-radius: var(--radius-lg);
    background: var(--surface-elevated);
    color: var(--body);
    font-size: 12px;
    font-variant-numeric: tabular-nums;
}

/* O que resolve aquele grupo. Secundário na cor, não no lugar: quem abre a tela
   já sabe que há pendência — o que falta é saber o que fazer com ela. */
.nfce-acao,
.nfce-truncado,
.nfce-sem-motivo {
    margin: 0 0 var(--space-2);
    color: var(--body);
    font-size: 12px;
}

.nfce-sem-motivo {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: var(--space-4);
}

.nfce-truncado {
    margin: var(--space-2) 0 0;
}

/* O motivo pode ser longo. Corta na linha, e o texto inteiro fica no title. */
.nfce-motivo {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    color: var(--body);
    font-size: 12px;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Link de baixar o ZIP, dentro da linha de resultado da exportacao.
   inline-flex para o svg alinhar com o texto; sem isso o icone senta na linha
   de base e desalinha a frase inteira. */
.link-baixar {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-left: 8px;
    padding: 2px 8px;
    background: var(--preenchimento);
    border-radius: var(--radius-sm);
    color: var(--ink);
    font-size: 12px;
    text-decoration: none;
    white-space: nowrap;
}

.link-baixar:hover {
    background: var(--preenchimento-hover);
    color: var(--link);
}

.link-baixar .icon {
    width: 16px;
    height: 16px;
}

/* Toast — DESIGN.md (## Components */
.toast-container {
    position: fixed;
    top: 72px;
    right: var(--space-5);
    z-index: var(--z-toast);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    pointer-events: none;
}

/* Canto inferior direito — avisos da varredura automática. Container à parte
   (não reaproveita .toast-container) pra não competir por espaço vertical
   com toasts normais nem herdar o `top` fixo deles. */
.toast-container-br {
    top: auto;
    bottom: var(--space-5);
    flex-direction: column-reverse;
}

/* O toast em si. Estava faltando: existiam regras para o container, o ícone, a
   mensagem e o botão de fechar, mas nenhuma para o `.toast` — o elemento que
   carrega os quatro. O efeito era um aviso sem fundo, com o texto da tela
   aparecendo por baixo, os três filhos empilhados em vez de lado a lado, e o
   "×" caído numa linha própria. Pior: o container é `pointer-events: none`
   (para não bloquear cliques na tela por baixo) e nada devolvia o clique ao
   toast, então o botão de fechar era desenhado e não fechava nada. */
.toast {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    max-width: 380px;
    padding: var(--space-3) var(--space-4);
    background: var(--surface-flutuante);
    box-shadow: var(--sombra-flutuante);
    border-radius: var(--radius);
    color: var(--ink);
    font-size: 14px;
    line-height: 1.45;
    /* Devolve o clique que o container desliga. Sem isto o "×" não fecha. */
    pointer-events: auto;
    animation: toastIn var(--dur-base) var(--ease-std);
}

/* Faixa da cor do tipo. O ícone sozinho é pequeno demais para dizer, de
   relance, se aquilo é confirmação ou erro. */
.toast-success { border-left: 0; }
.toast-error { border-left: 0; }
.toast-info { border-left: 0; }

/* 18px de ícone contra 20px de linha: sem o empurrão ele fica alto demais na
   primeira linha de uma mensagem de duas. */
.toast-ico { display: flex; flex-shrink: 0; margin-top: 1px; }
.toast-success .toast-ico { color: var(--accent-green); }
.toast-error .toast-ico { color: var(--accent-red); }
.toast-info .toast-ico { color: var(--link); }

.toast-msg { flex: 1; min-width: 0; word-break: break-word; }

.toast-close {
    background: none;
    border: none;
    color: var(--mute);
    cursor: pointer;
    padding: 2px;
    display: flex;
    border-radius: var(--radius-sm);
    flex-shrink: 0;
    transition: color var(--dur-fast) var(--ease-std);
}
.toast-close:hover { color: var(--ink); }

.toast-out { animation: toastOut var(--dur-base) var(--ease-std) forwards; }

@keyframes toastIn {
    from { opacity: 0; transform: translateX(16px); }
    to { opacity: 1; transform: translateX(0); }
}
@keyframes toastOut {
    from { opacity: 1; transform: translateX(0); }
    to { opacity: 0; transform: translateX(16px); }
}

/* Badge canônico — DESIGN.md (## Components */
.badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 9px;
    border-radius: var(--radius-sm);
    font-size: var(--fs-xs);
    font-weight: 600;
    white-space: nowrap;
}
/* O DESIGN.md ## Components promete o badge desde sempre, mas ele existia sem uma única
   variante — então cada tela pintava o seu com `style=`. As quatro tintas
   publicadas (## Colors), e o neutro para o que não é estado, só rótulo. */
.badge-ok { background: var(--fundo-ok); color: var(--accent-green); }
.badge-erro { background: var(--fundo-erro); color: var(--accent-red); }
.badge-aviso { background: var(--fundo-aviso); color: var(--accent-orange); }
.badge-info { background: var(--fundo-info); color: var(--link); }
.badge-neutro { background: var(--surface-elevated); color: var(--body); }

.dash-spin {
    width: 24px;
    height: 24px;
    margin: 0 auto;
    border: 2px solid var(--hairline);
    border-top-color: var(--link);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

.dash-empty {
    padding: 30px;
    text-align: center;
    color: var(--mute);
    font-size: 13px;
}

/* =====================================================================
   Tela Servidores (cards por sistema)
   ===================================================================== */
.servidores-wrap { display: flex; flex-direction: column; gap: 18px; }
/* .tela-topo já traz margin-bottom próprio (a régua precisa de mais ar que uma
   linha comum) — sem isto, o gap do flex acima soma com ele e dobra o vão. */
.servidores-wrap > .tela-topo, .filtros-wrap > .tela-topo { margin-bottom: 0; }

.servidores-toolbar {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.servidores-cards {
    display: grid;
    /* 280px cortava "next-01.webuniplus.com" com reticências em todos os
       cards; 320px cabe o host inteiro e ainda dá 4 colunas em 1600px. */
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: var(--space-3);
}

.srv-card {
    background: var(--surface-card);
    border: 0;
    border-radius: var(--radius);
    padding: 16px;
    position: relative;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.srv-card.clickable { cursor: pointer; }
.srv-card.clickable:hover {
    background: var(--surface-hover);
}

.srv-card-head { display: flex; align-items: center; gap: 10px; }

.servidores-card-icon {
    width: 40px;
    height: 40px;
    border-radius: var(--radius);
    background: var(--surface-hover);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    font-size: 18px;
}
.servidores-card-icon .icon-img { width: 22px; height: 22px; object-fit: contain; }
.servidores-card-icon .icon-fallback { width: 22px; height: 22px; font-size: 11px; }

.srv-card-title { flex: 1; min-width: 0; }
.srv-card-nome { font-size: 14.5px; font-weight: 700; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.srv-card-sub { font-size: 11.5px; color: var(--body); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.srv-card-refresh {
    width: 30px;
    height: 30px;
    border: 0;
    border-radius: var(--radius);
    background: var(--surface-card);
    color: var(--ink);
    cursor: pointer;
    font-size: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
}
.srv-card-refresh:hover { background: var(--surface-hover); }

/* Rodapé do card: número + rótulo na mesma linha de base, com a seta que
   revela que o card abre algo. Antes o número tinha 34px sozinho numa linha e
   o rótulo em outra, o que dava a um card de 280px um bloco desequilibrado. */
.srv-card-rodape {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-2);
    margin-top: auto;
    padding-top: var(--space-2);
    border-top: 0;
}
.srv-card-medida { display: flex; align-items: baseline; gap: var(--space-2); min-width: 0; }
.srv-card-rodape > .icon {
    width: 18px; height: 18px; flex-shrink: 0;
    color: var(--mute);
    transition: color var(--dur-fast) var(--ease-std);
    align-self: center;
}
.srv-card.clickable:hover .srv-card-rodape > .icon { color: var(--link); }

/* A cifra é NEUTRA e o estado vira um ponto ao lado. Com 25 cartões na tela,
   25 números de 26px em vermelho/laranja/verde fazem a grade inteira gritar —
   e nada se destaca, porque tudo está colorido. O ponto deixa o olho achar os
   críticos sem tingir o número. */
.srv-card-pend {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: 24px;
    font-weight: 600;
    line-height: 1;
    color: var(--ink);
    /* Sem isto o "1" e o "134.224" desalinham entre cards vizinhos. */
    font-variant-numeric: tabular-nums;
}

.srv-card-pend::before {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: var(--radius-full);
    flex-shrink: 0;
    background: var(--hairline-strong);
}
.srv-card-pend.danger::before  { background: var(--accent-red-vivid); }
.srv-card-pend.warning::before { background: var(--accent-orange-vivid); }
.srv-card-pend.ok::before      { background: var(--accent-green-vivid); }
.srv-card-pend-label {
    font-size: var(--fs-xs);
    color: var(--body);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Cards Desktop (VPN, 1 banco) */
.srv-card-actions { display: flex; gap: 6px; align-items: center; }

.srv-card-status {
    width: 30px;
    height: 30px;
    border: 0;
    border-radius: var(--radius);
    background: var(--surface-card);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
}
.srv-card-status:hover { background: var(--surface-hover); }

.srv-live-dot {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--accent-green);
    position: relative;
    animation: srv-live-pulse 1.8s ease-in-out infinite;
}
@keyframes srv-live-pulse {
    0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent-green-vivid) 55%, transparent); }
    70% { box-shadow: 0 0 0 8px transparent; }
    100% { box-shadow: 0 0 0 0 transparent; }
}

.srv-offline-dot {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--accent-red);
}

/* Servidor sem conexão: esmaecido, mas ACESSÍVEL. Tinha pointer-events:none,
   e como Excluir/Varrer/Bancos moram na tela de detalhe, um Desktop com a VPN
   fora do ar não podia nem ser removido do cadastro. */
.srv-card.offline {
    background: var(--surface-card);
    opacity: 0.6;
    filter: grayscale(0.6);
}
.srv-card.offline:hover { opacity: 0.85; filter: grayscale(0.2); }

.srv-card.checking .srv-live-dot,
.srv-card.checking .srv-offline-dot { animation: srv-checking 0.9s ease-in-out infinite; }
@keyframes srv-checking {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.3; }
}

.servidores-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 40px 0;
}

/* =====================================================================
   Detalhe do servidor + Tenants
   ===================================================================== */
/* O separador "·" do subtítulo dos cards da lista de servidores. */
.srv-detalhe-sep { color: var(--mute); }
/* Quem esta logado, na lista de usuarios: a linha sem Excluir/Desativar
   precisa dizer POR QUE nao tem, senao parece defeito. */
.usuario-eu, .usuario-inativo {
    font-size: var(--fs-xs);
    font-weight: 600;
    color: var(--body);
    background: var(--surface-elevated);
    border-radius: var(--radius-sm);
    padding: 1px 6px;
    margin-left: 4px;
}

.servidor-status {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: 6px 12px;
    border-radius: var(--radius-sm);
    font-size: var(--fs-xs);
    font-weight: 700;
    width: fit-content;
    white-space: nowrap;
}
.servidor-status.online { background: var(--fundo-ok); color: var(--accent-green); }
.servidor-status.offline { background: var(--fundo-erro); color: var(--accent-red); }
.servidor-status.verificando { background: var(--surface-hover); color: var(--body); }
.srv-check-dot {
    width: 8px; height: 8px; border-radius: 50%;
    border: 2px solid var(--mute);
    border-top-color: transparent;
    animation: girar 700ms linear infinite;
}
@keyframes girar { to { transform: rotate(360deg); } }

/* Nome próprio: havia dois @keyframes chamados `pulsar` com curvas diferentes,
   e o segundo (opacity .35) vencia para todo mundo — este esqueleto piscava
   bem mais forte do que o previsto. */
@keyframes pulsarSuave { 0%, 100% { opacity: .5; } 50% { opacity: .85; } }

@media (prefers-reduced-motion: reduce) {
    .srv-check-dot, .esq { animation: none; }
}

/* Esqueleto de carregamento: blocos no formato do conteúdo que vem, no
   lugar do "Carregando..." — a tela já nasce com a forma final e não
   salta quando os dados chegam. O tamanho vem do modificador. */
.esq {
    display: block;
    height: 12px;
    border-radius: var(--radius-sm);
    background: var(--surface-hover);
    animation: pulsarSuave 1.2s ease-in-out infinite;
}
.esq-curta { width: 40%; }
.esq-media { width: 60%; }
.esq-titulo { width: 160px; height: 18px; margin-bottom: var(--space-4); }
.esq-valor { width: 70%; height: 28px; }
.esq-grafico { height: 220px; border-radius: var(--radius-md); }
.esq-avatar { width: 36px; height: 36px; flex-shrink: 0; border-radius: var(--radius-full); }

/* Topo da tela de bancos */
.bancos-topo { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-4); }

/* Servidores, subaba "Todos": um bloco por sistema, com o nome e a contagem em
   cima dos cards — o título de seção do Painel. */
.srv-grupo + .srv-grupo { margin-top: var(--space-6); }
.srv-grupo-titulo {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: 0 0 var(--space-3);
    font-size: var(--fs-xs);
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--body);
}
.srv-grupo-titulo .painel-contagem { margin-left: 0; }

/* =====================================================================
   Tabela de drill-down — Pendências por tipo / Bancos / Filtros
   =====================================================================
   As três telas eram listas de largura total carregando um nome e um número:
   ~85% da tela vazia, e com todas as contagens iguais nenhuma pista de por
   onde começar. Viraram uma tabela só, com as colunas que o dado já permitia
   e que a lista descartava — o total do cliente e a quebra por tipo. */

.tab-pend-topo {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
    margin-bottom: var(--space-4);
    padding-bottom: var(--space-3);
    border-bottom: 0;
}
/* Sem regra própria, .tab-pend-titulo (um <h3>) caía no bold/tamanho padrão
   do navegador — mesmo problema do .tela-topo antes da consolidação: mesma
   escala de heading-sm, mesmo peso 600, mesmo ícone em --link. */
.tab-pend-titulo {
    margin: 0 0 var(--space-2);
    font-size: var(--fs-lg);
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--ink);
}
.tab-pend-titulo .icon { color: var(--link); vertical-align: -3px; margin-right: 4px; }
.tab-pend-topo .tipos-total { margin-bottom: 0; }

/* Banco sendo varrido antes de abrir: a linha para de aceitar clique e pisca. */
.tabela-pendencias tr.carregando { opacity: 0.6; pointer-events: none; animation: pulsar 1s ease-in-out infinite; }
@keyframes pulsar { 50% { opacity: 0.35; } }

.tabela-pendencias tbody tr { cursor: pointer; }
.tabela-pendencias tbody tr:focus-visible { outline: 2px solid var(--link); outline-offset: -2px; }

/* Cabeçalho ordenável: <button> dentro do <th>, não <th onclick> — só assim o
   teclado alcança e o leitor de tela anuncia como controle. */
.th-ordenar {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    color: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
    cursor: pointer;
    max-width: 100%;
    overflow: hidden;
}
.th-ordenar:hover { color: var(--ink); }
.th-ordenar:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; }
.tabela-pendencias th.ordenada .th-ordenar { color: var(--link); }

/* Número é o que se compara entre linhas: à direita e com algarismo de largura
   fixa, senão a coluna serrilha e os valores não se alinham. */
:is(.central-table, .hist-tabela) .col-num { text-align: right; font-variant-numeric: lining-nums tabular-nums; }
.tabela-pendencias td.col-num { font-weight: 500; }
.tabela-pendencias td.col-destaque { color: var(--ink); }
.tabela-pendencias .col-nome { font-weight: 600; }
.tabela-pendencias .col-srv { color: var(--body); font-size: var(--fs-xs); }
.col-srv-sis { color: var(--mute); }

/* Larguras: o nome e o número ficam perto (a coluna do nome esticava até o
   fim da tela e o total sobrava a 1000px do cliente, sem como seguir a linha
   com o olho); a distribuição toma o que sobra. */
.tabela-pendencias th:nth-child(1), .tabela-pendencias td:nth-child(1) { min-width: 200px; }
.tabela-pendencias .col-nome { width: 24%; max-width: 320px; }
.tabela-pendencias .col-srv { width: 16%; }
.tabela-pendencias th.col-num { width: 110px; }
/* 420px: abaixo disso o segundo rótulo da barra ("NF-e 124") saía cortado. */
.tabela-pendencias .col-dist { min-width: 420px; }

/* Lista longa: o cabeçalho e a contagem ficam à vista e só as linhas rolam. */
.tab-pend-corpo .central-table-wrap { max-height: calc(100vh - 370px); min-height: 240px; }

/* A linha inteira abre o banco: o hover vale para toda linha, não só as pares
   (a zebra tem a regra própria delas), e a seta diz que é clicável. */
.tabela-pendencias tbody tr:hover { background: var(--surface-hover); }
.tabela-pendencias .col-ir { width: 32px; padding-right: var(--space-3); text-align: right; color: transparent; }
.tabela-pendencias .col-ir .icon { width: 16px; height: 16px; vertical-align: middle; }
.tabela-pendencias tbody tr:hover .col-ir,
.tabela-pendencias tbody tr:focus-visible .col-ir { color: var(--link); }

/* Banco sem pendência: continua na lista, mas recua. */
.tabela-pendencias tr.sem-pendencia td:not(.col-ir) { color: var(--mute); }
.tabela-pendencias tr.sem-pendencia .col-nome,
.tabela-pendencias tr.sem-pendencia td.col-num { font-weight: 400; }

/* A barra é o ponto da tela: comprimento = total do cliente contra o maior
   total visível, segmentos = a quebra por tipo. É o que faz treze linhas de
   "1" virarem um ranking. Cor segue o TIPO, nunca a posição (DESIGN.md ## Colors). */
.dist-wrap { display: flex; align-items: center; gap: var(--space-2); }
td.col-dist { white-space: nowrap; }

.dist-track {
    flex: 0 0 40%;
    min-width: 60px;
    border-radius: var(--radius-full);
    background: color-mix(in srgb, var(--ink) 8%, transparent);
    overflow: hidden;
}
.dist-barra {
    display: flex;
    gap: 2px;                 /* vão na cor da superfície entre segmentos */
    height: 8px;
    min-width: 8px;
    border-radius: var(--radius-full);
    overflow: hidden;
}
.dist-seg {
    background: var(--seg, var(--link));
    min-width: 3px;           /* segmento pequeno continua visível */
}
.dist-rotulos { display: inline-flex; gap: var(--space-3); min-width: 0; overflow: hidden; }
/* Sem a caixa do chip: vinte e oito linhas de dois retângulos brilhantes
   competiam com a barra. O ponto de cor e o nome ficam, o número ganha o peso. */
.dist-rotulos .filtro-chip { padding: 0; background: transparent; font-weight: 400; color: var(--body); }
.dist-rotulos .filtro-chip b { font-weight: 500; color: var(--ink); font-variant-numeric: lining-nums tabular-nums; }
.dist-vazio { color: var(--mute); }
tr.sem-pendencia .dist-vazio { opacity: .6; }

.tab-pend-vazio { text-align: center; color: var(--body); padding: var(--space-6); }

/* =====================================================================
   Tela exclusiva de filtros
   ===================================================================== */
.filtros-wrap { display: flex; flex-direction: column; gap: 16px; }

/* A grade de cartões saiu com a tabela: cartão é para navegação visual, e aqui
   a tarefa é comparar número entre clientes. `.filtro-chip` fica — os rótulos
   da barra de distribuição o reaproveitam. */
/* Rótulo de série. O texto NÃO usa a cor da série: o passo de série é validado
   como objeto gráfico (3:1), e três deles ficam abaixo de 4.5:1 como texto — o
   amarelo em 2.17:1 sobre branco era o rótulo lavado do print. A identidade vem
   do ponto ao lado, o texto usa token de texto. */
.filtro-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: var(--fs-xs);
    font-weight: 600;
    padding: 2px 8px 2px 6px;
    border-radius: var(--radius);
    background: var(--surface-elevated);
    color: var(--ink);
    white-space: nowrap;
}
.filtro-chip::before {
    content: '';
    width: 8px;
    height: 8px;
    flex-shrink: 0;
    border-radius: var(--radius-full);
    background: var(--chip-color, var(--link));
}

.central-pend-spin {
    display: inline-block;
    width: 14px;
    height: 14px;
    border: 2px solid var(--hairline);
    border-top-color: var(--link);
    border-radius: 50%;
    animation: dashspin 0.7s linear infinite;
}
@keyframes dashspin { to { transform: rotate(360deg); } }

/* =====================================================================
   Superfícies de ação primária — assinatura da marca (DESIGN.md ## Colors)
   Fica ANTES do bloco Responsivo? Não: precisa vir depois das regras de
   componente para vencer a cascata, e antes das media queries de layout.
   ===================================================================== */


/* A variante fantasma do hero não é superfície primária */

/* =====================================================================
   Central — refinamentos de densidade e filtros (DESIGN.md ## Components)
   ===================================================================== */

/* ─── Chips de filtros ativos ─── */
/* Mora dentro da barra de contagem: sem faixa própria, sem quebra de linha e
   sem padding vertical — nada disso pode roubar altura da tabela. */
.central-chips-filtro {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: nowrap;
    padding: 0;
    min-width: 0;
}

/* No estado vazio os chips são filhos diretos do corpo (não há barra de
   contagem); ali podem quebrar linha à vontade. */
.central-body > .central-chips-filtro { flex-wrap: wrap; padding: var(--space-2) 0 var(--space-3); }

.central-chips-label {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: var(--fs-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--mute);
}
.central-chips-label .icon { width: 16px; height: 16px; }

.central-chip-filtro {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 6px 4px 10px;
    border-radius: var(--radius-sm);
    background: var(--fundo-info);
    border: 0;
    color: var(--link);
    font-size: var(--fs-xs);
    max-width: 260px;
}
.central-chip-filtro b { font-weight: 700; }
.central-chip-filtro > b + * { min-width: 0; }

.central-chip-filtro button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    padding: 0;
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    color: inherit;
    cursor: pointer;
    opacity: 0.7;
}
.central-chip-filtro button:hover {
    opacity: 1;
    background: color-mix(in srgb, var(--accent-blue-vivid) 25%, transparent);
}
.central-chip-filtro button .icon { width: 14px; height: 14px; }

.central-chips-limpar {
    border: none;
    background: transparent;
    color: var(--body);
    font-family: inherit;
    font-size: var(--fs-xs);
    font-weight: 600;
    text-decoration: underline;
    cursor: pointer;
    padding: 4px 6px;
    border-radius: var(--radius-sm);
}
.central-chips-limpar:hover { color: var(--accent-red); }

/* ─── Tabela: densidade e leitura ─── */
.central-table-wrap { overflow-x: auto; }

/* Coluna filtrada fica destacada para o filtro não passar despercebido */
.central-th-filter.filtrada {
    background: color-mix(in srgb, var(--accent-blue-vivid) 10%, var(--tabela-cabecalho));
    color: var(--link);
}
.central-th-ordem {
    display: inline-flex;
    vertical-align: -2px;
    margin-left: 2px;
    color: var(--link);
}
.central-th-ordem .icon { width: 14px; height: 14px; }

/* Hierarquia: o nome é o ponto de entrada visual da linha */
.central-col-cliente { max-width: 260px; }
.central-cliente-nome {
    font-weight: 700;
    color: var(--ink);
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: bottom;
}
/* Nome longo encolhe com reticências e os selos seguem à vista (sem o flex, o nome inteiro virava "…"). */
.central-cliente-cel { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.central-cliente-cel > * { flex: none; margin: 0; }
.central-cliente-cel > .central-cliente-nome { flex: 0 1 auto; min-width: 0; }
.central-col-razao {
    max-width: 260px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--body);
}
.central-col-pendencias { text-align: center; }

/* A coluna Contadores (8ª de Clientes) traz nomes longos com telefone; sem teto
   ela empurra a de status, a mais consultada, para fora da tela.
   Escopado em `.tabela-clientes`: solto em `.central-table` pegava a 8ª coluna
   de QUALQUER tabela do app — e a aba Contadores, que o comentário parecia
   citar, tem só cinco colunas, então nunca foi ela. */
.central-table.tabela-clientes td:nth-child(8) {
    max-width: 200px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.central-table.tabela-clientes td:nth-child(8) .central-chip {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: bottom;
}

.central-count {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: var(--space-3) var(--space-1);
    font-size: var(--fs-xs);
    color: var(--body);
}
.central-count-total { color: var(--mute); }

/* ─── Estado vazio ─── */
.central-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
    text-align: center;
    padding: 60px 20px;
    color: var(--body);
}
.central-empty-ico {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    border-radius: var(--radius-full);
    background: var(--surface-elevated);
    color: var(--mute);
}
.central-empty-ico .icon { width: 24px; height: 24px; }
.central-empty p { margin: 0; }

/* ─── Botão de ações da linha (o menu de contexto tambem responde ao
       botao direito, mantido para quem ja tem o habito) ─── */
/* Fixa à direita: com 10 colunas a tabela rola, e o botão de ações precisa
   continuar alcançável sem rolar até o fim. */
.central-th-acoes, .central-col-acoes {
    width: 46px;
    min-width: 46px;
    text-align: center;
    position: sticky;
    right: 0;
    background: var(--surface-card);
    border-left: 0;
}
.central-th-acoes { z-index: calc(var(--z-sticky) + 1); }
.central-col-acoes { z-index: 1; }
.central-row:hover .central-col-acoes { background: var(--surface-hover); }
/* Atenção (pulsa) e observação têm fundo opaco na linha: a célula fixa herda e acompanha até o pulso. */
.central-row:is(.central-atencao, .central-row-obs) .central-col-acoes,
.central-row:is(.central-atencao, .central-row-obs):hover .central-col-acoes { background: inherit; }

.central-row-menu {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-sm);
    border: 0;
    background: transparent;
    color: var(--mute);
    cursor: pointer;
    font-family: inherit;
    opacity: 0.55;
}
.central-row:hover .central-row-menu { opacity: 1; }
.central-row-menu:hover,
.central-row-menu:focus-visible {
    opacity: 1;
    background: var(--surface-hover);
    color: var(--link);
}
.central-row-menu .icon { width: 18px; height: 18px; }

/* Excluir contador reaproveita o botão de linha; a aparência de perigo é a do
   vocabulário de botões (`.perigo`) — não fica azul no hover como o "..." ao lado. */

/* Base de todo <h2> sem regra própria — o padrão do navegador é 1.5em. */
h2 { font-size: var(--fs-h2); }

.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* =====================================================================
   Home — escala desktop-first (1920x1080)
   Medido: a versao anterior gerava 1376px de conteudo num viewport util de
   838px (538px de rolagem so para ver o dashboard). Os tamanhos abaixo sao
   escopados em .dash para nao encolher as outras telas.
   ===================================================================== */
.dash { gap: var(--space-4); }

/* Hero */
.dash .hero-content { padding: var(--space-4) var(--space-5); gap: var(--space-3); }

/* KPIs — as telas de detalhe (.tela-detalhe) usam a mesma escala: é o mesmo
   card, e em tamanho diferente pareceria outro. */
.dash .kpi-row { gap: var(--space-3); }
.dash .kpi-card, .tela-detalhe .kpi-card { padding: var(--space-4); gap: var(--space-2); justify-content: flex-start; min-height: 0; }
.dash .kpi-ico, .tela-detalhe .kpi-ico { width: 28px; height: 28px; }
.dash .kpi-ico .icon, .tela-detalhe .kpi-ico .icon { width: 17px; height: 17px; }
.dash .kpi-label, .tela-detalhe .kpi-label { font-size: var(--fs-xs); }
.dash .kpi-val, .tela-detalhe .kpi-val { font-size: 28px; }
.dash .kpi-foot, .tela-detalhe .kpi-foot { min-height: 14px; }
/* Valor em frase ("OK", "Não verificado"): texto, não cifra de 28px. */
.kpi-val.kpi-val-txt { font-size: var(--fs-md); font-weight: 600; line-height: 1.3; letter-spacing: 0; }

/* Paineis e graficos */
.dash .panel-card, .tela-detalhe .panel-card { padding: var(--space-4); }
.dash .panel-card h3, .tela-detalhe .panel-card h3 { margin-bottom: var(--space-3); font-size: var(--fs-xs); }
.dash .chart-wrap { min-height: 190px; }
.dash .chart-wrap-lg { min-height: 225px; }

/* Grades e timeline */
.dash .dash-corpo { gap: var(--space-4); }
.dash .tl-item { padding: 5px 0; }
.dash .tl-dot { width: 26px; height: 26px; }
.dash .tl-dot .icon { width: 15px; height: 15px; }

/* Uma frase que precisa de linha propria — o que a tela NAO faz naquele
   servidor, e por que. */
.aviso-bloco {
    margin-bottom: var(--space-3);
}

/* =====================================================================
   Movimento — microinteracoes (DESIGN.md ## Responsive Behavior, ## Do's and Don'ts)
   O arquivo ja tinha 81 transicoes e 32 keyframes, mas 128 `:hover` contra
   UM `:active`: a interface reagia ao mouse passando por cima e nao ao
   clique. O que faltava nao era mais animacao, era resposta nos dois
   momentos em que o usuario age — quando ele aperta, e quando a tela troca.
   Tudo aqui usa os tokens de duracao da ## Typography e morre no bloco de
   prefers-reduced-motion no fim desta secao.
   ===================================================================== */

/* ─── Apertar ───
   Apertado responde com COR, nunca com tamanho. Encolher — foi assim que isto
   nasceu, `scale(0.97)` — muda a geometria da tela sob o dedo: numa barra de
   acoes o vizinho parece pular, e em clique repetido (selecionar banco atras de
   banco) a pagina inteira treme. Cor confirma o mesmo clique sem mexer nada de
   lugar, e e' o que ja se faz no hover destes botoes (brightness).

   Vale para tudo que se clica: nenhum elemento fica menor ao ser apertado.

   O `!important` e' de proposito, e e' o unico jeito honesto: os botoes que
   mais se clicam (.btn-primary, .btn-danger, .export-btn.primary, as buscas de
   NCM) trazem `filter` no proprio :hover, com seletor de classe — e apertar
   acontece sempre COM o mouse em cima. Sem ele, o hover ganharia justamente
   nos botoes onde o retorno mais importa. Nada mais no arquivo poe filter em
   :active, entao nao ha o que este important atropele. */
/* `.icon-btn` entra junto porque duas ocorrencias sao <a> (baixar arquivo):
   parecem botao, tem de responder como botao. */
button, .icon-btn {
    transition: filter var(--dur-fast) var(--ease-std);
}
button:active:not(:disabled),
.icon-btn:active:not(:disabled) {
    filter: brightness(0.90) !important;
}
/* No escuro, escurecer some: um botao #292929 fica #252525. O passo tem de ser
   para o outro lado. */
html[data-theme="dark"] button:active:not(:disabled),
html[data-theme="dark"] .icon-btn:active:not(:disabled) {
    filter: brightness(1.20) !important;
}
/* `[role="button"]` NAO entra aqui. As duas unicas ocorrencias no projeto sao
   linhas de lista — .bank-item e .filial-item, da tela de exportar. Elas ja
   respondem por fundo e borda no .checked, que e' o feedback certo para
   selecao. */

/* ─── Trocar de tela ───
   Toda tela e' escrita por telaBody() (app.js), que aplica `.tela-entra` uma
   vez por navegacao. Sem isto a troca de tela era um corte seco: o conteudo
   inteiro trocava no mesmo quadro. 6px, nao mais — deslocamento grande num
   painel de trabalho vira espera.

   Anima so tela NOVA. Voltar para uma aba aberta, ou apertar Voltar, redesenha
   uma tela que a pessoa ja tinha visto: reanimar ali fazia toda ida e volta
   entre abas parecer recarregamento (quem cuida disso e' o entrarNaTela).
   Pela mesma razao a Home perdeu a entrada em cascata dos seis blocos: era a
   tela mais visitada do app, e a cascata rodava inteira a cada visita. */
.tela-entra { animation: telaEntra var(--dur-base) var(--ease-std); }
@keyframes telaEntra {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
}

/* ─── Linha de tabela ───
   O hover ja existia; faltava a transicao, entao a faixa acendia e apagava
   de um quadro para o outro. */
.central-table tbody tr,
.data-table tbody tr {
    transition: background var(--dur-fast) var(--ease-std);
}

/* ─── Desligar tudo ───
   Os seis blocos de reduced-motion espalhados pelo arquivo cobrem um item
   cada. Este cobre o resto, inclusive o que for adicionado depois — e' a
   unica forma de a regra nao apodrecer. */
@media (prefers-reduced-motion: reduce) {
    /* O apertado nao entra aqui: mudar de cor nao e' movimento, e' justamente
       o retorno que sobra para quem pediu menos movimento. */
    .tela-entra { animation: none; }
}

/* =====================================================================
   Responsivo — DEVE permanecer no fim do arquivo (DESIGN.md ## Layout)
   ===================================================================== */
@media (max-width: 1000px) {
    /* Três e quatro colunas ficam apertadas antes do celular: "Validade do
       certificado" quebrava o rótulo e o dropdown de Sistema truncava em
       "Selecion...". Duas colunas até o colapso de 768px (abaixo), que já
       empilha tudo numa só. */
    .dlg-grade-3, .cli-ficha .dlg-grade-fiscal { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 1100px) {
    /* Sem largura para três colunas: tudo empilha na ordem de leitura. */
    .dash-corpo-pend, .dash-corpo-xml {
        /* minmax(0, …): com `1fr` a coluna crescia até o conteúdo mais largo
           (o canvas, a legenda) e a página vazava para a direita no celular. */
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: auto;
    }
    .dash-corpo-pend { grid-template-areas: "atencao" "tipos" "ranking"; }
    .dash-corpo-xml { grid-template-areas: "fech" "kpis" "envios" "clientes" "atividade"; }
    .area-atividade { max-height: 420px; }
    .dash-corpo .kpi-row { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
    .dash-corpo-xml .kpi-row > :first-child { grid-row: auto; }
    /* Os dois cards numa linha, o painel de dados na de baixo. */
    .detalhe-corpo { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .detalhe-corpo > .panel-card { grid-column: 1 / -1; }
    /* Página do cliente: um card por linha; o resumo desce para baixo da ficha. */
    .cli-grade, .cli-geral { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 768px) {
    .topbar { flex-wrap: wrap; height: auto; padding: 10px 12px; gap: 10px; }
    /* Cabeçalho de tela: sem quebra, o título era espremido até "SE…" entre o
       Voltar e as ações. Quebrando, cada peça desce inteira para a linha de baixo. */
    .tela-topo { flex-wrap: wrap; }
    .tela-topo-esq { flex-wrap: wrap; row-gap: var(--space-3); }
    /* O logo do sistema sobrava sozinho ao lado do Voltar; o subtítulo já diz o sistema. */
    .tela-topo-esq > .servidores-card-icon { display: none; }
    /* Quatro ações (página do cliente) não cabem numa linha de 390px: o grupo
       encolhe até a largura da tela e as ações quebram linha. */
    .tela-topo-dir { flex-wrap: wrap; flex-shrink: 1; }
    /* As subabas do cliente rolam de lado em vez de vazar da página. O par de
       classes vence o .central-tabs, que vem depois deste bloco no arquivo. */
    .central-tabs.cli-subabas { display: flex; overflow-x: auto; }
    /* Hora e download descem para baixo do texto do evento. */
    .cli-evento { grid-template-columns: 32px minmax(0, 1fr); }
    .cli-evento-lado { grid-column: 2; }
    .menubar { padding: 0 12px; }
    .brand { flex: 0 0 auto; }
    .brand-logo-long { height: 24px; }
    .header-actions { flex: 1; flex-wrap: nowrap; justify-content: flex-end; }
    .main-body { --main-body-topo: 18px; padding: var(--main-body-topo); }
    .servidores-filterbar { flex-direction: column; align-items: stretch; }
    .servidores-filterbar .filtro-select,
    .servidores-filterbar .filtro-buscar { width: 100%; }
    .chart-wrap { height: 220px; }

    .ncm-compare-container { flex-direction: column; }
    .ncm-compare-arrow { transform: rotate(90deg); justify-content: center; padding: 8px 0; }
    .ncm-action-buttons { flex-direction: column; }
    .ncm-btn {
 min-width: unset; 
}

    .toast-container { top: auto; bottom: var(--space-4); left: var(--space-4); right: var(--space-4); }
    /* No celular o container ocupa a largura toda; o teto de 380px deixaria o
       toast estreito e encostado à esquerda. */
    .toast { max-width: none; }

    /* Ficha em coluna única; o rodapé quebra em vez de espremer os botões. */
    .dlg-grade, .dlg-grade-3, .cli-ficha .dlg-grade-fiscal { grid-template-columns: 1fr; }
    .dlg-cabeca, .dlg-corpo, .dlg-rodape { padding-left: var(--space-4); padding-right: var(--space-4); }
    .dlg-rodape { flex-wrap: wrap; }
}

@media (max-width: 480px) {
    .central-filter-dropdown {
        left: 8px !important;
        right: 8px !important;
        max-width: calc(100vw - 16px);
        width: auto;
    }
    .header-actions .status-label { display: none; } .kpi-row { grid-template-columns: 1fr; }
    /* "R$ 129.499,81" em 28px não cabe em meia largura de celular. */
    .detalhe-corpo { grid-template-columns: minmax(0, 1fr); }
    .hero-content { padding: var(--space-5); }
    .hero-actions { width: 100%; }
    .btn-hero {
 flex: 1; justify-content: center; 
}
}

/* Indicador de exportação já concluída: fica no topo até o usuário encerrar,
   sem o pulso de "em andamento" para não parecer que ainda está rodando. */

/* ── Caixas de e-mail ───────────────────────────────────────────────────────
   A ORDEM da lista e' a ordem do rodizio: a primeira com folga e' a que envia.
   Por isso o numero a esquerda, e por isso a caixa sem folga fica apagada em
   vez de sumir — some da lista quem foi excluido, nao quem encheu hoje. */
.caixas-lista { display: flex; flex-direction: column; gap: var(--space-2); }
.caixa-item {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 10px 12px;
    background: var(--surface-card);
    border: 0;
    border-radius: var(--radius-md);
}
.caixa-indisponivel { opacity: .62; }
.caixa-ordem {
    flex: 0 0 24px;
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    background: var(--surface-elevated);
    color: var(--body);
    font-size: var(--fs-xs);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.caixa-dados { flex: 1 1 auto; min-width: 0; }
.caixa-nome {
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--ink);
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}
.caixa-sub {
    font-size: var(--fs-xs);
    color: var(--body);
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}
.caixa-host { color: var(--mute); font-variant-numeric: tabular-nums; }
/* Tipos de pendência. Uma coluna de caixas, não uma grade: são sete itens e a
   ordem importa (é a mesma do PEND_TIPOS e a mesma do filtro da grid). */
.config-pend-lista {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    border: 0;
    border-radius: var(--radius-lg);
    padding: var(--space-3);
    background: var(--surface-card);
}
.config-pend-item {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-md);
    cursor: pointer;
    font-size: var(--fs-sm);
}
.config-pend-item:hover { background: var(--surface-elevated); }

.caixa-marca {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .03em;
    padding: 1px 6px;
    border-radius: var(--radius-sm);
    background: var(--surface-elevated);
    color: var(--body);
}
.caixa-marca.em-uso { background: var(--fundo-ok); color: var(--accent-green); }
.caixa-marca.cheia { background: var(--fundo-aviso); color: var(--accent-orange); }
.caixa-uso {
    flex: 0 0 auto;
    font-size: var(--fs-xs);
    color: var(--body);
    font-variant-numeric: tabular-nums;
}
.caixa-uso.quase { color: var(--accent-orange); font-weight: 600; }
.caixa-uso.cheia { color: var(--accent-red); font-weight: 600; }
.caixa-acoes { flex: 0 0 auto; display: flex; gap: 4px; }

.caixa-form {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3);
    padding: var(--space-4) var(--space-5);
}
.caixa-form .field.full { grid-column: 1 / -1; }
.caixa-check {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: var(--fs-sm);
    color: var(--ink);
}
.caixa-resultado { padding: 0 var(--space-5); font-size: var(--fs-xs); }
.caixa-resultado:not(:empty) { padding-bottom: var(--space-3); }

@media (max-width: 700px) {
    .caixa-form { grid-template-columns: 1fr; }
    .caixa-item { flex-wrap: wrap; }
}

/* Vigência na lista de NCM — DESIGN.md (## Dashboard). A regra de base é a
   maioria das linhas e não precisa gritar; a futura precisa, porque é a que
   alguém cadastrou para depois e vai querer conferir. */
.cclass-vig-base { color: var(--ash); font-size: var(--fs-xs); }

.cclass-vig {
    font-variant-numeric: tabular-nums;
    font-size: var(--fs-xs);
    color: var(--body);
}

/* Herda o `badge-pill` do documento e só troca a tinta. */
.cclass-vig.futura { background: var(--fundo-aviso); color: var(--accent-orange); }

.field-dica {
    display: block;
    margin-top: var(--space-1);
    font-size: var(--fs-xs);
    color: var(--accent-orange);
}


/* =====================================================================
   badge-pill — componente do DESIGN.md (## Components → Signature)
   "backgroundColor: surface-elevated, textColor: body, typography: caption,
   rounded: full, padding: 4px 10px". Existia disperso em meia dúzia de
   classes que reimplementavam a mesma pílula; agora é uma só.
   ===================================================================== */
.badge-pill {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 4px 10px;
    border-radius: var(--radius-full);
    background: var(--surface-elevated);
    color: var(--body);
    font-size: var(--fs-xs);
    white-space: nowrap;
}

/* =====================================================================
   Modal de NCM — as classes que substituem os `style=` inline
   Eram 12 estilos escritos no markup, com grid, gap e tipografia cravados.
   A guarda de estilo só barra COR literal num `style=`, então tamanho e
   espaçamento passavam batido — e era o que fazia o modal ter uma segunda
   escala, destoando do resto mesmo com as cores certas.
   ===================================================================== */
.ncm-grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-2); }
.ncm-grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-2); margin-top: var(--space-2); }

/* Rótulo de seção dentro do modal: é o `caption` do documento, igual ao label
   de campo — não uma terceira variante. */
.ncm-secao-rotulo {
    display: block;
    font-size: var(--fs-xs);
    font-weight: 500;
    color: var(--charcoal);
    text-transform: uppercase;
    letter-spacing: .04em;
    margin-bottom: var(--space-1);
}

.ncm-secao { margin: var(--space-3) 0 var(--space-1); }
.ncm-ajuda { font-size: var(--fs-xs); color: var(--charcoal); margin-bottom: var(--space-3); }
.ncm-avancado {
    display: none;
    margin-top: var(--space-3);
    border-top: 0;
    padding-top: var(--space-3);
}
/* NCM, cClassTrib e CEST são códigos: fonte de código, como o documento manda
   ("Geist Mono — used in code wells"). Era `font-family:monospace` no markup. */
.ncm-codigo { font-variant-numeric: tabular-nums; }

/* =====================================================================
   BOTÕES — vocabulário único
   ver DESIGN.md (## Components → Buttons) e (## Dashboard)

   Havia 39 classes de botão, e ~200 declarações repetidas entre elas: padding
   em quatro variantes (8/16, 10/18, 11/16, 10/20), peso em 500, 600 e 700,
   `transition: all` em três durações, e `.export-btn` definido duas vezes com
   valores diferentes. Cada tela tinha o seu botão.

   O documento define TRÊS aparências. As outras duas aqui são derivação
   declarada, porque um painel tem controle que a vitrine não tem:

     .btn-primary    o retângulo âncora — branco no escuro, preto no claro.
                     "One per viewport at most": é o CTA, não o botão comum.
     .btn-secondary  ghost: superfície um degrau acima + hairline. O botão
                     de trabalho, o mais comum da tela.
     .btn-outline    canvas + hairline. Ação terciária.
     .btn-plain      DERIVADO: sem fundo e sem borda. Controle DENTRO de outra
                     peça — ordenar coluna, abrir menu de linha, alternar aba.
                     Não é CTA e não pode competir com o conteúdo da tabela.
     .btn-danger     DERIVADO: destrutivo. Existe porque excluir precisa ser
                     distinguível antes do clique, não só no diálogo.

   Modificadores: .btn-small (denso) e .icon-btn (quadrado, só ícone).

   As classes antigas continuam valendo como APELIDO da aparência que já
   tinham — trocar 27 nomes espalhados por 13 mil linhas de JS seria um diff
   sem revisão possível, e o ganho é o mesmo.
   ===================================================================== */

/* ── A base que TODO botão compartilha ─────────────────────────────────── */
.btn-primary, .btn-confirm, .btn-hero, .login-btn,
.cclass-search-btn, .ncm-search-btn, .ncm-manual-search-btn, .ncm-master-btn,
.ncm-btn-yes, .ncm-master-apply-btn, .filtro-buscar,
.btn-secondary, .btn-cancel, .btn-outline,
.export-btn, .export-active-btn, .branch-btn,
.mode-toggle-btn, .icon-btn, .xmlfalta-btn, .ncm-btn, .back-btn,
.ncm-btn-no, .ncm-btn-search, .central-toolbar-filter, .sync-active-btn,
.btn-plain, .central-filter-btn, .central-select-btn,
.btn-danger, .bell-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    /* Via token: é esta a regra que o Modo compacto encolhe (ver o fim do
       arquivo) — ela é quem vence a cascata para a lista inteira acima. */
    padding: var(--btn-pad);
    min-height: var(--btn-min-h);
    border: 0;
    border-radius: var(--radius-md);
    font-family: var(--font-ui);
    font-size: var(--btn-fs);
    font-weight: 500;
    line-height: 1.43;
    white-space: nowrap;
    cursor: pointer;
    /* Nunca `transition: all`: ela anima também largura e altura, e um botão
       que muda de tamanho ao passar o mouse empurra o vizinho. */
    transition: background var(--dur-fast) var(--ease-std),
                border-color var(--dur-fast) var(--ease-std),
                color var(--dur-fast) var(--ease-std);
}

/* ── 1. Primária: o pixel mais forte da tela ───────────────────────────── */
.btn-primary, .btn-confirm, .btn-hero, .login-btn:not(.login-btn-sso),
.cclass-search-btn, .ncm-search-btn, .ncm-manual-search-btn, .ncm-master-btn,
.ncm-btn-yes, .ncm-master-apply-btn, .filtro-buscar, .export-btn.primary {
    background: var(--primary);
    color: var(--primary-on);
}
.btn-primary:hover, .btn-confirm:hover, .btn-hero:hover, .login-btn:not(.login-btn-sso):hover,
.cclass-search-btn:hover, .ncm-search-btn:hover, .ncm-manual-search-btn:hover,
.ncm-master-btn:hover, .ncm-btn-yes:hover, .ncm-master-apply-btn:hover,
.filtro-buscar:hover, .export-btn.primary:hover {
    background: var(--primary-hover);
    color: var(--primary-on);
}
.btn-primary:active, .btn-confirm:active, .btn-hero:active, .login-btn:not(.login-btn-sso):active,
.filtro-buscar:active, .export-btn.primary:active {
    background: var(--primary-pressed);
}

/* ── 2. Secundária (ghost): o botão de trabalho ────────────────────────── */
/* .btn-hero.ghost vem aqui explicitamente: sem isto, a primária da mesma
   classe .btn-hero ganharia pela ordem. .central-toolbar-filter (Regime,
   Vínculo...) abre um menu — é secundária com seta, não uma quarta casca. */
.btn-secondary, .btn-cancel,
.export-btn, .export-active-btn, .branch-btn,
.mode-toggle-btn, .icon-btn, .xmlfalta-btn, .ncm-btn, .back-btn,
.ncm-btn-no, .ncm-btn-search, .central-toolbar-filter, .btn-hero.ghost,
.sync-active-btn {
    /* Sem borda, o fundo é que desenha o botão — e um token opaco sumia
       dentro do modal, que tem o mesmo fundo. */
    background: var(--preenchimento);
    color: var(--ink);
}
.btn-secondary:hover, .btn-cancel:hover,
.export-btn:hover, .export-active-btn:hover, .branch-btn:hover,
.mode-toggle-btn:hover, .icon-btn:hover,
.xmlfalta-btn:hover, .ncm-btn:hover, .back-btn:hover,
.ncm-btn-no:hover, .ncm-btn-search:hover, .central-toolbar-filter:hover,
.btn-hero.ghost:hover, .sync-active-btn:hover {
    background: var(--preenchimento-hover);
    color: var(--ink);
}

/* ── 3. Outline: terciária ─────────────────────────────────────────────── */
/* Sem borda não existe "contorno": vira o mesmo preenchimento da secundária. */
.btn-outline {
    background: var(--preenchimento);
    color: var(--ink);
}
.btn-outline:hover { background: var(--preenchimento-hover); }

/* ── 4. Plain (derivado): controle dentro de outra peça ────────────────── */
.btn-plain {
    background: transparent;
    color: var(--body);
    /* Mais baixo que os outros: ele mora dentro de barra de filtro, onde 36px
       empurra a linha inteira. */
    min-height: 28px;
    padding: 4px 8px;
}
/* A seta de filtro do cabeçalho de tabela: menor e mais apagada que o rótulo ao lado. */
.central-filter-btn {
    background: transparent;
    color: var(--mute);
    min-height: 0;
    padding: 2px;
}
.central-filter-btn .icon { width: 14px; height: 14px; }
.btn-plain:hover, .central-filter-btn:hover {
    background: var(--surface-hover);
    color: var(--ink);
}
/* Atalho de seleção ("Todos"/"Nada" dos filtros): tem de parecer botão em
   repouso. Na lista do "plain" ele ficava transparente e sem borda — só o
   hover mostrava que havia um botão ali. */
.central-select-btn {
    background: var(--preenchimento);
    color: var(--ink);
    min-height: 28px;
    padding: 4px 8px;
}
.central-select-btn:hover { background: var(--preenchimento-hover); }

/* ── 5. Perigo (derivado): destrutivo — UM estilo só ───────────────────────
   Excluir, remover, desvincular, desconectar, mover para a lixeira: todo botão
   que desfaz algo tem a MESMA cara, seja ícone numa linha, botão de cabeçalho
   ou confirmação de diálogo. Eram sete: vermelho cheio (.btn-danger,
   .btn-confirm.perigo, .export-btn.perigo), texto vermelho na casca da
   secundária, texto vermelho solto (.dlg-perigo) e cinza que só avermelhava no
   hover (.btn-plain.perigo, o Excluir da linha de contador).

   Repouso: a tinta de erro dos badges (--fundo-erro + --accent-red, medida em
   "erro sobre tinta" no contraste.check.js) — distinguível ANTES do clique, sem
   o peso do vermelho cheio numa tela onde quase nunca se exclui nada. Hover: o
   vermelho cheio, o "vai mesmo apagar" quando a mão já está em cima.
   Tamanho e formato vêm da classe-base (.icon-btn, .btn-small...); o modificador
   é sempre `.perigo`. Classe-base nova com `.perigo` entra nas DUAS listas —
   o botoes.check.js cobra. */
.btn-danger, .btn-confirm.perigo, .export-btn.perigo, .btn-plain.perigo,
.btn-secondary.perigo, .central-row-menu.perigo {
    background: var(--fundo-erro);
    color: var(--accent-red);
}
.btn-danger:hover, .btn-confirm.perigo:hover, .export-btn.perigo:hover, .btn-plain.perigo:hover,
.btn-secondary.perigo:hover, .central-row-menu.perigo:hover {
    background: var(--accent-red-vivid);
    color: var(--on-red);
}

/* ── Estado "aplicado": filtro ligado ─────────────────────────────────────
   Não é o escolhido de um grupo (esse é o controle segmentado, na cor de
   ação): é o botão que diz "há um filtro valendo aqui". Tinta, para não
   competir com a primária da mesma barra. */
.central-toolbar-filter.active, .central-toolbar-filter.active:hover,
.central-filter-btn.active, .central-filter-btn.active:hover {
    background: var(--fundo-info);
    color: var(--link);
}
.central-toolbar-filter.active .central-filtro-seta { color: var(--link); }

/* ── Tinta semântica: a escolha que carrega um significado ────────────────
   "Incluir" (dá certo), "ignorar" (perde algo), "liberar" (atenção). Não é
   CTA nem destrutivo: fundo --fundo-* e texto --accent-*, o mesmo par dos
   badges de estado. */
.xmlfalta-btn.incluir { background: var(--fundo-ok); color: var(--accent-green); }
.xmlfalta-btn.incluir:hover { background: color-mix(in srgb, var(--accent-green-vivid) 22%, transparent); }
.xmlfalta-btn.ignorar { background: var(--fundo-erro); color: var(--accent-red); }
.xmlfalta-btn.ignorar:hover { background: color-mix(in srgb, var(--accent-red-vivid) 22%, transparent); }
.btn-outline.bank-liberar { background: var(--fundo-aviso); color: var(--accent-orange); }
.btn-outline.bank-liberar:hover { background: color-mix(in srgb, var(--accent-orange-vivid) 22%, transparent); }
/* As duas pílulas de progresso do topo: exportação e sincronização de NCM. */
.export-active-btn.concluido, .sync-active-btn[data-status="done"] { background: var(--fundo-ok); color: var(--ink); }
.export-active-btn.concluido .ind-ico, .sync-active-btn[data-status="done"] .icon { color: var(--accent-green); }
.export-active-btn.parcial, .sync-active-btn[data-status="syncing"] { background: var(--fundo-aviso); color: var(--ink); }
.export-active-btn.parcial .ind-ico, .sync-active-btn[data-status="syncing"] .icon { color: var(--accent-orange); }
/* A busca de NCM e de cClassTrib, linha a linha: buscando (aviso), achou e
   aplicado (ok), não achou (neutro). Eram laranja e verde SÓLIDOS, os únicos
   botões de estado da aplicação pintados assim. */
.ncm-search-btn.searching, .cclass-search-btn.searching {
    background: var(--fundo-aviso);
    color: var(--ink);
    animation: pulse 1.5s infinite;
}
.ncm-search-btn.searching .icon, .cclass-search-btn.searching .icon { color: var(--accent-orange); }
.ncm-search-btn.found, .cclass-search-btn.found { background: var(--fundo-ok); color: var(--ink); }
.ncm-search-btn.found:hover, .cclass-search-btn.found:hover {
    background: color-mix(in srgb, var(--accent-green-vivid) 22%, transparent);
    color: var(--ink);
}
.ncm-search-btn.found .icon, .cclass-search-btn.found .icon,
.ncm-search-btn.applied .icon, .cclass-search-btn.applied .icon { color: var(--accent-green); }
.ncm-search-btn.notfound, .cclass-search-btn.notfound,
.ncm-search-btn.applied, .cclass-search-btn.applied {
    background: var(--preenchimento);
    color: var(--body);
}
.ncm-search-btn.notfound:hover, .cclass-search-btn.notfound:hover,
.ncm-search-btn.applied:hover, .cclass-search-btn.applied:hover {
    background: var(--preenchimento-hover);
    color: var(--body);
}
.ncm-search-btn.applied, .cclass-search-btn.applied { opacity: .7; }

/* ── Modificadores ─────────────────────────────────────────────────────── */
.btn-small {
    min-height: 28px;
    padding: 4px 12px;
    font-size: var(--fs-xs);
}

/* Só ícone: quadrado. Sem isto o padding lateral deixa o ícone deslocado
   dentro de uma área larga demais para o que ele é. Via token (--icon-btn-w):
   sem ele, o modo compacto encolhe a ALTURA (--btn-min-h) e não a largura, e
   o botão vira um retângulo em vez de continuar quadrado. */
.icon-btn {
    width: var(--icon-btn-w);
    gap: 0;
}
.icon-btn.btn-small { width: 28px; }
/* Entrar: a altura e a fonte do campo de login (vocabulário de campos). */
.login-btn { min-height: 48px; font-size: var(--fs-md); }

/* Na linha de um campo de formulário: a altura do campo (40px, vocabulário de
   campos). Sem isto o botão fica mais baixo que o campo do lado. */
.dlg-inline > .btn-primary, .dlg-inline > .btn-secondary,
.cert-form .btn-primary, .cert-form .btn-secondary, .cert-form-acoes > .btn-plain,
.portal-daterange .btn-primary, .cclass-modelo-acoes .icon-btn { min-height: 40px; }

/* ── Desabilitado, igual para todos ────────────────────────────────────── */
.btn-primary:disabled, .btn-confirm:disabled, .btn-secondary:disabled,
.btn-cancel:disabled, .btn-danger:disabled, .export-btn:disabled,
.btn-outline:disabled, .btn-hero:disabled, .login-btn:disabled,
.filtro-buscar:disabled, .ncm-master-btn:disabled, .ncm-search-btn:disabled,
.cclass-search-btn:disabled, .icon-btn:disabled, .central-toolbar-filter:disabled,
.btn-plain:disabled {
    opacity: .5;
    cursor: not-allowed;
    /* Travado tem de PARECER travado: sem o cinza, o Excluir vermelho
       continuava convidativo sem aceitar clique. Era só no rodapé de modal. */
    filter: grayscale(.7);
}

/* Foco: obrigatório, e ainda mais depois de a borda em repouso ter caído para
   1.35:1 pela decisão registrada no topo deste arquivo. */
.btn-primary:focus-visible, .btn-confirm:focus-visible,
.btn-secondary:focus-visible, .btn-cancel:focus-visible,
.btn-danger:focus-visible, .export-btn:focus-visible,
.btn-outline:focus-visible, .btn-plain:focus-visible,
.icon-btn:focus-visible, .btn-hero:focus-visible, .login-btn:focus-visible,
.filtro-buscar:focus-visible, .central-toolbar-filter:focus-visible,
.central-filter-btn:focus-visible, .central-select-btn:focus-visible {
    outline: 2px solid var(--ink);
    outline-offset: 2px;
}

/* FIM DO VOCABULÁRIO DE BOTÕES — o botoes.check.js lê só até aqui.
   Sem esta marca o bloco ia até o fim do arquivo, e qualquer regra nova
   acrescentada depois entrava no vocabulário sozinha: um botão com aparência
   própria colado no fim do style.css passava batido. */

/* =====================================================================
   CAMPOS — vocabulário único
   (2026-09-23) Havia 14 aparências para "campo": borda --hairline (6%) num
   e --hairline-strong (14%) no vizinho, fundo --surface-card num e
   --surface-flutuante no outro, altura de 30 a 40px, fonte de 12 ou 14px,
   anel de foco em três intensidades. Na barra de Exportar XML a busca e o
   select lado a lado tinham bordas de força diferente — o select parecia
   desabilitado.

   Uma aparência, dois tamanhos:
     formulário   40px, --fs-sm — modal, ficha, cadastro, login.
     barra        --btn-min-h, --btn-fs — divide a barra de ferramentas com
                  os botões: mesma altura, e encolhe junto no Modo compacto.

   Campo é a ÚNICA peça com borda (decisão 3, no topo). Fundo
   --surface-flutuante: no modal fica rente ao fundo e a borda desenha o
   campo; na página o campo claro se destaca do painel.

   As classes antigas continuam valendo como APELIDO, igual ao vocabulário
   de botões — layout (largura, margem) segue na regra de cada tela; aparência,
   só aqui. O campos.check.js lê este bloco até a marca de fim.
   ===================================================================== */

/* ── A aparência que todo campo compartilha ─────────────────────────── */
.field input, .field select, .field textarea,
.dlg-campo > input, .dlg-campo > select, .dlg-campo > textarea,
.login-campo input,
.central-atencao-modal textarea, .central-atencao-modal input[type="date"],
.central-dialogo input[type="text"],
.data-popover-campos input[type="date"],
.ncm-search-input,
.filtro-search-input, .central-search,
.filtro-select, .export-sort-select, .central-select,
.cclass-banco-e, .cclass-servidor-e, .cclass-tipo-e,
.export-month-picker input[type="month"],
.central-filter-search input {
    box-sizing: border-box;
    border: 1px solid var(--hairline-strong);
    border-radius: var(--radius-md);
    background-color: var(--surface-flutuante);
    color: var(--ink);
    font-family: var(--font-ui);
    line-height: 1.4;
    outline: none;
    transition: border-color var(--dur-fast) var(--ease-std),
                box-shadow var(--dur-fast) var(--ease-std);
}

/* ── Tamanho formulário ─────────────────────────────────────────────── */
.field input, .field select, .field textarea,
.dlg-campo > input, .dlg-campo > select, .dlg-campo > textarea,
.login-campo input,
.central-atencao-modal textarea, .central-atencao-modal input[type="date"],
.central-dialogo input[type="text"],
.data-popover-campos input[type="date"],
.ncm-search-input {
    min-height: var(--campo-h);
    padding: 0 12px;
    font-size: var(--campo-fs);
}

/* ── Tamanho barra: a altura dos botões da mesma barra ──────────────── */
.filtro-search-input, .central-search,
.filtro-select, .export-sort-select, .central-select,
.cclass-banco-e, .cclass-servidor-e, .cclass-tipo-e,
.export-month-picker input[type="month"],
.central-filter-search input {
    min-height: var(--btn-min-h);
    padding: 0 12px;
    font-size: var(--btn-fs);
}

/* ── Texto longo ────────────────────────────────────────────────────── */
.field textarea, .dlg-campo > textarea, .central-atencao-modal textarea {
    min-height: calc(var(--campo-h) * 2.2);
    padding: 10px 12px;
    line-height: 1.5;
    resize: vertical;
}

/* ── Com o botão de copiar dentro (CNPJ e IE da ficha do cliente) ───── */
.dlg-campo-copiar > input { padding-right: 40px; }

/* ── Select: seta própria, a mesma em todos ─────────────────────────── */
.field select, .dlg-campo > select,
.filtro-select, .export-sort-select, .central-select,
.cclass-banco-e, .cclass-servidor-e, .cclass-tipo-e {
    appearance: none;
    -webkit-appearance: none;
    padding-right: 34px;
    background-image: var(--seta-select);
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 16px;
    cursor: pointer;
}

/* ── Busca: lupa, a mesma em todas ──────────────────────────────────────
   Era ícone no markup em uma tela, nada nas outras seis. Pelo fundo, toda
   busca ganha a lupa sem ninguém lembrar de pôr. */
.filtro-search-input, .central-search, .ncm-search-input, .central-filter-search input {
    padding-left: 36px;
    background-image: var(--lupa);
    background-repeat: no-repeat;
    background-position: left 12px center;
    background-size: 18px;
}

/* ── Tamanho login: a única tela que é SÓ o formulário, e a de celular.
   Campo maior (e 16px, que também impede o zoom do iOS ao focar). ───── */
.login-campo input { min-height: 48px; padding: 0 14px; font-size: var(--fs-md); }

/* ── Senha com o olho dentro (login): folga à direita para o botão ───── */
.login-senha input { padding-right: 48px; }

/* ── Preenchido pelo navegador: o autofill pinta o campo de azul-claro,
   fora da paleta e ilegível no escuro. O anel interno (sombra sem blur, a
   única permitida) cobre o fundo com a cor do campo. ─────────────────── */
.field input:-webkit-autofill, .dlg-campo > input:-webkit-autofill,
.login-campo input:-webkit-autofill {
    -webkit-text-fill-color: var(--ink);
    box-shadow: inset 0 0 0 1000px var(--surface-flutuante);
    caret-color: var(--ink);
}

/* ── Estados ────────────────────────────────────────────────────────── */
.field input::placeholder, .field textarea::placeholder,
.dlg-campo > input::placeholder, .dlg-campo > textarea::placeholder,
.login-campo input::placeholder,
.central-atencao-modal textarea::placeholder,
.central-dialogo input[type="text"]::placeholder,
.ncm-search-input::placeholder, .filtro-search-input::placeholder,
.central-search::placeholder, .central-filter-search input::placeholder {
    color: var(--mute);
    opacity: 1;
}

.field input:hover, .field select:hover, .field textarea:hover,
.dlg-campo > input:hover, .dlg-campo > select:hover, .dlg-campo > textarea:hover,
.login-campo input:hover,
.central-atencao-modal textarea:hover, .central-atencao-modal input[type="date"]:hover,
.central-dialogo input[type="text"]:hover,
.data-popover-campos input[type="date"]:hover,
.ncm-search-input:hover, .filtro-search-input:hover, .central-search:hover,
.filtro-select:hover, .export-sort-select:hover, .central-select:hover,
.cclass-banco-e:hover, .cclass-servidor-e:hover, .cclass-tipo-e:hover,
.export-month-picker input[type="month"]:hover,
.central-filter-search input:hover {
    border-color: color-mix(in srgb, var(--ink) 28%, transparent);
}

.field input:focus, .field select:focus, .field textarea:focus,
.dlg-campo > input:focus, .dlg-campo > select:focus, .dlg-campo > textarea:focus,
.login-campo input:focus,
.central-atencao-modal textarea:focus, .central-atencao-modal input[type="date"]:focus,
.central-dialogo input[type="text"]:focus,
.data-popover-campos input[type="date"]:focus,
.ncm-search-input:focus, .filtro-search-input:focus, .central-search:focus,
.filtro-select:focus, .export-sort-select:focus, .central-select:focus,
.cclass-banco-e:focus, .cclass-servidor-e:focus, .cclass-tipo-e:focus,
.export-month-picker input[type="month"]:focus,
.central-filter-search input:focus {
    border-color: var(--link);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-blue-vivid) 16%, transparent);
}

/* Confere (a palavra de confirmação bateu) e faltando (obrigatório vazio):
   aqui, depois do foco, para vencer a cascata dentro e fora do foco. */
.field input.confere, .field input.confere:focus {
    border-color: var(--accent-green);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-green-vivid) 14%, transparent);
}
.dlg-campo > .central-campo-faltando { border-color: var(--accent-red); }

.field input:disabled, .field select:disabled, .field textarea:disabled,
.dlg-campo > input:disabled, .dlg-campo > select:disabled, .dlg-campo > textarea:disabled,
.filtro-select:disabled, .export-sort-select:disabled, .central-select:disabled,
.filtro-search-input:disabled, .central-search:disabled {
    opacity: .5;
    cursor: not-allowed;
}

/* ── Arquivo: a mesma casca, tracejada — "solte aqui" ─────────────────── */
.gdoor-import-file, .planilha-file, .relatorio-file-input {
    box-sizing: border-box;
    padding: 8px;
    border: 1px dashed var(--hairline-strong);
    border-radius: var(--radius-md);
    background: var(--surface-flutuante);
    color: var(--ink);
    font-family: var(--font-ui);
    font-size: var(--fs-xs);
    cursor: pointer;
    transition: border-color var(--dur-fast) var(--ease-std);
}
.gdoor-import-file:hover, .planilha-file:hover, .relatorio-file-input:hover { border-color: var(--link); }
.gdoor-import-file:focus-visible, .planilha-file:focus-visible, .relatorio-file-input:focus-visible {
    outline: 2px solid var(--link);
    outline-offset: 2px;
}

/* ── Rótulo: o mesmo acima de todo campo ────────────────────────────── */
.field label, .dlg-campo > label, .dlg-campo > .dlg-rotulo, .central-atencao-label, .login-campo span {
    font-size: 13px;
    font-weight: 500;
    color: var(--body);
    line-height: 1.3;
}
.field label { display: block; margin-bottom: 6px; }

/* FIM DO VOCABULÁRIO DE CAMPOS — o campos.check.js lê só até aqui. */

/* =====================================================================
   CAIXA DE MARCAR — vocabulário único
   (2026-09-23) Havia três: a nativa com accent-color (14px no filtro de
   coluna, 18px nos relatórios), a nativa sem nada (Configurações, caixas de
   e-mail — o azul do sistema operacional, que não troca com o tema) e a
   desenhada da lista de Exportar XML, quase um círculo (raio 8 num quadrado
   de 18) e VERDE quando marcada. Uma só: desenhada, 16px, na cor de ação.
   `.bank-check` é a mesma caixa num <span> — a linha inteira é o controle.
   ===================================================================== */
input[type="checkbox"], .bank-check {
    appearance: none;
    -webkit-appearance: none;
    box-sizing: border-box;
    display: inline-grid;
    place-content: center;
    flex-shrink: 0;
    width: 16px;
    height: 16px;
    margin: 0;
    border: 1.5px solid var(--mute);
    border-radius: var(--radius-xs);
    background: var(--surface-flutuante);
    color: var(--primary-on);
    vertical-align: middle;
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-std),
                border-color var(--dur-fast) var(--ease-std);
}
/* A marca: recorte em "check" na cor do texto sobre a ação. */
input[type="checkbox"]::before {
    content: "";
    width: 9px;
    height: 9px;
    background: currentColor;
    clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
    transform: scale(0);
    transition: transform var(--dur-fast) var(--ease-std);
}
.bank-check .icon { width: 13px; height: 13px; }
input[type="checkbox"]:checked, .bank-item.checked .bank-check {
    background: var(--primary);
    border-color: var(--primary);
}
input[type="checkbox"]:checked::before { transform: scale(1); }
/* Parcial (o "marcar todos" com só alguns marcados): a caixa acesa com um traço. */
input[type="checkbox"]:indeterminate { background: var(--primary); border-color: var(--primary); }
input[type="checkbox"]:indeterminate::before { transform: scale(1); clip-path: inset(40% 8%); }
input[type="checkbox"]:hover:not(:checked):not(:disabled),
.bank-item:hover:not(.checked) .bank-check { border-color: var(--ink); }
input[type="checkbox"]:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; }
input[type="checkbox"]:disabled { opacity: .5; cursor: not-allowed; }

/* FIM DA CAIXA DE MARCAR */

/* =====================================================================
   CONTROLE SEGMENTADO — vocabulário único
   (2026-09-23) "Escolha uma entre poucas" tinha cinco desenhos: o trilho
   da Central (.central-tabs), botões soltos com o escolhido azul (período
   de Exportar XML e dos dois modais do cliente), abas com estilo inline e
   texto VERDE (filiais do e-mail), pílulas com uma cor por opção (regime do
   NCM) e a pílula redonda do tema, com o escolhido em azul claro.

   Um só: trilho --preenchimento, segmento transparente, escolhido na cor de
   ação — a mesma decisão das abas de trabalho (.tab-item.ativa). Peso 500
   em todos os estados: escolhido é fundo e cor, nunca negrito (decisão 3).
   .theme-switch/.theme-switch-opt são o mesmo controle, só com ícone.
   ===================================================================== */
.central-tabs, .theme-switch {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 3px;
    border-radius: var(--radius-md);
    background: var(--preenchimento);
    flex-shrink: 0;
}
/* Preenche a largura, segmentos iguais (regime do NCM, ordenar A-Z). */
.central-tabs.cheio { display: flex; }
.central-tabs.cheio > .central-tab { flex: 1 1 0; }

.central-tab, .theme-switch-opt {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--body);
    font-family: var(--font-ui);
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-std),
                color var(--dur-fast) var(--ease-std);
}
.central-tab {
    padding: var(--tab-pad);
    font-size: var(--tab-fs);
}
.theme-switch-opt { width: 28px; height: 26px; padding: 0; }
.theme-switch-opt .icon { width: 16px; height: 16px; }
.central-tab:hover, .theme-switch-opt:hover {
    background: var(--preenchimento);
    color: var(--ink);
}
.central-tab.active, .central-tab.active:hover,
.theme-switch-opt.ativo, .theme-switch-opt.ativo:hover {
    background: var(--primary);
    color: var(--primary-on);
}
.central-tab.active .icon, .theme-switch-opt.ativo .icon { color: var(--primary-on); }
.central-tab:focus-visible, .theme-switch-opt:focus-visible {
    outline: 2px solid var(--link);
    outline-offset: 2px;
}

/* Ordenar A-Z / Z-A no dropdown de filtro: sem nenhuma opção escolhida os dois
   segmentos eram transparentes sobre o trilho — só texto solto, e o hover
   (mesmo tom do trilho) não aparecia. Em repouso são peças visíveis, na cor
   do próprio dropdown, sobre o trilho. */
.central-filter-sort .central-tab:not(.active) { background: var(--surface-flutuante); }
.central-filter-sort .central-tab:not(.active):hover { background: var(--preenchimento-hover); }

/* FIM DO CONTROLE SEGMENTADO */

/* =====================================================================
   CAIXA DE AVISO — vocabulário único
   (2026-09-23) Eram sete desenhos para "um recado na tela": texto verde em
   negrito (.msg-ok), texto vermelho em negrito (.msg-erro), texto laranja
   (.aviso-bloco), texto preto com ícone laranja (.aviso-superusuario),
   fonte de 12px (.central-aviso-exclusao), e caixas montadas com style= no
   JS (resultado do "Testar conexão"). Um só: texto --ink em peso normal,
   o TOM no fundo e no ícone — o que se lê é o recado, a cor diz de que tipo.

     neutro .msg-neutro
     ok     .msg-ok, .modal-resultado.ok
     aviso  .aviso-superusuario, .aviso-bloco, .modal-aviso
     erro   .msg-erro, .central-aviso-exclusao, .modal-resultado.erro

   .msg-* ficam em linha (abraçam o texto); as outras ocupam a largura.
   Margem continua na regra de cada tela.
   ===================================================================== */
.msg-ok, .msg-erro, .msg-neutro,
.aviso-superusuario, .aviso-bloco, .modal-aviso,
.central-aviso-exclusao, .modal-resultado {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    padding: 10px 12px;
    border-radius: var(--radius-md);
    color: var(--ink);
    font-size: var(--fs-sm);
    font-weight: 400;
    line-height: 1.5;
}
.msg-ok, .msg-erro, .msg-neutro { display: inline-flex; align-items: center; }
.modal-resultado { margin-top: var(--space-3); }
.modal-resultado[hidden], .central-aviso-exclusao[hidden] { display: none; }

.msg-ok .icon, .msg-erro .icon, .msg-neutro .icon,
.aviso-superusuario .icon, .aviso-bloco .icon, .modal-aviso .icon,
.central-aviso-exclusao .icon, .modal-resultado .icon {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    margin-top: 1px;
}

.msg-neutro { background: var(--preenchimento); }
.msg-neutro .icon { color: var(--mute); }
.msg-ok, .modal-resultado.ok { background: var(--fundo-ok); }
.msg-ok .icon, .modal-resultado.ok .icon { color: var(--accent-green); }
.aviso-superusuario, .aviso-bloco, .modal-aviso { background: var(--fundo-aviso); }
.aviso-superusuario .icon, .aviso-bloco .icon, .modal-aviso .icon { color: var(--accent-orange); }
.msg-erro, .central-aviso-exclusao, .modal-resultado.erro { background: var(--fundo-erro); }
.msg-erro .icon, .central-aviso-exclusao .icon, .modal-resultado.erro .icon { color: var(--accent-red); }

/* FIM DA CAIXA DE AVISO */

/* Trilho sem segmento nenhum (filiais do e-mail com uma filial só): some,
   em vez de sobrar uma pílula cinza vazia. */
.central-tabs:empty { display: none; }
.contatos-filiais, .contatos-novo { margin-bottom: var(--space-3); }
.contatos-contexto:empty { display: none; }



/* =====================================================================
   Histórico — DESIGN.md (## Dashboard, `table-dense`)
   Mesma pele de .central-table (fonte, espaçamento, cabeçalho, hover, zebra)
   — ver o bloco "TABELA PADRÃO DO APP" no início do arquivo.
   ===================================================================== */
.hist-filtros {
    display: flex;
    align-items: flex-end;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin: var(--space-4) 0;
}
.hist-filtros .field { margin-bottom: 0; min-width: 160px; }

/* Histórico de envio de XML: a barra é a `.central-toolbar` da Central, que
   não tem margem própria — na Central o respiro vem do `.central-header` que
   a envolve. Aqui não há esse envelope, e a barra encostava no cabeçalho da
   tabela. Mesmo respiro que a `.hist-filtros` acima já dava. */
.hist-xml-barra { margin: var(--space-4) 0; }

.hist-tabela-wrap {
    border: 0;
    border-radius: var(--radius);
    background: var(--surface-card);
    overflow: auto;
    max-height: calc(100vh - 320px);
}

.hist-tabela { width: 100%; border-collapse: collapse; font-size: var(--tabela-fs); }

.hist-tabela thead th {
    position: sticky;
    top: 0;
    background: var(--tabela-cabecalho);
    color: var(--mute);
    font-size: var(--fs-xs);
    font-weight: 400;
    letter-spacing: .04em;
    text-transform: uppercase;
    text-align: left;
    padding: var(--tabela-th-pad);
    border-bottom: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.hist-tabela tbody td {
    height: var(--tabela-linha-h);
    padding: var(--tabela-td-pad);
    border-bottom: 0;
    color: var(--body);
    vertical-align: middle;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.hist-tabela tbody tr:last-child td { border-bottom: 0; }
.hist-tabela tbody tr:hover td { background: var(--surface-hover); }
/* :not(.hist-erro): a linha de erro já pinta o próprio <td> de vermelho
   (embaixo, no bloco de estados) — excluir aqui em vez de confiar na ordem
   do arquivo pra decidir quem vence entre duas regras de mesma especificidade. */
.hist-tabela tbody tr:nth-child(even):not(.hist-erro) td { background: var(--zebra-tint); }
.hist-tabela tbody tr:nth-child(even):not(.hist-erro):hover td { background: var(--surface-hover); }

/* Data e duração são números: algarismo tabular para alinharem na vertical. */
.hist-col-quando, .hist-col-dur {
    font-variant-numeric: tabular-nums;
    font-size: var(--fs-xs);
    white-space: nowrap;
    color: var(--mute);
}

/* Alvo e detalhe crescem sem limite; cortam com reticências e o resto vai no
   title, como na tabela de servidores. */
.hist-col-alvo, .hist-col-detalhe {
    max-width: 280px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.hist-col-alvo { color: var(--ink); }

/* `width: 1%` numa tabela = "só o necessário": sem isto a coluna do botão
   dividia a largura em pé de igualdade com Cliente e Detalhe, e o ícone ficava
   perdido no canto de uma célula larga. */
.hist-col-baixar { width: 1%; white-space: nowrap; text-align: center; }

/* Falha é o que mais se procura num histórico: a linha inteira se marca. */
.hist-tabela tbody tr.hist-erro td { background: var(--fundo-erro); }
.hist-tabela tbody tr.hist-erro .hist-col-detalhe { color: var(--accent-red); }

/* Registro anterior ao histórico: veio da tabela `envios` e não tem quem. */
.hist-legado { color: var(--ash); }


/* =====================================================================
   Exportação: observação e ponto de atenção na linha do banco
   Os dois vêm do cadastro do cliente e NÃO são a mesma coisa: atenção é algo
   que pode dar errado agora — leva alfinete, tinta e sobe para o topo da
   lista —, observação é anotação, e fica discreta ao lado do nome.
   ===================================================================== */
.bank-nota {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
    overflow: hidden;
}

/* Herda a forma do `badge-pill` do documento; aqui só a tinta e o corte. */
.bank-atencao {
    background: var(--fundo-aviso);
    color: var(--accent-orange);
    max-width: 260px;
    overflow: hidden;
    text-overflow: ellipsis;
}
.bank-atencao .icon { width: 14px; height: 14px; flex-shrink: 0; }
/* Já liberado: a pílula continua ali (o texto importa), mas sem o alarme. */
.bank-atencao.liberado { background: transparent; color: var(--charcoal); }

/* Linha travada pelo ponto de atenção. Sem `pointer-events: none`: o clique
   PRECISA chegar para abrir o texto — travar em silêncio parece tela quebrada.
   A tinta é a mesma da linha de atenção da Central, para as duas telas
   contarem a mesma história. */
/* Ponto de atencao na exportacao: o MESMO shimmer da Central. As duas telas
   falam do mesmo cadastro; dois sinais diferentes para o mesmo estado fazem
   a pessoa ter de aprender dois vocabularios. */
.bank-item.bank-travado {
    animation: centralAtencaoShimmer 2.2s ease-in-out infinite;
    cursor: default;
}

/* Observacao na exportacao: o mesmo amarelo leve da linha da Central. */
.bank-item.bank-obs-linha {
    background: color-mix(in srgb, var(--fundo-linha-aviso) 40%, var(--surface-card));
}
.bank-item.bank-travado .bank-check {
    border-style: dashed;
    opacity: 0.5;
}
/* Sem classe de botão nova: é `.btn-outline.btn-small` do vocabulário, e aqui
   fica só a tinta laranja que o liga ao ponto de atenção da mesma linha. */
.bank-liberado-marca {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    font-size: var(--fs-xs);
    color: var(--accent-green);
    white-space: nowrap;
}
.bank-liberado-marca .icon { width: 14px; height: 14px; }

/* Texto do ponto de atenção dentro do diálogo de liberação. */

.bank-obs {
    font-size: var(--fs-xs);
    color: var(--charcoal);
    max-width: 240px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* =====================================================================
   Modo compacto — Ferramentas → Aparência (assets/js/nav.js), estado em
   assets/js/app.js (toggleModoCompacto / aplicarModoCompacto).

   Redefine só os TOKENS de densidade declarados no :root (topo do arquivo,
   `--btn-*`, `--tabela-*`, `--bank-item-*`) — nenhum seletor novo, nenhuma
   duplicata da lista de botões. Cada regra que consome esses tokens (a base
   de .btn-*, a grid de Clientes, a linha de Exportar XML) já muda sozinha,
   porque CSS custom property é herdada: o `body` é ancestral de tudo, então
   qualquer botão/linha SEM override mais próximo (como `.btn-small`, que
   declara os três `--btn-*` direto nele e por isso não é afetado — já é
   pequeno) pega o valor daqui.

   Os números não são inventados: `--btn-*` são exatamente os de `.btn-small`
   (o modificador "denso" que o vocabulário de botões já tinha, ver acima) —
   modo compacto é ligar aquele modificador em todo botão de uma vez, não
   criar uma segunda escala de tamanho para o app aprender.

   Isto NÃO cobre o app inteiro — cobre os três alvos que geram mais volume
   na tela (botões, grid de Clientes, lista de Exportar XML). Outra tela que
   precisar do mesmo tratamento entra como mais um token consumido por ela e
   mais uma linha aqui — não como reescrita.
   ===================================================================== */
body.modo-compacto {
    --btn-pad: 4px 12px;
    --btn-min-h: 28px;
    --btn-fs: var(--fs-xs);
    --tabela-td-pad: 2px 8px;
    --tabela-th-pad: 3px 8px;
    --tabela-fs: 12px;
    --tabela-linha-h: 30px;
    --selo-h: 18px;
    --bank-item-pad: 3px 10px;
    --bank-item-min-h: 30px;
    --bank-item-gap: var(--space-2);
    --icon-btn-w: 28px;
    --tab-pad: 3px 10px;
    --tab-fs: var(--fs-xs);
    --campo-h: 32px;
    --campo-fs: 13px;
}

/* =====================================================================
   Modal de Configurações (assets/js/configuracoes.js) — categoria na
   lateral esquerda, conteúdo à direita. `.modal-close.central-dlg-x` e
   `.modal.modal-xl` já existiam; só a divisão em duas colunas é nova.
   ===================================================================== */
/* `.modal.modal-xl` sozinho travava em 760px -- estreito demais pro painel
   de Usuários (id + nome + data + status + até 3 botões numa linha só,
   sem quebra: ver `#listaUsuarios .detail-item` mais abaixo). Precisa do
   par de classes pra empatar a especificidade de `.modal.modal-xl` (a
   ordem no arquivo é quem desempata). */
.modal.config-modal {
    max-width: 1080px;
}
.config-modal {
    padding: 0;
    /* Quem rola é a lateral e o painel, cada um por si — não o modal inteiro,
       senão a lista de categorias soma junto com o conteúdo e o menu passa a
       exigir rolar a tela toda para trocar de categoria. */
    overflow: hidden;
    display: flex;
    flex-direction: column;
    height: min(700px, calc(100vh - var(--space-8)));
}
.config-modal-corpo {
    display: flex;
    flex: 1;
    min-height: 0;
}
.config-modal-lateral {
    flex: 0 0 200px;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-4) var(--space-3);
    background: var(--surface-card);
    border-right: 0;
    overflow-y: auto;
}
.config-modal-lateral h2 {
    font-size: var(--fs-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--mute);
    font-weight: 600;
    padding: 0 var(--space-2);
    margin-bottom: var(--space-2);
}
.config-modal-item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-md);
    background: transparent;
    border: 0;
    color: var(--body);
    font-family: inherit;
    font-size: var(--fs-sm);
    text-align: left;
    cursor: pointer;
}
.config-modal-item:hover { background: var(--surface-hover); }
.config-modal-item.ativo {
    background: var(--surface-hover);
    color: var(--ink);
    
}
.config-modal-painel {
    flex: 1;
    min-width: 0;
    padding: var(--space-6);
    overflow-y: auto;
}

/* Aparência: uma linha por ajuste, o nome à esquerda e o controle à direita. */
.config-linhas { display: flex; flex-direction: column; gap: var(--space-2); }

.config-switch-linha {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius);
    background: var(--preenchimento);
}
/* Liga/desliga: a linha inteira é o <label> — clicar no texto também alterna. */
label.config-switch-linha { cursor: pointer; }
.config-switch-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.config-switch-txt strong { font-size: var(--fs-sm); font-weight: 600; color: var(--ink); }
.config-switch-txt span { font-size: var(--fs-xs); color: var(--mute); }

/* Topo de categoria com ação: título e subtítulo à esquerda, o botão
   principal da tela à direita (Usuários do painel). */
.config-topo {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-5);
    /* O X de fechar do modal fica solto no canto, por cima do painel. */
    padding-right: var(--space-8);
}
.config-topo h2 { margin-bottom: var(--space-1); }
.config-topo p.subtitle { margin: 0; }
.config-topo > button { flex-shrink: 0; }
/* O texto encolhe antes: com subtítulo longo o botão caía para baixo dele. */
.config-topo > div { flex: 1 1 280px; min-width: 0; }

/* Usuários do painel: a lista é o conteúdo; o cadastro abre por cima dela
   só quando pedido (antes eram três campos fixos no topo e a lista ficava
   espremida no pé da tela). */
.usuario-novo {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    margin-bottom: var(--space-5);
    padding: var(--space-4);
    border-radius: var(--radius);
    background: var(--preenchimento);
}
.usuario-novo[hidden] { display: none; }
.usuario-novo .aviso-superusuario { margin: 0; }
.usuario-novo .modal-nota { margin: 0; }
.usuario-novo .modal-actions { margin: 0; }
.usuario-novo-campos { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--space-3); }

.usuarios-lista { display: flex; flex-direction: column; gap: var(--space-1); }
.usuario-linha {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius);
    background: var(--preenchimento);
}
.usuario-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.usuario-info > * { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.usuario-nome { font-size: var(--fs-sm); font-weight: 600; color: var(--ink); }
.usuario-meta { font-size: var(--fs-xs); color: var(--mute); }
.usuario-acoes { display: flex; gap: var(--space-1); flex-shrink: 0; }
.usuario-linha.inativo .user-avatar { background: var(--surface-hover); color: var(--mute); }
.usuario-linha.inativo .usuario-nome { color: var(--mute); }
.usuario-linha .esq:not(.esq-avatar) { flex: 1; max-width: 260px; }

/* =====================================================================
   Portal do cliente (portal.html / portal.js) — 2026-09-23
   Página à parte, sem a casca da equipe (sem topbar/menubar/mega-menu — chrome
   de trabalho interno que não faz sentido aqui). Tudo mais vem de graça do
   resto do arquivo: .login-split (login), .escolha-marca (iniciais da empresa),
   .kpi-row/.chart-wrap/.dlg-secao/.tipo-linha (dashboard) — os
   únicos componentes genuinamente novos são a casca abaixo.
   ===================================================================== */
.portal-main {
    max-width: 1120px;
    margin: 0 auto;
    padding: var(--space-6) var(--space-4) var(--space-10);
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}
/* [hidden] tem a mesma especificidade de .login-split/.portal-main
   (display: grid/flex) e perde no empate — sem isto, alternar telas com
   `.hidden = true` (portal.js) marcava o atributo certo e a tela errada
   continuava desenhada por cima. Mesmo idioma de .tab-content[hidden]
   (ver perto de .tab-content, mais acima no arquivo — ali também ficaram
   .loading/.empty-state/.btn-plain, que portal.js também liga/desliga assim). */
.login-split[hidden], .portal-main[hidden] { display: none; }

.portal-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
}
.portal-header h1 { margin: 0; font-size: var(--fs-xl); font-weight: 600; color: var(--ink); }
.portal-header p { margin: 4px 0 0; font-size: var(--fs-sm); color: var(--mute); }

/* A moldura da empresa: quem é a empresa que se está vendo — iniciais, nome,
   razão social e CNPJ — num cartão, e o "Trocar" (portalAbrirSeletor) no
   canto quando o acesso enxerga mais de uma. Antes o nome era um título com
   seta, e o acesso com várias empresas passava por uma tela só para escolher. */
.portal-moldura {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    max-width: 560px;
    padding: var(--space-4) var(--space-5);
    border-radius: var(--radius-lg);
    background: var(--surface-card);
}
.portal-moldura-txt { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.portal-moldura-txt small {
    font-size: var(--fs-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--mute);
}
.portal-moldura-txt h1 { margin: 0; font-size: var(--fs-lg); overflow-wrap: anywhere; }
.portal-moldura-txt p { margin: 0; overflow-wrap: anywhere; }
.portal-moldura-txt p:empty { display: none; }
#portalEmpresaCnpj { font-variant-numeric: lining-nums tabular-nums; }
.portal-moldura .btn-secondary { flex-shrink: 0; }

/* O menu é o .central-ctx-menu do resto do app; os itens aqui são <button>
   (teclado), então zera o que o navegador põe num botão. */
.portal-seletor { max-height: min(420px, calc(100vh - 120px)); overflow-y: auto; }
.portal-seletor .central-ctx-menu-item, .acesso-seletor .central-ctx-menu-item, .sistema-seletor .central-ctx-menu-item,
.contador-seletor .central-ctx-menu-item { width: 100%; border: 0; background: transparent; text-align: left; font-weight: 500; }
.portal-seletor .central-ctx-menu-item:hover, .acesso-seletor .central-ctx-menu-item:hover, .sistema-seletor .central-ctx-menu-item:hover,
.contador-seletor .central-ctx-menu-item:hover,
.portal-seletor .central-ctx-menu-item:focus-visible, .sistema-seletor .central-ctx-menu-item:focus-visible,
.contador-seletor .central-ctx-menu-item:focus-visible { background: var(--surface-hover); outline: none; }
.portal-seletor .central-ctx-menu-item .icon, .sistema-seletor .central-ctx-menu-item .icon { margin-left: auto; color: var(--link); flex-shrink: 0; }
.sistema-seletor .central-ctx-menu-item .icone-sis { flex-shrink: 0; }
.portal-seletor-txt, .acesso-seletor-txt { display: flex; flex-direction: column; min-width: 0; }
.portal-seletor-txt > *, .acesso-seletor-txt > * { overflow: hidden; text-overflow: ellipsis; }
.portal-seletor-txt small, .acesso-seletor-txt small { font-size: var(--fs-xs); font-weight: 400; color: var(--mute); }
.portal-header-acoes { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
/* A moldura encolhe antes: sem isto, no celular os botões caíam para uma
   linha solta embaixo da empresa. */
.portal-header > div:first-child { flex: 1 1 180px; min-width: 0; }

/* Iniciais do cliente no lugar do logo de sistema — mesmo tratamento do
   .dlg-marca das fichas (central.js): quadrado tingido, texto no tom do link. */
.portal-main .escolha-marca {
    font-size: var(--fs-sm);
    font-weight: 700;
    color: var(--link);
    background: color-mix(in srgb, var(--link) 12%, transparent);
    overflow: hidden;
}
/* Com foto: preenche a moldura (vence o `.escolha-marca img` de 24px, do logo de sistema). */
.portal-main .escolha-marca .foto-cliente { width: 100%; height: 100%; }
.portal-seletor .cli-avatar { width: 28px; height: 28px; margin-right: 0; }

.portal-daterange { display: flex; align-items: flex-end; gap: var(--space-3); flex-wrap: wrap; }
.portal-daterange .dlg-campo { flex: 0 0 auto; min-width: 150px; }

.portal-filtros { display: flex; flex-direction: column; gap: var(--space-3); }
.portal-fiscal { max-width: 440px; }
/* .central-tabs.cheio (display: flex) empata com [hidden] e ganharia: o
   seletor aparecia para o sistema que não separa o fiscal. */
.portal-fiscal[hidden] { display: none; }

/* Dashboard: duas colunas no desktop (pagamento ao lado dos meses); KPIs,
   vendas por dia e vendedores ocupam a linha inteira. */
.portal-grade {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-4);
    align-items: start;
}
.portal-grade[hidden] { display: none; }
.portal-cheio { grid-column: 1 / -1; }
.portal-grade .kpi-row { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
/* Sem pagamento (Uniplus), os meses tomam a linha em vez de deixar meia vazia. */
#portalPagamentosSecao[hidden] + #portalMesesSecao { grid-column: 1 / -1; }
/* A regra antiga de .panel-card (cards de pendência) dá margin-bottom: 20px;
   aqui quem espaça é o gap da grade. */
.portal-main .panel-card { margin: 0; }

.portal-donut { height: 200px; }
.portal-esq .kpi-card { gap: var(--space-3); }
.portal-esq .panel-card:not(.portal-cheio) .esq-grafico { height: 280px; }
.portal-donut + .portal-lista { margin-top: var(--space-4); }
/* .tipo-linha nasceu para contagem de pendência (2-3 dígitos) e com uma 5ª
   coluna de seta; aqui o valor é em reais e não há para onde ir. */
.portal-lista .tipo-linha { grid-template-columns: minmax(0, 240px) minmax(40px, 1fr) auto 52px; }
.portal-lista .tipo-val { text-align: right; font-variant-numeric: tabular-nums; }
.portal-nome { display: flex; flex-direction: column; min-width: 0; }
.portal-nome > * { overflow: hidden; text-overflow: ellipsis; }
.portal-nome small { font-size: var(--fs-xs); color: var(--mute); white-space: normal; }

.portal-comparativo { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); }
.portal-comparativo > div {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-3);
    border-radius: var(--radius-md);
    background: var(--preenchimento);
}
.portal-comparativo span { font-size: var(--fs-xs); color: var(--mute); }
.portal-comparativo strong { font-size: var(--fs-md); font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.portal-delta { display: flex; align-items: center; gap: var(--space-2); margin: var(--space-3) 0 var(--space-4); font-size: var(--fs-sm); }
.portal-delta.up { color: var(--accent-green); }
.portal-delta.down { color: var(--accent-red); }

@media (max-width: 760px) {
    .portal-grade { grid-template-columns: minmax(0, 1fr); gap: var(--space-3); }
    /* No celular a barra desce para uma linha própria: ao lado do nome ela
       cortava "Cartão de crédito" em "Cartão de...". */
    .portal-lista .tipo-linha {
        grid-template-columns: minmax(0, 1fr) auto 52px;
        grid-template-areas: "nome val pct" "barra barra barra";
        row-gap: var(--space-1);
    }
    .portal-lista .tipo-nome { grid-area: nome; }
    .portal-lista .tipo-barra { grid-area: barra; }
    .portal-lista .tipo-val { grid-area: val; }
    .portal-lista .tipo-pct { grid-area: pct; }
    .portal-lista.tipos-lista { gap: var(--space-3); }
    .portal-grade .kpi-row { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); }
    .portal-grade .kpi-card { padding: var(--space-4); min-height: 0; }
}

@media (max-width: 480px) {
    .portal-main { padding: var(--space-4) var(--space-3) var(--space-8); }
    /* A moldura ocupa a largura toda (ao lado dos botões, o nome quebrava letra
       a letra) e os botões da conta sobem para uma linha própria, à direita. */
    /* :first-child só para empatar com `.portal-header > div:first-child` (mais acima). */
    .portal-header > .portal-moldura:first-child { flex-basis: 100%; max-width: none; }
    .portal-moldura { flex-wrap: wrap; padding: var(--space-4); gap: var(--space-3); }
    /* O "Trocar" desce para uma barra inteira embaixo: ao lado, comia a largura do nome. */
    #portalEmpresaTrocar { flex: 1 0 100%; }
    #portalEmpresaTrocar .btn-secondary { width: 100%; }
    .portal-header-acoes { order: -1; margin-left: auto; }
    .portal-header h1 { font-size: var(--fs-lg); }
    .portal-daterange { align-items: stretch; }
    .portal-daterange .dlg-campo { flex: 1 1 140px; }
    .portal-daterange .btn-primary { width: 100%; }
    .portal-fiscal { max-width: none; }
}
