/* Estilo do painel Argus.
   Extraído de web/index.html em 2026-08-11: eram dois blocos <style>, aqui
   concatenados NA ORDEM original — cascata depende de ordem.
   O <script> de tema, que rodava entre os dois, continua inline no HTML:
   ele precisa rodar antes do paint e um módulo adiado faria a página piscar. */

  /* PALETA ARGUS — manual de identidade v1.0 (identidades/argus/manual.html).
     Azul-ardósia: primária #4C7FB0, oceano #33526E, céu #9DC5E4, profunda
     #1F2937, aço #98A2B3. Os valores saem do styles.css do próprio manual, que
     é o tema de interface da marca; nada aqui foi inventado.

     Os NOMES dos tokens são os de sempre — quem mudou foram só os valores. É
     isso que deixa os ~600 var(--…) espalhados pelo projeto continuarem valendo
     sem uma edição na marcação.
     :root = tema ESCURO. O claro (o padrão) está em html.light. */
  :root{
    /* PALETA ARGUS v2 — manual em identidades/argus/manual.html (azul-ardósia).
       Substituiu a brasa/laranja em 2026-08-11. Valores do styles.css que
       acompanha o manual; nada aqui é derivado de gosto.
       Ardósia profunda #1F2937 · azul-oceano #33526E · azul-ardósia #4C7FB0 ·
       azul-céu #9DC5E4 · aço #98A2B3. */
    --bg-0:#10161D;
    --bg-1:#141B23;
    --card:#182129;
    /* SUPERFÍCIE FLUTUANTE — mais clara que o card, de propósito.
       Até 2026-08-13 este token repetia o valor de --card, e o menu suspenso
       desaparecia justamente onde mais abre: por cima de um card. Mesma cor, sem
       nada além da sombra para dizer que uma camada está sobre a outra.
       Menu é a camada mais alta da tela e tem de parecer isso. */
    --dropdown-bg:#202B36;
    --dropdown-border:#3A4857;
    --border:#2C3947;
    /* --cyan / --cyan-accent-rgb mantêm o nome (usados no arquivo todo) e
       carregam a cor de AÇÃO (botão, link, menu ativo, foco). A primária
       #4C7FB0 dá só 4.23:1 sobre branco — abaixo do mínimo para texto pequeno.
       Por isso a ação é o AZUL-CÉU no escuro e o AZUL-OCEANO no claro; a
       primária fica para o símbolo, ícones grandes e áreas de cor. */
    --cyan:#9DC5E4;
    --cyan-dim:#6FA0CB;
    --indigo:#4C7FB0;
    --text:#E5EBF1;
    --muted:#9AAABB;
    /* Só DOIS degraus de cinza, e não três. O --muted-3 existia e foi
       aposentado em 2026-08-13: media 2,94:1 sobre o card no escuro e 2,58:1 no
       claro, e os seis lugares que o usavam eram texto de 11px e um ícone de
       estado — justamente onde contraste importa mais. Não dava para salvá-lo:
       para chegar aos 4,5:1 exigidos ele teria de ficar quase igual ao
       --muted-2, e um terceiro degrau que não se distingue do segundo não é
       hierarquia, é enfeite. A hierarquia real é o salto para --text (13,57:1). */
    --muted-2:#7A8B9C;
    --surface:#182129;
    /* O campo é um RECUO no card: fundo um degrau ABAIXO da superfície, não do
       lado dela. Antes --panel ficava a meio caminho entre o card e o fundo da
       página e a diferença sumia — sobrava só a borda, fraca demais para dizer
       "aqui se digita". No foco ele SOBE (--panel-strong), invertendo o recuo. */
    --panel:#0E141A;
    --panel-strong:#1E2831;
    --panel-soft:#151D25;
    --panel-softer:#121920;
    --heading:#FFFFFF;
    --shadow-color: rgba(0,0,0,0.35);
    --sombra: 0 2px 16px rgba(0,0,0,.35);
    /* Degradê de SUPERFÍCIE COM CONTEÚDO: NÃO chega à ardósia profunda.
       O degradê cheio do manual (céu → ardósia → #1F2937) é para peça grande;
       aqui todo uso de --grad carrega texto ou ícone em cima — botão, avatar,
       badge, checkbox —, e um degradê que atravessa do céu claro ao quase-preto
       não admite UMA cor de texto que funcione nas duas pontas. Parando no
       azul-ardósia, o --on-grad rende de 5.6:1 a 12.4:1.
       Aprendido na tela em 2026-08-11, na paleta anterior: com a ponta escura,
       rótulo mais longo que "Entrar" entrava nela e sumia. */
    --grad: linear-gradient(135deg,#9DC5E4 0%,#4C7FB0 100%);
    /* Texto sobre o degradê: ardósia profunda nos dois temas — o degradê é
       claro na parte útil, e branco sobre o azul-céu daria 1.7:1. */
    --on-grad:#1F2937;
    /* Célula ESCURA do símbolo (Olho na Matriz). No fundo escuro a ardósia
       profunda some, e o manual troca por #3D6489 — é a única célula que muda
       entre as versões clara e escura do símbolo. */
    --brand-cel:#3D6489;
    --section-card-bg:#141B23;
    --section-card-border:#2C3947;
    --note-bg: rgba(var(--cyan-accent-rgb),0.08);
    --note-border: rgba(var(--cyan-accent-rgb),0.22);
    --section-header:#9DC5E4;
    --hairline-rgb: 152,162,179;
    /* Base das bordas/divisores translúcidos, usada como rgba(var(--hair-rgb),
       var(--fb-XX)) no projeto todo. É CALIBRADA por tema: na opacidade média
       (--fb-18) ela cai exatamente na cor de borda do tema — #2C3947 sobre o
       card escuro, #DFE5EC sobre o card claro. Não confundir com
       --hairline-rgb, que é o divisor de seção e vive numa opacidade bem menor. */
    --hair-rgb: 110,124,141;
    /* Fundo da barra de título dos painéis = o degradê da marca, mas
       SEMITRANSPARENTE — deixa o card aparecer por trás, virando um véu leve em
       vez de faixa cheia, pra não competir com os botões CTA. */
    --titlebar-bg: linear-gradient(135deg, rgba(157,197,228,0.12) 0%, rgba(76,127,176,0.12) 130%);
    --titlebar-text:#E5EBF1;
    /* Zebra das grids: linhas pares ganham um tom neutro bem leve (branco no
       escuro, preto no claro — ver html.light). Só pra dar ritmo de leitura. */
    --zebra-row: rgba(255,255,255,0.035);
    --fb-10: 0.14; --fb-12: 0.16; --fb-15: 0.2; --fb-16: 0.22; --fb-18: 0.24;
    --fb-20: 0.28; --fb-22: 0.3; --fb-25: 0.34; --fb-40: 0.5;
    --cyan-accent-rgb: 157,197,228;
    /* Semânticas de status, por tema. O par `-2` é a ponta escura do degradê
       dos botões de confirmação, e o `-rgb` existe para os fundos/bordas
       translúcidos (rgba() precisa dos canais soltos).

       ⚠️ NÃO EXISTE ÂMBAR nesta paleta. Removido em 2026-08-11 a pedido do
       usuário: numa tela inteiramente fria, o âmbar era o único elemento
       quente e gritava. Aviso e erro passam a ser a MESMA família — vermelho
       claro para aviso, escuro para erro —, e a diferença entre eles é de
       intensidade, não de matiz. O ganho é que a tela tem um único tom quente,
       reservado a alerta, e é isso que faz o alerta saltar num fundo frio.
       ⚠️ O INFO também não pode ser azul: viraria a cor da própria marca. Fica
       no aço #98A2B3, o neutro do manual. */
    --ok:#4ADE80;    --ok-2:#22C55E;    --ok-rgb:74,222,128;
    --erro:#F87171;  --erro-2:#DC2626;  --erro-rgb:248,113,113;
    --aviso:#FCA5A5; --aviso-2:#F87171; --aviso-rgb:252,165,165;
    --info:#98A2B3;
    /* PROVISÓRIO — âmbar, e o único âmbar da paleta. Nasceu para a baixa
       temporária (BT), que precisa ser distinguível de relance das outras três
       do mesmo lugar: AB é ciano, PG é verde, CA é vermelho. Não dava para
       reaproveitar o --aviso, que nesta paleta é da MESMA família do --erro
       (ver a decisão de 2026-08-11 no bloco dos status) e faria BT e CA
       parecerem a mesma coisa. */
    --provisorio:#FBBF24; --provisorio-rgb:251,191,36;
    /* O âmbar também vira BOTÃO desde 09/09/2026, no modal de aviso: o Carlos
       pediu que warning e danger fossem distinguíveis de relance ("uma outra
       cor aí, laranjinha, para ter uma coisa bem enxergável"), e como o --aviso
       é da mesma família do --erro, o único âmbar da paleta é este. O -2 fecha o
       degradê e o --on-provisorio é o rótulo por cima: #FBBF24 é claro, então
       pede texto escuro, igual ao --on-ok. */
    --provisorio-2:#F59E0B; --on-provisorio:#1F2937;
    /* Âmbar do GRÁFICO, separado do --provisorio de propósito. O token de texto
       e o de marca resolvem problemas diferentes: o --provisorio precisa de
       contraste para ser LIDO como texto; este precisa de distância de cor do
       vermelho ao lado, porque no gráfico as faixas se ENCOSTAM. Medido com o
       validador de paleta: no claro o par (#B45309, #B91C1C) dá ΔE 9.1 em visão
       normal e 4.9 sob deuteranopia — abaixo do piso; trocando pelo valor
       abaixo sobe para 22.6 / 9.9. Ver o relatório no comentário do gráfico em
       js/cliente-indicadores.js. */
    --graf-atrasado:#EAB308;

    /* IDENTIDADE do tipo de pessoa (dono, 2026-09-05): "no ícone de pessoa
       física, um begezinho/amarelinho; no de pessoa jurídica, um verdinho".
       Vive na grade de clientes, no avatar ao lado do nome.

       ⚠️ NÃO SÃO --ok NEM --provisorio, de propósito, embora peça "verde" e
       "amarelo/bege" — são os mesmos DOIS papéis que este arquivo já cuida de
       manter separados (ver a nota do --provisorio, logo abaixo): o avatar
       fica na MESMA linha do interruptor de Status, que já é verde quando
       Liberado e âmbar quando em Baixa Temporária. Reaproveitar a cor faria o
       ícone de PESSOA JURÍDICA parecer "liberado" e o de PESSOA FÍSICA
       parecer "baixa temporária" de relance — dois papéis (tipo de cadastro x
       situação do cadastro) na mesma cor. Tons próprios, na mesma família de
       matiz que o pedido descreveu, mas deslocados o bastante para não colar.

       A cor aqui é SECUNDÁRIA de propósito: o ícone (pessoa x prédio,
       icons.js) já diferencia os dois sem cor nenhuma — quem não distingue
       matiz continua lendo a forma. Por isso o contraste pedido é o de
       elemento gráfico (≥3:1), não o de texto.

       Contraste medido contra o fundo da grade (#10161D no escuro):
         --tipo-pj #34D399 -> 9.46:1     --tipo-pf #E3B873 -> 9.85:1 */
    --tipo-pj:#34D399; --tipo-pj-rgb:52,211,153;
    --tipo-pf:#E3B873; --tipo-pf-rgb:227,184,115;

    /* SUPERFÍCIE separada da cor de TEXTO: os dois papéis são incompatíveis
       numa cor só. Como texto de status sobre o card, a semântica precisa de um
       tom legível ali; como fundo de botão inteiro, precisa de outro, com o
       rótulo por cima. O par --*-sup é sempre estreitado até caber UMA cor de
       rótulo nas duas pontas do degradê. */
    --ok-sup:#4ADE80; --ok-sup-2:#22C55E;
    /* Superfícies de alerta: as MESMAS nos dois temas. Vermelho escuro com
       rótulo branco funciona tanto sobre card claro quanto escuro, e evita o
       problema de rótulo que morre numa das pontas. Aviso é o degrau mais
       claro, erro o mais escuro — a diferença é de intensidade. */
    --erro-sup:#B91C1C; --erro-sup-2:#991B1B;
    --aviso-sup:#DC2626; --aviso-sup-2:#B91C1C;
    /* Texto SOBRE cada cor semântica. Não dá para usar --on-grad aqui: as
       semânticas do tema CLARO são escuras e pedem branco, enquanto no escuro
       são claras e pedem escuro. Medido na página, não estimado. */
    --on-ok:#1F2937; --on-erro:#FFFFFF; --on-aviso:#FFFFFF;
    /* Os botões com gradiente (Fechar/Salvar/Confirmar) seguem o --grad. Os
       --cta-success-* / --btn-grad-2 continuam existindo porque há regra que os
       cita; apontam para as pontas do degradê do tema. */
    --btn-grad-2: #4C7FB0;
    --cta-success-1: #9DC5E4; --cta-success-2: var(--btn-grad-2);
  }
  /* Tema CLARO — o padrão do painel. É o tema em que a marca foi desenhada; o
     escuro (:root) é a variante. */
  /* MARCAS DOS SISTEMAS (wordmark na coluna Sistema da grade — ver js/marcas.js).
     Estas cores são das MARCAS dos clientes, não da paleta do Argus, e por isso
     não derivam de token nenhum daqui: vêm dos manuais em identidades/checkbem/
     e identidades/avenus/. Só existem como variável porque mudam com o tema, e
     é o único jeito de o mesmo <symbol> servir aos dois sem trocar de arquivo.

     O gradiente do CheckBem é igual nos dois temas; o que vira é a palavra
     "Check", quase preta no claro e quase branca no escuro. No Avenus o
     gradiente inteiro clareia no escuro, senão o verde-escuro some no fundo. */
  :root{
    --marca-checkbem-texto:#E9F1F9;
    --marca-checkbem-a:#2F80D0;
    --marca-checkbem-b:#58D0F0;
    --marca-avenus-a:#14B8A6;
    --marca-avenus-b:#5EEAD4;
  }

  html.light{
    --marca-checkbem-texto:#0A2E44;
    --marca-avenus-a:#052E2B;
    --marca-avenus-b:#14B8A6;
  }

  /* Alinha o wordmark com o texto das outras colunas: sem isto o SVG assenta na
     linha de base como se fosse letra e fica alguns pixels abaixo do resto. */
  /* `display:block` mata o vão de baseline que um <svg> inline deixa embaixo. O
     preço é que `text-center` na célula não o alcança — bloco não é texto —, e a
     coluna Sistema é centralizada desde 2026-08-14. Daí a margem automática.
     Seguro mexer aqui: o único lugar que usa esta classe é a coluna Sistema da
     grade de clientes (celulaSistema, em cliente-grade.js). */
  .marca-sistema{ display:block; margin-inline:auto; }

  html.light{
    /* Tema CLARO da paleta v2. Agora os neutros do manual JÁ SÃO frios
       (#F6F8FA / #DFE5EC / #52657A), então o cromo vem direto dele — sem o
       ajuste que a paleta laranja exigia, quando os beges deixavam a tela
       terrosa. Um efeito colateral bom da marca ter virado azul. */
    --bg-0:#F6F8FA;
    --bg-1:#EEF2F6;
    --card:#FFFFFF;
    /* No CLARO o menu continua branco, e não por descuido: qualquer cinza que o
       separasse do card branco o deixaria igual ao fundo da página (#F6F8FA) —
       a tela tem as duas superfícies, e o menu abre sobre as duas. Então aqui
       quem separa é a BORDA (um degrau mais forte que --border) e a sombra. */
    --dropdown-bg:#FFFFFF;
    --dropdown-border:#C6D2E0;
    --border:#DFE5EC;
    /* Ação = AZUL-OCEANO, não a primária. O #4C7FB0 dá 4.23:1 sobre branco,
       logo abaixo do mínimo para texto pequeno; o #33526E dá 8.1:1. A primária
       fica para símbolo, ícones grandes e áreas de cor. */
    --cyan:#33526E;
    --cyan-dim:#1F2937;
    --indigo:#4C7FB0;
    --text:#1F2937;
    --muted:#52657A;
    /* Escurecido de #7A8B9C em 2026-08-11, junto com --panel. É a cor do
       PLACEHOLDER e dos rótulos de seção ("Endereço"), e no tom antigo dava
       3,50:1 sobre o card — já abaixo dos 4,5:1 exigidos. Com o campo mais
       escuro cairia para 2,97:1, pior que o mínimo de 3:1 até para texto
       grande. Agora: 4,51:1 no campo e 5,31:1 no card.
       Custo assumido: a distância para --muted encolheu (5,31 contra 6,00 no
       card), então a hierarquia secundário/terciário lê mais junta do que
       antes. Legibilidade primeiro — o degrau para --text (12,47:1) continua
       fazendo o trabalho de hierarquia. */
    --muted-2:#5C6D80;
    /* (Sem --muted-3 aqui também — ver a nota em :root. No claro ele era o
       #98A2B3, o mesmo aço da marca que saiu do kit pelo mesmo motivo.) */
    --surface:#FFFFFF;
    /* Ver a nota em :root. No claro o efeito é mais crítico: o card é branco
       PURO, e um campo a 2% dele fica invisível.
       Escurecido de #F2F4F7 para #E8EDF3 em 2026-08-11, a pedido: contra o card
       branco o degrau anterior ainda lia como "mesma superfície". Fica mais
       escuro que --panel-soft de propósito — este token é a superfície de
       ENTRADA (field-shell, filter-shell, checkbox), não um tom de seção, e no
       foco o campo sobe para --panel-strong (branco), invertendo o recuo. */
    --panel:#E8EDF3;
    --panel-strong:#FFFFFF;
    --panel-soft:#EEF2F6;
    --panel-softer:#F6F8FA;
    --heading:#1F2937;
    --shadow-color: rgba(31,41,55,0.08);
    --sombra: 0 2px 16px rgba(31,41,55,.08);
    /* Mesma faixa segura do escuro — ver a nota em :root. */
    --grad: linear-gradient(135deg,#9DC5E4 0%,#4C7FB0 100%);
    --on-grad:#1F2937;
    --brand-cel:#1F2937;
    --section-card-bg:#F6F8FA;
    --section-card-border:#DFE5EC;
    --note-bg:#EAF2F9;
    --note-border:#C4DCEE;
    /* Título de seção é HIERARQUIA, não acento: cinza escuro, não a cor da
       marca. Senão cada bloco da ficha vira uma faixa colorida. */
    --section-header:#52657A;
    --hairline-rgb: 31,41,55;
    --hair-rgb: 176,190,205;
    --titlebar-bg: linear-gradient(135deg, rgba(157,197,228,0.28) 0%, rgba(76,127,176,0.18) 130%);
    --titlebar-text:#33526E;
    /* bordas de formulario/grid ficavam quase invisiveis no claro (mesmo alpha
       baixo do escuro, pensado pro fundo quase-preto) -- sobe a opacidade so
       aqui, mesma cor base (--muted), pra dar definicao sem virar cor nova */
    --fb-10: 0.35; --fb-12: 0.35; --fb-15: 0.45; --fb-16: 0.45; --fb-18: 0.45;
    --fb-20: 0.5; --fb-22: 0.5; --fb-25: 0.55; --fb-40: 0.6;
    --cyan-accent-rgb: 51,82,110;
    --cta-success-1: #9DC5E4; --cta-success-2: #4C7FB0;
    --btn-grad-2: #4C7FB0;
    /* zebra no claro: ardósia bem leve sobre o fundo claro das grids */
    --zebra-row: rgba(31,41,55,0.028);
    /* semânticas no claro: tons escuros o bastante para texto sobre branco.
       Sem âmbar — ver a nota em :root. Aviso é o vermelho CLARO (#DC2626,
       4.8:1) e erro o ESCURO (#B91C1C, 6.5:1). */
    /* O verde de TEXTO precisa ser o escuro: #16A34A, que estava aqui desde
       antes do rebrand, dá 3.30:1 sobre o card branco — falhava calado no
       "Liberado" da grade. Só apareceu ao medir também as cores usadas como
       TEXTO, não apenas as de superfície. */
    --ok:#15803D;    --ok-2:#166534;    --ok-rgb:21,128,61;
    --erro:#B91C1C;  --erro-2:#991B1B;  --erro-rgb:185,28,28;
    --aviso:#DC2626; --aviso-2:#B91C1C; --aviso-rgb:220,38,38;
    --info:#52657A;
    /* Âmbar escuro: o #FBBF24 do tema escuro não tem contraste sobre branco. */
    --provisorio:#B45309; --provisorio-rgb:180,83,9;
    /* Aqui o âmbar é escuro (contraste sobre branco), então o rótulo inverte. */
    --provisorio-2:#92400E; --on-provisorio:#FFFFFF;
    --graf-atrasado:#CA8A04;
    /* --tipo-pj/--tipo-pf: ver a nota completa em :root. Tons escurecidos para
       contraste sobre o card claro (medidos contra #F6F8FA):
         --tipo-pj #047857 -> 5.15:1     --tipo-pf #7C5A22 -> 5.90:1 */
    --tipo-pj:#047857; --tipo-pj-rgb:4,120,87;
    --tipo-pf:#7C5A22; --tipo-pf-rgb:124,90,34;
    /* No claro o verde vai para o tom ESCURO com rótulo branco (5.0:1 a 7.0:1);
       o #16A34A do texto é claro demais para branco e escuro demais para
       ardósia — ficava em 4.45:1, falhando por um fio. As superfícies de alerta
       são as mesmas do tema escuro; ver a nota em :root. */
    --ok-sup:#15803D; --ok-sup-2:#166534;
    --erro-sup:#B91C1C; --erro-sup-2:#991B1B;
    --aviso-sup:#DC2626; --aviso-sup-2:#B91C1C;
    /* Cada semântica tem a SUA cor de rótulo, e elas não coincidem. O vermelho
       é escuro e pede BRANCO. O verde é claro demais para branco (3.32:1) e
       pede escuro. O aviso pinta o botão com --aviso-sup, que é amarelo CLARO,
       e por isso também pede escuro — era branco aqui até 2026-08-11 e, quando
       a superfície clareou, o rótulo caiu para 1.67:1. Medido na página, não
       deduzido: foi assim que esse erro apareceu antes de ir para a tela. */
    --on-ok:#FFFFFF; --on-erro:#FFFFFF; --on-aviso:#FFFFFF;
  }
  html.light .text-white{ color:var(--heading); }
  /* Zebra em todas as grids do projeto: linhas PARES do corpo (thead não é
     afetado) com um tom neutro bem leve. Desde 2026-08-31 ela é o ÚNICO
     separador horizontal — a borda que havia em cada linha das grades filhas
     saiu, porque dois separadores fazendo o mesmo trabalho só sujam. */
  tbody tr:nth-child(even){ background: var(--zebra-row); }

  /* DIVISOR DE COLUNA, global (2026-08-31, a pedido do dono). Nasceu na grade
     de Senhas, onde IP/WS e Ações passaram a empilhar dois ícones cada e viravam
     um bloco só sem a linha; virou regra para as tabelas não divergirem.
     `+` e não `:not(:first-child)`: assim a primeira coluna nunca ganha traço, e
     um traço colado na borda do cartão é sujeira, não separação.
     `--fb-25` e não `--fb-12` (o das horizontais): a linha horizontal atravessa
     a grade inteira e se lê mesmo fraca; um traço vertical de uma célula não tem
     esse luxo. Medido na tela — a 0.16 o dono não conseguia enxergar. */
  thead th + th,
  tbody td + td{ border-left:1px solid rgba(var(--hair-rgb),var(--fb-25)); }
  /* Botões da paginação da grade de clientes.
     min-width/height/padding em rem junto com a fonte: a caixa é FIXA e o texto
     cresce dentro dela com o botão "Aa" — converter só o font-size trocaria um
     defeito (não aumenta) por outro (aumenta e corta). 2rem = os 32px de antes. */
  .pg-btn{ min-width:2rem; height:2rem; padding:0 0.5625rem; border-radius:8px; border:1px solid rgba(var(--hair-rgb),var(--fb-25)); color:var(--text); background:var(--panel-softer); font-size:0.8125rem; font-weight:600; line-height:1; display:inline-flex; align-items:center; justify-content:center; transition:opacity .15s, background .15s; }
  .pg-btn:hover:not(:disabled){ background:var(--panel-soft); }
  .pg-btn:disabled{ opacity:.4; cursor:not-allowed; }
  /* A barra de paginação reserva a altura de um botão MESMO VAZIA (2rem = a
     altura do .pg-btn acima). Dois motivos, e o primeiro é um defeito real:
     ela é esvaziada durante a busca (limparPaginacaoDeClientes), e é
     exatamente nesse instante que computeClientPageSize mede o que existe
     abaixo da grade — com altura zero, a conta sobrava linha e a página ganhava
     a barra de rolagem que o cálculo existe para evitar. O segundo é que a
     grade para de dar um pulo quando a barra reaparece no fim do carregamento. */
  #client-pagination{ min-height:2rem; }
  html,body{
    background: var(--bg-0);
    /* A pilha é a do kit: com o Segoe UI como fallback intermediário, se o
       Google Fonts não carregar a página cai num tipo próximo, e não no
       sans-serif genérico (Arial, no Windows). */
    font-family:'Inter','Segoe UI',sans-serif;
    color:var(--text);
  }
  .font-display{font-family:'Sora','Segoe UI',sans-serif;}
  /* Cabeçalho de tabela é título: entra na fonte de display, como manda a §3 do
     design-system. Vale para todas as grades de uma vez, em vez de marcar
     .font-display tabela a tabela e esquecer metade. */
  thead th{ font-family:'Sora','Segoe UI',sans-serif; }

  /* ESCALA DE FONTE — por que estas classes existem.
     O botão "Aa" (acessibilidade) só altera o font-size da RAIZ, em js/app.js.
     Isso escala apenas o que está declarado em rem/em: tudo que estivesse fixo
     em px ficava parado enquanto o resto crescia. Era o caso de 68 utilitários
     `text-[Npx]` do Tailwind (o corpo de 12 grades inteiro, entre outros) e de
     6 regras daqui — o menu, os chips, a paginação e o status não aumentavam.

     Os valores são conversão EXATA dos px que estavam no lugar (16px = 1rem),
     então no nível normal nada mudou de aparência; o que mudou é que agora
     acompanham o botão. O nome carrega o px de origem de propósito: `fs-135`
     é o antigo 13.5px, e assim continua greppável contra o design.

     text-xs (12px) e text-sm (14px) do próprio Tailwind já são rem e não
     precisam de equivalente aqui — os `text-[12px]`/`text-[14px]` que havia
     foram para eles, não para uma classe nova. */
  .fs-9  { font-size:0.5625rem; }   /*  9px  */
  .fs-10 { font-size:0.625rem; }    /* 10px  */
  .fs-105{ font-size:0.65625rem; }  /* 10.5px*/
  .fs-11 { font-size:0.6875rem; }   /* 11px  */
  .fs-115{ font-size:0.71875rem; }  /* 11.5px*/
  .fs-13 { font-size:0.8125rem; }   /* 13px  */
  .fs-135{ font-size:0.84375rem; }  /* 13.5px*/

  /* Os dois controles flutuantes (Aa e tema) já cresciam sozinhos: o círculo é
     w-11/h-11, que o Tailwind emite em rem. O que não crescia era o CONTEÚDO —
     o glifo "Aa" estava com font-size inline em px e os ícones de sol/lua com
     width/height fixos no atributo do SVG. Resultado a 125%: círculo de 55px
     com desenho de 18px boiando dentro. Aqui o conteúdo acompanha o botão.
     1.1875rem/0.75rem = os 19px/12px do glifo; 1.125rem = os 18px do ícone. */
  #font-scale-toggle .fs-aa-maior{ font-size:1.1875rem; }
  #font-scale-toggle .fs-aa-menor{ font-size:0.75rem; }
  #theme-toggle svg{ width:1.125rem; height:1.125rem; }

  /* Respiro no pé do dashboard por causa do que flutua sobre o fim da página.
     Eram DOIS flutuantes; desde 2026-09-04 é só a barra de indicadores — os
     controles de fonte e tema subiram para o topo fino, a pedido do dono.

     A conta atual, medida a 390x844: a barra fica a `bottom-5` (1.25rem) e tem
     ~3.3rem de altura, então ocupa ~73px a partir da base. As 6rem (96px)
     deixam 23px de folga. Ela NÃO quebra em duas linhas numa tela estreita —
     tem `overflow-x-auto` e rola —, então essa altura não cresce.

     A conta atual: a faixa de totais ocupa ~3.5rem coladas na base, e as 4.5rem
     daqui deixam ~1rem de folga entre a paginação e ela. Eram 6rem enquanto a
     barra era uma pílula flutuante a 20px do chão — e aquelas 6rem custavam uma
     linha inteira da grade na tela do dono (sobravam 67px vazios, e a linha
     mede 67).

     Em rem de propósito: a folga acompanha a escala de fonte, que é o que faz
     a faixa crescer. Com o respiro em px, o botão de página ia parar DEBAIXO
     dela e ficava inclicável (medido em 112,5% e 125%).
     Seletor de ID de propósito — vence .py-6/.sm:py-8 do Tailwind sem !important. */
  #dashboard-screen{ padding-bottom:4.5rem; }

  /* LARGURA MÁXIMA DO SISTEMA — o teto que a grade de clientes e os modais
     grandes compartilham. 1920px desde 2026-09-04 (era 1280px).

     ⚠️ É UMA CLASSE, e não o `max-w-[1280px]` repetido, porque o número estava
     escrito em OITO lugares: o contêiner do dashboard, cinco modais do
     index.html e dois montados em js/cobranca.js. Subir de 1280 para 1920
     significou editar os oito e conferir se nenhum tinha ficado para trás — e
     um deles (o de notas em lote) já havia sido subido sozinho para 1920 horas
     antes, virando um segundo literal com o mesmo papel. Uma tela que quer o
     teto do sistema agora pede `class="largura-sistema"`; quem quer outra
     medida continua usando o utilitário do Tailwind, e a diferença fica visível
     na marcação.

     Mora no app.css (carregado DEPOIS do tailwind.css) para vencer um
     `max-w-*` do Tailwind na mesma especificidade, sem `!important`. */
  :root{ --largura-sistema:1920px; }
  .largura-sistema{ max-width:var(--largura-sistema); }

  /* ===================== BARRA LATERAL =====================
     Spec: docs/superpowers/specs/2026-09-04-barra-lateral-design.md

     DUAS VARIÁVEIS, e a diferença entre elas é o que faz a gaveta custar três
     linhas em vez de um conjunto paralelo de regras:
       --barra-tamanho  quanto a barra MEDE            (constante)
       --barra-largura  quanto de espaço ela RESERVA   (zera na gaveta)
     Tudo que recua lê a segunda. Zerá-la no @media devolve o dashboard E os 13
     modais ao comportamento anterior de uma vez só. */
  :root{ --barra-tamanho:15rem; --barra-largura:var(--barra-tamanho); --topo-altura:3.5rem; }

  /* ⚠️ `#barra-lateral.hidden` PRECISA estar escrito, e não é redundância com o
     .hidden do Tailwind: um seletor de ID (1,0,0) vence uma classe (0,1,0) em
     qualquer ordem de arquivo, então o `display:flex` daqui anularia o
     `display:none` do utilitário e a barra apareceria por cima da tela de
     login. Vale para o #barra-veu pelo mesmo motivo. */
  #barra-lateral{
    /* ⚠️ z-57, ACIMA das telas de trabalho (z-50). No monitor grande tanto faz,
       porque o recuo impede que elas se encontrem — mas no celular a barra vira
       gaveta, `--barra-largura` zera e a tela de trabalho ocupa tudo. Em z-45 a
       gaveta abria DEBAIXO do modal: o botão respondia, o véu aparecia e a
       navegação, não. Continua abaixo dos diálogos (z-60+), que devem cobri-la. */
    position:fixed; left:0; top:0; bottom:0; width:var(--barra-tamanho); z-index:57;
    display:flex; flex-direction:column; padding:1rem 0.75rem;
    background:var(--panel-softer); border-right:1px solid var(--border);
    /* Da gaveta, mas moram aqui porque valem nos DOIS gatilhos dela (largura e
       escolha) — ver o bloco "GAVETA — DOIS GATILHOS", mais abaixo. Barra fixa
       não se move, então a transição fica inerte. */
    transition:transform .2s ease;
    box-shadow:0 0 40px -8px var(--shadow-color);
  }
  #barra-lateral.hidden{ display:none; }

  /* Flex desde 2026-09-08, para o botão de ocultar dividir a linha com o
     lockup. `space-between` e não `gap`: o lockup fica à esquerda e a alça
     ancorada na direita, independente da largura do logo — e os dois <img>
     nunca aparecem juntos (um é do tema claro, o outro do escuro). */
  .barra-marca{
    display:flex; align-items:center; justify-content:space-between; gap:0.5rem;
    padding:0.25rem 0.5rem 1rem;
    border-bottom:1px solid rgba(var(--hair-rgb),var(--fb-15));
    margin-bottom:0.875rem;
  }
  /* Mesma troca por tema do lockup do cabeçalho antigo (o manual proíbe a
     versão clara sobre fundo escuro); só a altura muda, porque aqui ele divide
     a largura com nada e não precisa competir com uma linha de navegação. */
  .barra-lockup{ height:2.125rem; width:auto; display:block; }
  .barra-lockup-claro{ display:none; }
  html.light .barra-lockup-claro{ display:block; }
  html.light .barra-lockup-escuro{ display:none; }

  /* Rola só a navegação, e só quando não couber: a marca e a conta ficam
     ancoradas. min-height:0 porque um filho flex não encolhe abaixo do próprio
     conteúdo sem ele, e aí quem rolaria seria a barra inteira. */
  .barra-nav{
    flex:1; min-height:0; overflow-y:auto;
    display:flex; flex-direction:column; gap:0.875rem;
  }
  .barra-secao{ display:flex; flex-direction:column; gap:0.125rem; }
  .barra-grupo{
    font-size:0.6875rem; font-weight:600; letter-spacing:0.12em; text-transform:uppercase;
    color:var(--muted-2); padding:0 0.625rem 0.25rem; margin:0;
  }
  .barra-item{
    display:flex; align-items:center; gap:0.5625rem; width:100%;
    padding:0.5rem 0.625rem; border-radius:8px;
    font-size:0.84375rem; font-weight:500; color:var(--text); text-align:left;
    transition:background .15s ease, color .15s ease;
  }
  .barra-item:hover{ background:var(--card); }
  /* O ativo segue o padrão que já existe na barra da ficha
     (.client-nav-btn.ativa): mesma cor, mesma opacidade de fundo. Duas
     convenções diferentes para "onde eu estou" no mesmo painel seria pior que
     nenhuma. */
  .barra-item.ativa{ color:var(--cyan); background:rgba(var(--cyan-accent-rgb),0.14); }

  .barra-conta{
    position:relative; margin-top:0.875rem; padding-top:0.875rem;
    border-top:1px solid rgba(var(--hair-rgb),var(--fb-15));
  }
  /* ⚠️ O `.dropdown-panel-acima` NAO fica aqui: ele tem de vir DEPOIS do
     `.dropdown-panel` no arquivo, que esta bem mais abaixo. Mesma
     especificidade (uma classe cada), entao quem vence e o ultimo -- e daqui o
     `top:auto` era desfeito pelo `top:calc(100% + 8px)` do proprio
     .dropdown-panel. O menu da conta abria para baixo e sumia embaixo da tela
     (dono, 2026-09-04). Segundo caso do mesmo erro no mesmo dia; o primeiro foi
     o #client-nav-bar. */

  /* ===================== TOPO FINO =====================
     Faixa fixa no alto da área útil, FORA do #dashboard-screen. Ficava dentro
     dele e sumia junto com a grade quando uma tela de trabalho abria, o que
     deixava o título só de enfeite: nunca dava tempo de ele dizer outra coisa
     além de "Clientes" (dono, 2026-09-04). Agora as telas de trabalho começam
     abaixo dele e ele fica.

     Fundo opaco de propósito: o conteúdo rola por baixo, e sem ele a grade
     apareceria atravessando o cabeçalho. */
  #topo-fino{
    position:fixed; top:0; left:var(--barra-largura); right:0; height:var(--topo-altura);
    z-index:45; display:flex; align-items:center; padding:0 1rem;
    background:var(--bg-0); border-bottom:1px solid rgba(var(--hair-rgb),var(--fb-15));
  }
  #topo-fino.hidden{ display:none; }
  @media (min-width:640px){ #topo-fino{ padding:0 2rem; } }
  .topo-fino-interno{ display:flex; align-items:center; gap:0.75rem; width:100%; }
  .topo-direita{ margin-left:auto; display:flex; align-items:center; gap:0.625rem; }

  /* CONTROLES DE ACESSIBILIDADE — o mesmo elemento em dois lugares. Ver o
     comentário no index.html: quem troca o pai é o js/app.js. */
  #controles-acessibilidade{ display:flex; align-items:center; gap:0.5rem; }
  #controles-acessibilidade.flutuante{
    position:fixed; bottom:1.25rem; right:1.25rem; z-index:40;
  }
  /* No topo fino ele é um item de linha como os outros, e os botões encolhem:
     44px eram a medida de um alvo isolado no canto da tela, e numa faixa de
     56px de altura eles encostariam nas bordas.
     ⚠️ `#…button` é (1,0,1) e vence o `.w-11` (0,1,0) do Tailwind por
     especificidade — não precisa de !important. */
  #controles-acessibilidade.no-topo{ position:static; }
  #controles-acessibilidade.no-topo button{ width:2.375rem; height:2.375rem; }
  /* O divisor que o dono pediu: diz que o sino é um assunto e estes são outro.
     Mora no ::before do bloco para existir só quando ele está no topo — solto
     no HTML, sobraria um risco no ar na tela de login. */
  #controles-acessibilidade.no-topo::before{
    content:''; width:1px; height:1.375rem; flex:0 0 auto;
    background:rgba(var(--hair-rgb),var(--fb-25)); margin-right:0.125rem;
  }
  /* Só existe onde a barra é gaveta. Acima de 1024px a navegação está sempre na
     tela e um botão para abri-la não teria o que fazer. */
  .topo-menu-btn{
    display:none; align-items:center; justify-content:center;
    padding:0.5rem; border-radius:8px; color:var(--muted);
    border:1px solid rgba(var(--hair-rgb),var(--fb-25)); background:var(--panel-softer);
  }
  .topo-menu-btn:hover{ color:var(--text); }

  /* ===================== O RECUO ===================== */
  /* ⚠️ `width:auto` JUNTO DA MARGEM, e não a margem sozinha: o
     #dashboard-screen carrega `w-full` do Tailwind (`width:100%`), que resolve
     contra o BODY e ignora a margem. Só com a margem ele ficava 1920px de
     largura começando em 240 — 240px passando da tela, com barra de rolagem
     horizontal no painel inteiro. Medido aqui em 2026-09-04, e invisível numa
     olhada: o excesso cai fora da janela, então o que se vê é a grade
     "cortada" à direita, que parece defeito da tabela. */
  #dashboard-screen{
    margin-left:var(--barra-largura); width:auto;
    /* O topo fino e `fixed` e nao ocupa layout: sem este respiro a primeira
       linha da grade nasceria debaixo dele. Soma o py-8 que o Tailwind ja dava. */
    padding-top:calc(var(--topo-altura) + 2rem);
  }

  /* As 13 telas de trabalho (a camada z-50). Vence o `inset:0` do utilitário
     .inset-0 por ordem de arquivo — mesma especificidade, e o app.css carrega
     depois do tailwind.css. É o mesmo mecanismo da .largura-sistema.
     ⚠️ Classe nomeada, e não um seletor sobre .z-50: prender o layout a um
     utilitário faria qualquer elemento futuro com z-50 recuar sem que ninguém
     tivesse pedido, e o defeito apareceria longe da causa. */
  .tela-de-trabalho{ left:var(--barra-largura); top:var(--topo-altura); }

  /* ⚠️ A CLASSE VALE PARA QUALQUER CAMADA `fixed` DA TELA, e não só para o
     contêiner. Dezenove dos vinte e um véus são `absolute` e recuam de carona
     com o pai; DOIS são `fixed` (#systems-overlay e #client-overlay), posicionam
     contra a viewport e por isso passavam por cima da barra — o modal recuava
     certo e o escurecido dele cobria o menu (dono, 2026-09-04). A divergência
     entre os dois estilos de véu é anterior à barra; só ficou visível agora. */

  /* A GRADE SAI DE CENA enquanto uma tela de trabalho está aberta (dono,
     2026-09-04): a grade de clientes é o fundo do painel, e ver o fundo
     borrado em volta do modal é ruído, não profundidade.

     ⚠️ `visibility` E NÃO `display:none`, de propósito: `computeClientPageSize`
     (js/cliente-grade.js) decide quantas linhas cabem medindo o `thead` com
     getBoundingClientRect, e o listener de `resize` só se cala quando o
     dashboard tem a classe `hidden` do Tailwind. Com `display:none` aqui, uma
     janela redimensionada com modal aberto mediria zero e recarregaria a grade
     com o número de linhas errado. `visibility` preserva o layout, então a
     conta continua valendo. */
  #dashboard-screen.com-tela-aberta{ visibility:hidden; }

  /* ===================== GRADE DE CLIENTES NO CELULAR =====================
     Veio do style inline do <table>. Ver o comentário no index.html para o
     porquê do valor: é a soma das colunas fixas mais o mínimo do nome, e abaixo
     dele rolar é melhor que espremer. */
  #clients-table{ min-width:50rem; }

  /* CÓDIGO/CNPJ EM COLUNA PRÓPRIA — só em tela grande (dono, 2026-09-05).
     Escondida por padrão; a media query "TELA GRANDE" mais abaixo é quem liga.

     ⚠️ ID + CLASSE DE PROPÓSITO, e não `.col-grande{display:none}` sozinho.
     No modo cartão (max-width:903px, mais abaixo) o `#clients-table td` vira
     `display:block` — regra também com `#clients-table`, então empatada em
     especificidade com uma `.col-grande{display:none}` sem prefixo perderia
     por ORDEM (a do cartão vem depois no arquivo) e a coluna reapareceria como
     linha de cartão duplicando o que o subtítulo já mostra. Com o `#clients-table`
     também aqui, esta regra tem uma classe a mais de especificidade e vence
     INDEPENDENTE da ordem — é a mesma lição das outras três vezes que a ordem
     mordeu neste arquivo, resolvida na raiz em vez de mais uma para a pilha. */
  #clients-table .col-grande{ display:none; }
  /* O teto é o que faz o cabeçalho da tabela grudar e a lista rolar por dentro;
     o piso impede a caixa de virar um risco quando a busca não devolve nada.

     ⚠️ ESTE TETO É SÓ O VALOR INICIAL — quem manda é o
     `computeClientPageSize` (js/cliente-grade.js), que o reescreve a partir da
     medição real assim que a grade renderiza. As `21rem` eram 336px reservados
     à mão para tudo que fica acima e abaixo da grade, e em 2026-09-04 a soma
     real virou 352: o topo fino passou a ser uma faixa `fixed` e ninguém
     lembrou de re-tunar a constante. O conteiner ficou 16px alto demais, a
     página passou a rolar, e a rede de segurança da grade creditava essa sobra
     ao rodapé — tirando uma linha em toda tela. O número aqui vale só até o
     primeiro render; depois dele, medida. */
  #clients-scroll{ max-height:calc(100vh - 21rem); min-height:12rem; }

  /* Abaixo de 768px a LINHA VIRA CARTÃO (dono, 2026-09-04: "responsivo não é só
     abrir e não ter estouro, é funcionar"). Seis colunas num visor de 390px
     cabiam — rolando de lado para ler uma linha, o que não é usar.

     ⚠️ CSS PURO, sem tocar no renderizador: o `data-rotulo` de cada <td> vira o
     rótulo por `::before`, então quem monta a linha continua montando UMA
     estrutura só. Duas marcações para a mesma grade seria a garantia de as duas
     divergirem no primeiro campo novo.

     ⚠️ Não precisa de `!important` em lugar nenhum: `#clients-table td` é
     (1,0,1) e vence `.text-center` (0,1,0) do Tailwind por especificidade, não
     por ordem.

     ⚠️ O CORTE EM 903px É MEDIDO, não escolhido: a tabela pede 800px (o
     min-width acima) e some 104px de recuo até a janela — 64 do
     #dashboard-screen mais 40 do card. Abaixo de 904px ela não cabe, e o
     contêiner passa a exigir arrasto lateral. Medido a 768: tabela de 800 num
     contêiner de 703, 97px escondidos, e a coluna que sumia era a de Ações.
     Por isso o tablet em pé também recebe cartões — foi o caso que o dono
     descreveu como "abrir e não funcionar". */
  @media (max-width:903px){
    /* O contêiner deixa de rolar sozinho: no celular quem rola é a página, e um
       painel de cartões dentro de uma caixa de altura fixa dá duas rolagens
       concorrentes na mesma tela. */
    #clients-scroll{ max-height:none; overflow-x:visible; }
    #clients-table{ min-width:0; white-space:normal; }
    #clients-table thead{ display:none; }
    #clients-table, #clients-table tbody, #clients-table tr, #clients-table td{ display:block; width:auto; }

    #clients-table tr{
      border:1px solid var(--section-card-border); border-radius:12px;
      background:var(--panel-softer); margin-bottom:0.75rem; overflow:hidden;
    }
    #clients-table td{ padding:0.5rem 0.875rem; text-align:left; }

    /* A primeira célula (nome, nº e documento) é o cabeçalho do cartão; a
       última (os botões) é o rodapé. Nenhuma das duas leva rótulo: o nome se
       explica e os ícones já têm title. */
    #clients-table td:first-child{
      padding:0.75rem 0.875rem;
      border-bottom:1px solid rgba(var(--hair-rgb),var(--fb-15));
    }
    #clients-table td:last-child{
      padding:0.625rem 0.875rem;
      border-top:1px solid rgba(var(--hair-rgb),var(--fb-15));
      background:var(--card);
    }

    /* Rótulo à esquerda, valor à direita — a leitura de ficha, que é como se lê
       um cartão. */
    #clients-table td[data-rotulo]{
      display:flex; align-items:center; justify-content:space-between; gap:1rem;
    }
    #clients-table td[data-rotulo]::before{
      content:attr(data-rotulo);
      font-size:0.6875rem; font-weight:600; letter-spacing:0.1em;
      text-transform:uppercase; color:var(--muted-2); flex:0 0 auto;
    }

    /* O `truncate` existe por causa da COLUNA — nome comprido empurrava a
       tabela e criava barra horizontal (ver o comentário no index.html). No
       cartão não há coluna que empurrar, e cortar "JOSE CARLOS SKRZYSZOWSKI
       JUNIOR ADVOGADOS ASSOCIADOS" em "JOSE CARLOS SKRZYSZOWSKI JUNIOR ..."
       esconde justamente o que identifica o cliente. Aqui ele quebra em duas
       linhas. Vale para a célula e para os <p> de dentro dela. */
    #clients-table .truncate,
    #clients-table td.truncate{ overflow:visible; text-overflow:clip; white-space:normal; }
    #clients-table td[colspan]{ text-align:center; }

  }

  /* Os dois flutuantes centrados na VIEWPORT passam a centrar na área útil.
     ⚠️ Esquecer isto não quebra nada — só desloca os dois 120px para a
     esquerda, que é desalinhamento do tipo que se olha três vezes sem ver. */
  /* ⚠️ O #client-nav-bar NAO e corrigido aqui, e sim dentro da propria regra
     dele, la embaixo. Uma linha solta neste bloco tem a MESMA especificidade da
     original e perde por vir ANTES no arquivo -- foi exatamente o que aconteceu
     na primeira tentativa: o #indicadores-bar (que nao tem regra posterior)
     centrou certo e o da ficha continuou 120px a esquerda. */
  /* A BARRA DE TOTAIS E UMA FAIXA FIXA NO RODAPE, em qualquer largura.
     Era uma pilula flutuante centrada, e o preco dela era um vao: para nao
     cobrir a paginacao ela exigia 96px de respiro no fim da pagina, dos quais
     85 eram os dela (20px da base + 65px de altura). Medido na tela do dono
     (1588x1066): sobravam 67px vazios embaixo da grade — uma linha inteira que
     nao cabia por menos de um pixel (avail 670 / linha 67 = 9,99).

     Como faixa ela ocupa o lugar que ja gastava, e o respiro cai para pouco
     mais que a altura dela. O que era vao vira barra. De quebra, ela para de
     passar por cima do conteudo no meio da rolagem, e a tela grande passa a se
     parecer com a do celular, que ja era assim. */
  #indicadores-bar{
    position:fixed; top:auto; bottom:0; left:var(--barra-largura); right:0;
    transform:none; max-width:none; width:auto; z-index:44; margin:0;
  }
  #indicadores-bar > div{
    border-radius:0; border-left:0; border-right:0; border-bottom:0;
    padding:0.625rem 1rem; box-shadow:none; justify-content:center;
  }

  /* ===== A BARRA DE INDICADORES NO CELULAR E NO TABLET EM PE =====
     Dono, 2026-09-04: sem as palavras, e numa FAIXA FIXA NO RODAPE — o par do
     topo fino, na outra ponta.

     ⚠️ JA FOI `sticky` LOGO ABAIXO DO TOPO, e durou uma versao. Ocupar espaco
     no fluxo resolvia sozinha a coordenacao com o JS (a barra nasce `hidden` e
     so aparece quando os numeros chegam), mas o preco era o que o dono viu na
     hora: grudada no alto, ela TRAVA os cartoes que sobem — o conteudo some por
     baixo dela bem no meio da leitura. No rodape isso nao acontece, porque
     ninguem le de baixo para cima.

     A coordenacao volta a ser necessaria e sai de graca: o respiro do rodape
     e RESERVADO SEMPRE (5rem), apareca a barra ou nao. Espaco vazio embaixo do
     ultimo cartao e invisivel — e so mais fundo de pagina —, entao nao ha o que
     um `if` no JS fosse melhorar aqui.

     ⚠️ ESTE BLOCO PRECISA VIR DEPOIS da regra acima: as duas sao
     `#indicadores-bar` (1,0,0) e quem vence e a ultima. Escrito junto do bloco
     dos cartoes, mais acima, o `left` de la desfazia o daqui. Terceira vez que
     a ordem morde neste arquivo hoje. */
  @media (max-width:903px){
    /* SEM AS PALAVRAS — fica o ponto colorido e o numero.
       ⚠️ Escondido para o OLHO, nao para o leitor de tela: com `display:none` a
       barra viraria quatro numeros sem nome para quem usa leitor, e a cor, que
       e o que substitui o rotulo, nao e lida. */
    #indicadores-bar .ind-rotulo{
      position:absolute; width:1px; height:1px; padding:0; margin:-1px;
      overflow:hidden; clip-path:inset(50%); white-space:nowrap; border:0;
    }

    /* Sem respiro proprio: a faixa do rodape agora e a mesma nas duas larguras,
       entao as 4.5rem da regra geral ja servem aqui. */
  }

  /* ===================== GAVETA — DOIS GATILHOS =====================
     A barra vira gaveta por LARGURA (abaixo de 1024px, como sempre foi) ou por
     ESCOLHA (html.barra-oculta, dono 2026-09-08: "tem horas que eu vou querer
     trabalhar sem o menu durante o dia, como se tivesse no responsivo").

     ⚠️ NÃO É MODO NOVO: é o mesmo estado com um gatilho a mais. Quem devolve a
     largura ao painel inteiro — grade, as 13 telas de trabalho, topo fino e
     rodapé — é `--barra-largura:0px`, porque todos recuam lendo essa variável.
     Por isso os dois blocos abaixo dizem a MESMA coisa: mexer num pede mexer
     no outro, e é de propósito que estejam colados.

     Transição e sombra saíram para a regra base de #barra-lateral: valem nos
     dois gatilhos e não custam nada enquanto ela está fixa (barra parada não
     anima). */
  @media (max-width:1023px){
    :root{ --barra-largura:0px; }
    #barra-lateral{ transform:translateX(-100%); }
    .topo-menu-btn{ display:flex; }
  }

  /* ⚠️ `html.barra-oculta` (0,1,1) e não `:where(...)` PARA A VARIÁVEL: ela
     precisa vencer o `:root` (0,1,0) que a define cheia, mais acima. */
  html.barra-oculta{ --barra-largura:0px; }
  /* ⚠️ Aqui, ao contrário, `:where()` é o ponto: ele não soma especificidade,
     então esta regra fica em (1,0,0) — igual à base de #barra-lateral, que ela
     vence só pela ordem — e continua PERDENDO para `#barra-lateral.aberta`
     (1,1,0), logo abaixo. Sem o :where(), `html.barra-oculta #barra-lateral`
     seria (1,1,1) e venceria o `.aberta`: a gaveta nunca abriria no monitor
     grande, que é justamente o que este bloco existe para permitir. */
  :where(html.barra-oculta) #barra-lateral{ transform:translateX(-100%); }
  :where(html.barra-oculta) .topo-menu-btn{ display:flex; }

  /* Comum aos dois gatilhos: a gaveta aberta cancela o deslocamento. */
  #barra-lateral.aberta{ transform:none; }

  /* O botão que oculta a barra vive DENTRO dela (dono, 2026-09-08: escolheu
     esta opção em vez de um botão fixo no topo) — o objeto que some carrega o
     próprio controle, e quem o traz de volta é o hambúrguer do topo fino.
     Some na faixa estreita pela mesma razão que o hambúrguer só existe lá: ali
     a barra JÁ é gaveta por largura, e "ocultar" não teria o que fazer. */
  .barra-alternar{
    display:flex; align-items:center; justify-content:center;
    width:1.75rem; height:1.75rem; flex:0 0 auto; border-radius:8px;
    color:var(--muted-2); background:transparent; border:1px solid transparent;
    transition:color .15s ease, background-color .15s ease, transform .2s ease;
  }
  .barra-alternar:hover{ color:var(--text); background:var(--panel-strong); }
  /* Oculta, a seta aponta para o outro lado: a mesma alça diz "trazer de
     volta" sem trocar de ícone no JS. */
  :where(html.barra-oculta) .barra-alternar{ transform:rotate(180deg); }
  @media (max-width:1023px){
    .barra-alternar{ display:none; }
  }
  @media (prefers-reduced-motion: reduce){
    #barra-lateral{ transition:none; }
  }

  #barra-veu{ position:fixed; inset:0; z-index:56; background:rgba(2,4,9,0.6); }
  #barra-veu.hidden{ display:none; }

  /* BARRA DE NAVEGAÇÃO DA FICHA (js/cliente-navegacao.js).
     Até 2026-09-05 flutuava solta no <body>, por cima do modal do cliente,
     1,25rem abaixo do topo fino. Pedido do dono: "eu queria que ele ficasse
     dentro daquele banner fixo, centralizado, junto daquela barra" — agora
     mora DENTRO de #topo-fino-interno (o JS a anexa lá, não mais no body).

     ⚠️ POR ISSO A CENTRALIZAÇÃO FICOU MAIS SIMPLES, e não é só troca de
     posição. A conta antiga (`calc(50% + var(--barra-largura)/2)`) existia
     porque a barra centralizava contra a VIEWPORT inteira, e a área útil da
     ficha começa depois da barra lateral — sem o ajuste ela saía 120px fora
     do centro. Agora o pai (#topo-fino-interno) JÁ é só a área útil (o
     #topo-fino que o contém tem `left:var(--barra-largura)`): centralizar
     contra ele com `left:50%` já dá a conta certa, e ela vale sozinha na
     gaveta também, sem precisar zerar variável nenhuma.

     `position:absolute` (não mais `fixed`): a posição agora é relativa ao PAI
     (#topo-fino-interno, com `position:relative`), não à viewport. z-index não
     precisa mais vencer o #client-modal (z-50) — a barra vive inteira dentro
     de #topo-fino (z-45), que ocupa 0..topo-altura, e o modal só começa DEPOIS
     disso (`.tela-de-trabalho{ top:var(--topo-altura) }`): os dois nunca se
     sobrepõem, então a disputa de z-index deixou de existir.

     Tudo em rem: cresce junto com o botão Aa, como o resto da tela. */
  #client-nav-bar{
    position:absolute; left:50%; top:50%; transform:translate(-50%, -50%);
    display:flex; align-items:center; gap:0.25rem;
    padding:0.375rem; border-radius:999px;
    background:var(--dropdown-bg); border:1px solid var(--border);
    box-shadow:0 12px 32px -10px var(--shadow-color);
    /* Teto de largura para a barra não estourar o pai — não é o que evita
       encostar no título/sino (ver a faixa estreita, logo abaixo): sozinho,
       isto só garante que a barra pare nas bordas de #topo-fino-interno. */
    max-width:calc(100% - 2rem);
  }
  /* Recolhida: some tudo menos o próprio botão de alternar, que vira a alça de
     volta. Não escondemos a barra inteira de propósito — sem alça visível o
     usuário não teria como trazê-la de volta. */
  /* Recolhida sobra SÓ a alça. Os divisores entram nesta lista de propósito:
     eles separam grupos que deixaram de existir, e sozinhos viravam um risco
     solto ao lado do chevron. */
  #client-nav-bar.recolhida .client-nav-secoes,
  #client-nav-bar.recolhida .client-nav-sep,
  #client-nav-bar.recolhida .client-nav-so-aberta{ display:none; }
  /* Sem os grupos, o gap da flex ainda reservava espaço à direita da alça. */
  #client-nav-bar.recolhida{ gap:0; }
  /* FAIXA ESTREITA (celular): não sobra vão nenhum ao lado do título e do
     sino para centralizar mais uma coisa ali dentro — hambúrguer, título e
     sino já disputam a largura inteira. A barra volta a flutuar como fazia
     antes de 2026-09-05: `fixed`, centrada na VIEWPORT (não mais no pai — a
     `--barra-largura` já é 0px aqui, então 50% da tela já é o centro certo,
     sem precisar da conta antiga com a variável), logo abaixo do topo fino. */
  @media (max-width:903px){
    /* FAIXA PRÓPRIA, e não uma pílula flutuante (dono, 08/09/2026: "ela não
       cabe mais lá na faixa fixa... não tem como criar uma outra faixinha fixa
       só para ela e não deixar ela flutuante?").
       O QUE INCOMODAVA: a pílula é `fixed` e o conteúdo do modal rola POR TRÁS
       dela. O `padding-top` do #client-modal só afasta o começo — à primeira
       rolagem, campos e títulos passavam atrás da pílula.
       Colada embaixo do topo fino e com o MESMO `--bg-0` e o MESMO fio dele, as
       duas leem como um bloco só, e nada passa por trás porque a faixa é opaca
       e vai de ponta a ponta.
       Só aqui: acima de 903px a barra continua a pílula centrada dentro do topo
       fino, que é onde o dono disse que "ficou perfeita". */
    #client-nav-bar{
      position:fixed; left:0; right:0; top:var(--topo-altura);
      transform:none; max-width:none;
      justify-content:center;
      padding:0.375rem 0.75rem;
      border:none; border-bottom:1px solid rgba(var(--hair-rgb),var(--fb-15));
      border-radius:0;
      background:var(--bg-0);
      box-shadow:none;
    }
    /* ⚠️ AQUI A DISPUTA DE Z-INDEX VOLTA A EXISTIR, e a nota logo acima (a que
       diz que ela "deixou de existir") só vale ACIMA de 903px. A barra ficou
       morta no celular entre 05/09 e 08/09 por causa disso.
       O QUE ACONTECIA, medido em 08/09/2026 com a ficha aberta a 375x812: a
       barra era pintada em y 68..113, dentro do #client-modal (56..812, z-50),
       e o clique no centro dela atingia o #client-overlay — nunca a barra.
       `position:fixed` NÃO tira o elemento do contexto de empilhamento do pai:
       a barra mora em #topo-fino (z-45), então ela é filha de 45 por mais que
       se posicione por cima de 50.
       POR ISSO SOBE O PAI, e não a barra: dar z-index a ela não adianta —
       dentro de um contexto de 45, 999 continua sendo 45 lá fora.
       51 é escolhido, não arredondado. Precisa passar de #client-modal (50) e
       ficar ABAIXO de #barra-lateral (57), senão o menu lateral aberto deixaria
       de cobrir a barra. Os modais que têm de cobrir tudo estão todos acima:
       indicadores 60, name-picker 70, password-form 75, loading 80, confirm 90.
       Não há efeito colateral visual: #topo-fino ocupa 0..--topo-altura e o
       modal começa exatamente em --topo-altura (.tela-de-trabalho), então os
       dois nunca se sobrepõem — o único pedaço que passa a ficar por cima do
       modal é o que já deveria estar lá, a própria barra. */
    #topo-fino{ z-index:51; }
    /* A ficha começa ABAIXO da faixa. Sem isto, a faixa cobriria o título e o X
       de fechar do modal — a ficha ficava sem saída visível. Só faz sentido
       nesta faixa de largura: acima dela a barra mora dentro do topo fino e
       nunca chega a sobrepor o modal (que só começa em `--topo-altura`, via
       .tela-de-trabalho).
       3,25rem = a altura da faixa (0,375 × 2 de padding + 2 do botão = 2,75rem,
       medido em 45px a 375px de largura) mais meio rem de respiro. Era 5rem
       enquanto a barra flutuava: aquele valor pagava também o vão de 0,75rem
       acima dela e a folga em volta da pílula, que deixaram de existir.
       Em rem porque a faixa também é — as duas crescem juntas no botão Aa.
       A classe vem do js/cliente-navegacao.js e só existe enquanto a barra
       existe: ficha sem barra (menos de 2 seções) mantém o py-8 de origem. */
    #client-modal.com-barra-nav{ padding-top:3.25rem; }
  }
  /* Só o GRUPO DAS SEÇÕES rola na horizontal, e não a barra inteira: assim o
     recolher e o voltar-ao-topo ficam sempre ancorados nas pontas, enquanto os
     ícones do meio deslizam. Sem isto, a 375px a barra pedia 379px de conteúdo
     dentro de 343px disponíveis e o último botão saía cortado.
     min-width:0 é o que autoriza o item flex a encolher abaixo do conteúdo —
     sem ele o overflow-x nunca chega a valer. */
  #client-nav-bar .client-nav-secoes{
    display:flex; align-items:center; gap:0.25rem;
    overflow-x:auto; min-width:0; scrollbar-width:none;
  }
  #client-nav-bar .client-nav-secoes::-webkit-scrollbar{ display:none; }
  #client-nav-bar .client-nav-sep{
    width:1px; height:1.25rem; background:rgba(var(--hair-rgb),var(--fb-25)); flex-shrink:0;
  }
  .client-nav-btn{
    width:2rem; height:2rem; border-radius:999px; flex-shrink:0;
    display:inline-flex; align-items:center; justify-content:center;
    color:var(--muted); background:transparent; border:none;
    transition:background .15s ease, color .15s ease;
  }
  .client-nav-btn:hover{ color:var(--text); background:var(--panel-softer); }
  .client-nav-btn.ativa{ color:var(--cyan); background:rgba(var(--cyan-accent-rgb),0.14); }

  /* GRID DE CIRCUITO — saiu em 2026-08-10 e VOLTOU em 2026-08-14, a pedido.
     Restaurado exatamente como era (`git show 50443c6^:web/css/app.css`), não
     redesenhado de memória: 42px de célula, linha de 1px, e a máscara radial que
     o apaga antes das bordas para ele não encostar nos cantos da tela.

     As duas versões de cor são de origem: no escuro a linha é azul a 13%; no
     claro o azul sobre fundo quase branco simplesmente sumia, então vira ardósia
     a 11%. É a mesma grade, não uma cor nova por tema.

     O que NÃO voltou, e continua fora: os dois glow blobs (.glow-blob) e o anel
     de scan do logo (.scan-ring). Estão em `git show 50443c6^:web/css/app.css` e
     `git show d28fa1c:web/css/app.css`. */
  .grid-bg{
    position:fixed; inset:0;
    background-image:
      linear-gradient(rgba(59,130,246,0.13) 1px, transparent 1px),
      linear-gradient(90deg, rgba(59,130,246,0.13) 1px, transparent 1px);
    background-size: 42px 42px;
    mask-image: radial-gradient(ellipse 90% 85% at 50% 45%, black 0%, transparent 92%);
    -webkit-mask-image: radial-gradient(ellipse 90% 85% at 50% 45%, black 0%, transparent 92%);
    pointer-events:none;
  }
  html.light .grid-bg{
    background-image:
      linear-gradient(rgba(15,23,42,0.11) 1px, transparent 1px),
      linear-gradient(90deg, rgba(15,23,42,0.11) 1px, transparent 1px);
  }

  /* .glass-card mantém o NOME (usada no projeto todo) e perdeu o vidro: agora é
     superfície sólida com borda de 1px e a sombra suave do kit. Sem
     backdrop-filter — sobre fundo claro ele não tinha o que desfocar, e era o
     que impedia position:fixed dentro dela. */
  .glass-card{
    /* ⚠️ `position:relative` NÃO é para posicionar nada — é o que põe o cartão
       ACIMA da grade de fundo. Pela ordem de pintura do CSS, um elemento
       posicionado (a .grid-bg é `fixed`) cobre o FUNDO de um bloco não
       posicionado; sem esta linha a grade risca os cartões por dentro e eles
       parecem semitransparentes.

       Isto funcionava sozinho até 2026-08-10, porque o `backdrop-filter` do
       vidro criava contexto de empilhamento e promovia o cartão. A grade e o
       vidro saíram no MESMO commit, então uma remoção escondeu a consequência da
       outra; ao trazer só a grade de volta, em 2026-08-14, o efeito apareceu.

       Medido antes de aplicar, com os 18 modais abertos: dos 24 elementos
       `absolute` visíveis, NENHUM mudou de posição — não há nada ancorado num
       ancestral mais distante que passasse a se ancorar no cartão. E `relative`
       não afeta descendente `fixed`, então o motivo pelo qual o backdrop-filter
       foi removido (ele impedia `position:fixed` dentro do cartão) continua
       resolvido. */
    position: relative;
    background: var(--card);
    border: 1px solid var(--border);
    box-shadow: var(--sombra);
  }

  /* @keyframes spin fica: .spinner (mais adiante no arquivo) usa o mesmo
     nome — só a argola em volta do logo saiu, o keyframe continua servindo
     ao spinner de carregamento. */
  @keyframes spin{ to{ transform:rotate(360deg); } }

  /* Separador entre o lockup e o texto de boas-vindas do login. Substitui a
     moldura giratória (.scan-frame) de 2026-08-11 — o usuário não gostou do
     efeito na tela e pediu algo mais simples no lugar. */
  .login-divider{
    width:100%; height:1px;
    background: rgba(var(--hair-rgb), var(--fb-40));
  }


  .field-shell{
    background: var(--panel);
    /* Borda um degrau mais forte que --border: o campo pousa tanto no card
       branco quanto no card de seção (--section-card-bg), e com a borda padrão
       ele quase desaparecia no segundo caso, onde os dois tons são vizinhos. */
    border: 1px solid rgba(var(--hair-rgb),var(--fb-25));
    transition: border-color .18s ease, box-shadow .18s ease, background .18s ease;
  }
  .field-shell:focus-within{
    border-color: var(--cyan);
    box-shadow: 0 0 0 3px rgba(var(--cyan-accent-rgb),0.14);
    background: var(--panel-strong);
  }
  .field-shell input, .field-shell textarea{
    background:transparent; outline:none; color:var(--text);
  }
  .field-shell input::placeholder, .field-shell textarea::placeholder{ color:var(--muted-2); }

  /* Autofill: o Chrome/WebKit pinta o campo de branco/amarelo ao preencher
     e-mail/senha salvos, atropelando o tema escuro. -webkit-text-fill-color
     garante o texto na cor do tema. Vale para todos os inputs do app.

     O fundo é resolvido com background-clip:text — recortando o background nos
     glifos, o fundo do autofill não pinta e o campo continua transparente,
     mostrando o var(--panel) da field-shell. Não dá para usar o box-shadow
     inset (a receita mais comum) porque --panel é TRANSLÚCIDO: uma cor sólida
     por baixo mataria o vidro do campo.

     A transição longa abaixo era a solução anterior e sozinha não basta: ela
     aposta que o navegador ANIMA até a cor do autofill e nunca chega lá, mas o
     Chrome atual pinta esse fundo num passo interno que a transição não segura.
     Fica como reserva para WebKit mais antigo, onde ainda funciona. */
  input:-webkit-autofill,
  input:-webkit-autofill:hover,
  input:-webkit-autofill:focus,
  input:-webkit-autofill:active{
    -webkit-text-fill-color: var(--text) !important;
    caret-color: var(--text);
    -webkit-background-clip: text;
    background-clip: text;
    transition: background-color 600000s 0s, color 600000s 0s;
  }

  /* Checklist de pré-requisitos da senha forte (troca no 1º acesso) — cada
     item começa "pendente" (cinza, círculo vazio) e vira "ok" (verde, check)
     assim que a condição é satisfeita em tempo real. */
  .pw-req{ color:var(--muted-2); transition: color .18s ease; }
  .pw-req .pw-req-off{ display:inline; }
  .pw-req .pw-req-on{ display:none; }
  .pw-req.met{ color:var(--ok); }
  .pw-req.met .pw-req-off{ display:none; }
  .pw-req.met .pw-req-on{ display:inline; }

  .filter-shell{
    background: var(--panel);
    border: 1px solid rgba(var(--hair-rgb),var(--fb-25));
    transition: border-color .18s ease, box-shadow .18s ease, background .18s ease;
  }
  .filter-shell:focus-within{
    border-color: var(--cyan);
    box-shadow: 0 0 0 3px rgba(var(--cyan-accent-rgb),0.14);
  }
  .filter-shell select, .filter-shell input{
    color:var(--text); background:transparent;
  }
  .filter-shell select option, .field-shell select option{ background:var(--surface); color:var(--text); }
  /* optgroup precisa da regra PRÓPRIA: sem ela o Chrome pinta o rótulo do grupo
     com o padrão dele (fundo branco), e no tema escuro o texto some. Cor de
     rótulo (--muted) + negrito para o grupo ler como cabeçalho, não como opção. */
  .filter-shell select optgroup, .field-shell select optgroup{
    background:var(--surface); color:var(--muted); font-weight:600;
  }
  .filter-shell input::placeholder{ color:var(--muted-2); }

  /* Pílula de destaque do kit (lá chamada .tag). Reaproveita o nome .badge, que
     existia aqui sem nenhum uso no projeto — em vez de deixar a classe morta e
     criar outra ao lado. Hoje marca o sistema contratado na grade de clientes. */
  .badge{
    display:inline-block;
    padding:0.25rem 0.75rem; border-radius:999px; font-size:0.6875rem; font-weight:600;
    letter-spacing:.12em; text-transform:uppercase;
    background:var(--grad); color:var(--on-grad); white-space:nowrap;
  }
  #client-rows tr{ border-top:1px solid rgba(var(--hair-rgb),var(--fb-12)); cursor:pointer; }
  #client-rows tr:hover{ background:rgba(var(--cyan-accent-rgb),0.04); }

  /* Cabeçalho da grid de clientes: colunas clicáveis pra ordenar. */
  .sortable-col{ cursor:pointer; user-select:none; transition:color .15s ease; }
  .sortable-col:hover{ color:var(--text); }
  /* O ícone é SVG e ocupa o mesmo espaço nos três estados (neutro, asc, desc) —
     com glifo de texto a largura mudava entre ▲ e o vazio e o cabeçalho dançava
     a cada clique. inline-flex + align-middle assentam o ícone na linha de base
     do texto sem empurrar a altura da célula. */
  .sortable-col .sort-arrow{ display:inline-flex; width:11px; height:11px; margin-left:4px;
                             vertical-align:middle; opacity:.35; transition:opacity .15s ease; }
  .sortable-col .sort-arrow svg{ width:100%; height:100%; }
  .sortable-col:hover .sort-arrow{ opacity:.75; }
  .sortable-col.sort-active{ color:var(--cyan); }
  .sortable-col.sort-active .sort-arrow{ opacity:1; }

  /* Cabeçalho FIXO: gruda no topo do contêiner rolável da grade. O fundo opaco
     não é enfeite — sem ele as linhas passam POR TRÁS do texto do cabeçalho e o
     resultado é ilegível. z-index mantém o cabeçalho acima das linhas, e o
     box-shadow substitui o border-bottom, que o sticky não leva junto. */
  .grid-header-fixo th{
    position:sticky; top:0; z-index:2;
    background:var(--panel-softer);
    box-shadow:inset 0 -1px 0 rgba(var(--hair-rgb),var(--fb-15));
  }

  .icon-btn{
    width:28px; height:28px; border-radius:8px;
    display:inline-flex; align-items:center; justify-content:center;
    border:1px solid rgba(var(--hair-rgb),var(--fb-20)); background:var(--panel-soft);
    /* cor base dos ícones de dentro: quem usa currentColor (o "kebab" de três
       pontos, por exemplo) herda daqui em vez da cor de texto cheia da linha.
       Ícone que quer outra cor continua declarando a sua. */
    color:var(--muted);
    transition: border-color .15s ease, background .15s ease, color .15s ease;
  }
  /* A cor de AÇÃO entra no hover, não em repouso: ícone de linha é apoio, e no
     escuro o --cyan virou um ciano claro que, cravado em cada linha da grade,
     lia como branco e competia com o nome do cliente. */
  .icon-btn:hover{ border-color:rgba(var(--cyan-accent-rgb),0.4); background:rgba(var(--cyan-accent-rgb),0.08); color:var(--cyan); }
  .icon-btn:disabled{ opacity:.45; }

  .avatar-box{
    width:38px; height:38px; border-radius:10px; flex-shrink:0;
    display:inline-flex; align-items:center; justify-content:center;
    background:rgba(var(--hair-rgb),var(--fb-10)); border:1px solid rgba(var(--hair-rgb),var(--fb-16));
    /* Os ícones de pessoa/empresa (icons.js) desenham em currentColor, então a
       cor deles nasce AQUI. Sem esta linha herdariam a cor de texto da linha da
       tabela e ficariam tão fortes quanto o nome do cliente — o ícone é apoio,
       não informação principal. */
    color:var(--muted);
  }
  /* IDENTIDADE por tipo de pessoa (dono, 2026-09-05) — ver a nota longa dos
     tokens --tipo-pj/--tipo-pf em :root sobre por que não são --ok/--provisorio.
     `data-tipo` em vez de reaproveitar `.person`/`.company` do resto do painel:
     aqui é só cor de avatar, e um seletor próprio não puxa nenhum outro estilo
     de leitor de tela ou botão junto. */
  .avatar-box[data-tipo="company"]{
    background:rgba(var(--tipo-pj-rgb),0.14); border-color:rgba(var(--tipo-pj-rgb),0.35);
    color:var(--tipo-pj);
  }
  .avatar-box[data-tipo="person"]{
    background:rgba(var(--tipo-pf-rgb),0.14); border-color:rgba(var(--tipo-pf-rgb),0.35);
    color:var(--tipo-pf);
  }

  /* Scrollbar customizada, alinhada à paleta azul/ciano do app (troca a barra cinza padrão do SO) */
  *{ scrollbar-width: thin; scrollbar-color: rgba(var(--cyan-accent-rgb),0.35) transparent; }
  *::-webkit-scrollbar{ width:9px; height:9px; }
  *::-webkit-scrollbar-track{ background:transparent; }
  *::-webkit-scrollbar-thumb{ background:rgba(var(--cyan-accent-rgb),0.35); border-radius:9999px; border:2px solid transparent; background-clip:padding-box; }
  *::-webkit-scrollbar-thumb:hover{ background:rgba(var(--cyan-accent-rgb),0.55); background-clip:padding-box; }

  /* Contatos e IPs (tabelas filhas, lado a lado): a lista tem uma ALTURA
     FIXA — não é teto (max-height), é altura de verdade (height). Antes cada
     painel encolhia/crescia com o conteúdo até um teto (com items-stretch
     igualando os dois na hora); agora cada um nasce do mesmo tamanho sempre,
     não importa quantos registros tem — 0 registros mostra a mesma altura
     vazia do painel cheio. Ajuste geral (herdado por qualquer novo
     .child-list-scroll sem classe própria): --child-list-max. */
  :root{ --child-list-max: 300px; }
  .child-list-scroll{ max-height: var(--child-list-max); overflow-y:auto; overflow-x:auto; }
  /* Contatos: altura própria, calibrada nas PRÓPRIAS linhas (dono,
     2026-09-05: "simula que tenha três registros de contatos e coloca a
     barra de scroll acima de três registros"). Uma linha de Contatos muda
     MUITO de altura entre os dois modos (ver cliente-contatos.js): empilhado
     abaixo de 2xl (até 5 informações por contato — nome, cargo, e-mail,
     telefone E celular, status) mediu 146px no pior caso (cargo + os dois
     telefones); em colunas a partir de 2xl mediu 66px no pior caso (só
     nome+cargo empilhados na mesma célula). Cabeçalho: 40px empilhado, 56px
     em colunas. Três linhas do pior caso, cabeçalho incluso:
       abaixo de 2xl:  40 + 3×146 = 478px  → 500px (folga de ~21px)
       a partir de 2xl: 56 + 3×66  = 254px  → 257px (folga de 3px)

     ⚠️ A FOLGA DE 21px ERA VISÍVEL, e virou defeito. A faixa de 2xl para
     cima nasceu com 275px "por segurança contra sub-pixel"; medido com os
     contatos REAIS do cliente 1 (dois com cargo e dois telefones, um só com
     nome e celular): conteúdo de 244px dentro de um card de 275px = 31px de
     vão vazio embaixo da 3ª linha. O dono viu na hora (2026-09-06: "eu pedi
     três linhas visíveis... está com três linhas lá e um espaçamento
     abaixo"), e é o mesmo erro que a altura de Senhas tinha. 3px cobrem o
     arredondamento de sub-pixel; 21px são meio dedo de espaço morto.

     Os 257px cabem TRÊS CONTATOS CHEIOS (nome+cargo, e-mail, fixo com ramal
     e celular = 66px cada), que é o compromisso certo: qualquer trio de
     contatos cabe. Com os do cliente 1 sobram 13px, porque o terceiro
     contato dele é curto (sem cargo, só celular) — isso é variação do
     conteúdo, não folga inventada. A 4ª linha pede 320px e não cabe: barra
     aparece, que é o pedido.

     A faixa ABAIXO de 2xl (500px) continua como estava, de propósito: o dono
     trabalha na largura máxima e ajusta as faixas menores depois, uma a uma
     (ver a mesma nota na altura de Senhas). Aquele número ainda carrega a
     folga da calibração antiga.

     `max-height:none`: sem isto, o teto de 300px do `--child-list-max`
     (herdado da regra genérica .child-list-scroll, acima) cortaria os
     500px abaixo de 2xl. */
  .child-list-scroll.contacts-list{ height: 500px; max-height: none; }
  /* IPs: altura PRÓPRIA — não é mais a mesma de Contatos (dono, 2026-09-05:
     "no máximo 4 registros sem a barra de rolagem. A partir de 5, com a
     barra"; pedido específico desta tela, diferente das 3 linhas de
     Contatos). Uma linha de IP é bem mais rasa que uma de Contatos (só
     Localidade+ícone+IP, sem cargo/e-mail/telefone): medido em 56,5px em
     colunas (2xl+) e 66,5px empilhado (abaixo de 2xl); cabeçalho 40,5px
     nos dois modos. Quatro linhas, cabeçalho incluso, abaixo de 2xl:
       40,5 + 4×66,5 = 306,5px → 330px (folga antiga, ~24px, ainda não
       recalibrada — faixa estreita é assunto de outro dia). */
  .child-list-scroll.ips-list{ height: 330px; max-height: none; }

  /* ⚠️ A PARTIR DE 2xl, A LINHA 1 INTEIRA SEGUE UMA ALTURA SÓ — e a régua é
     o card de CONTATOS. Decisão do dono, 2026-09-06: "na linha de contatos e
     IPs a gente vai se basear na altura do card de contatos... calcula as
     três linhas sem barra de rolagem, junta ali perfeitinho com o divisor,
     mede a altura do contatos fixa, e depois você põe a mesma altura no IPs.
     IPs são quatro, mas aí vai ter barra de rolagem mesmo."

     POR QUE UMA REGRA NA LINHA, E NÃO UMA EM CADA CARD: o `#child-row-1` usa
     items-stretch, então o card mais alto manda na altura dos dois, e o mais
     baixo ganha um vão entre a grade e o divisor (o rodapé é mt-auto). Foi
     exatamente esse o defeito relatado: IPs estava 33px mais alto que
     Contatos e o vão apareceu em CONTATOS, não em IPs — folga escondida num
     card vira defeito no vizinho. Com a altura pendurada em `.row1`, os dois
     não têm como divergir: existe um número só.

     O número (medido ao vivo, 1920px, contatos reais do cliente 1 e um trio
     de contatos cheios): cabeçalho 56px + 3 linhas de 66px = 254px → 257px,
     3px de folga só para o arredondamento de sub-pixel.
     Consequência aceita e pedida: os 4 IPs precisam de 264px (40 + 4×56) e
     só recebem 257px, então a grade de IPs nasce com barra de rolagem. */
  @media (min-width:1536px){
    .child-list-scroll.row1{ height: 257px; }
  }
  /* Cabeçalho da grade TRAVADO (sticky) ao rolar — dono, 2026-09-05: "cabeçalho
     travado também da grade" [de IPs]. Estendido a Contatos também, mesma
     ficha, mesmo padrão de lista com altura fixa e rolagem interna — sem
     isto, rolar a lista escondia os rótulos das colunas junto com as linhas.
     Precisa de um fundo OPACO nas células do cabeçalho (herda --panel-softer,
     o mesmo fundo do wrapper que a rolagem já usa) — sem isso as linhas
     que passam por baixo apareceriam translúcidas atrás dos rótulos.

     ⚠️ `border-collapse:separate` na TABELA é o que faz o sticky funcionar
     de verdade — medido ao vivo: sem isto o cabeçalho não gruda, mesmo com
     `position:sticky` certo no `th`. O preflight do Tailwind carimba
     `table{border-collapse:collapse}` (item de reset, não é deste app), e
     `collapse` quebra sticky em `<th>` nos navegadores — é uma limitação
     antiga do próprio CSS de tabelas, não bug deste código. `border-spacing:0`
     evita que `separate` reabra o espaço entre células que `collapse` fechava
     — sem ele as bordas da tabela pareceriam duplicadas.

     Escopado nas QUATRO grades filhas da ficha via `.row1`/`.row2` (Contatos,
     IPs, Senhas e Pagamentos) — uma regra só, em vez de uma cópia por card,
     pelo mesmo motivo da altura logo abaixo: cópia é o que deixa um card
     ficar para trás quando o próximo chega (Pagamentos entrou em 2026-09-06,
     a pedido do dono: "o cabeçalho eu quero que ele fique fixo"). Não mexe no
     reset global nem em `#clients-table`. */
  .child-list-scroll.row1 table, .child-list-scroll.row2 table{
    border-collapse: separate; border-spacing: 0;
  }
  .child-list-scroll.row1 thead th, .child-list-scroll.row2 thead th{
    position: sticky; top: 0; z-index: 1; background: var(--panel-softer);
  }
  /* Linha 2 (Senhas | Pagamentos): MESMA lógica da linha 1 — uma altura só
     para a linha inteira, pendurada em `.row2` para os dois cards não terem
     como divergir, e a régua é o card de SENHAS. Decisão do dono,
     2026-09-06: "na linha de senhas e pagamentos a gente vai se basear na
     altura de senhas". O porquê de a regra ser da LINHA e não de cada card
     está explicado em `.row1`, acima: items-stretch faz o card mais alto
     mandar nos dois, e a folga de um vira vão no vizinho.

     O número sai da calibragem de Senhas (comentário logo abaixo): 490px,
     que é cabeçalho 56,57 + 5 linhas de 86 = 486,57, mais 3px de folga de
     sub-pixel. Pagamentos herda esses 490px e, como as linhas dele têm outra
     altura, ganha barra de rolagem quando passar do que couber — mesma troca
     aceita em IPs na linha 1.

     Isto substituiu o teto dinâmico de 373px que Pagamentos tinha (altura
     que crescia com o conteúdo até 5 linhas). Agora ele é fixo como os
     outros: 0 registros ocupa a mesma altura que 5. */
  .child-list-scroll.row2{ height: 490px; max-height: none; }
  /* Senhas: altura PRÓPRIA, igual em espírito a Contatos/IPs. Pedido
     original (dono, 2026-09-05): "no máximo 4 linhas, sem a barra de
     rolagem. A partir de 5, com barra de rolagem". Corrigido no dia
     seguinte (dono, 2026-09-06, ao ver o resultado ao vivo): "eu solicitei 5
     linhas na grade... até 5 sem barra de rolagem, a partir da sexta linha
     com barra" — 5 linhas fixas, rolagem só a partir da 6ª.

     Detalhe DIFERENTE dos outros dois cards: a grade de Senhas não tem
     colunas que se combinam por viewport (sem `2xl:hidden`/`2xl:table-cell`
     como em IPs) — as 5 colunas (Apelido/Senha/Consultas/IP-WS/Ações) são
     sempre as mesmas em qualquer largura. Por isso aqui basta UMA altura, sem
     media query: a linha mede o MESMO tanto no card largo (1 coluna, ~877px)
     e no mais apertado que existe (2 colunas bem em cima do `lg`, ~401px) —
     medido ao vivo nos dois: 86px certinhos, porque quem manda na altura da
     linha são os dois ícones empilhados de IP/WS e de Ações, não o texto.

     ⚠️ ERRO QUE ISTO CORRIGE (2026-09-06): a primeira calibração usou como
     base os 124,3px de um PIOR CASO artificial — apelido de 40 caracteres
     quebrando em duas linhas no card estreito. Com isso a faixa a partir de
     `lg` ganhou 705px de altura, e apelido de verdade ("TESTE", "JULIO2",
     "TESTE DO SISTEMA") não quebra nunca: cabiam SETE linhas antes da barra
     aparecer, quando o pedido era cinco (dono, ao ver na tela: "te parecem 5
     linhas na grade? eu pedi 5 linhas sem barra de rolagem"). A lição: a
     régua é o conteúdo REAL e comum, não o pior caso imaginável. Se algum dia
     aparecer um apelido longo o bastante para quebrar, aquela linha ocupa o
     dobro e a barra chega um pouco antes da 5ª — troca aceita de propósito,
     porque o contrário (mostrar 7 quando se pediu 5) é o defeito visível.

     ⚠️ SEGUNDO ERRO, no mesmo dia: a folga. A conta certa (486,9px) recebeu
     ~28px de "margem de segurança contra sub-pixel", e esses 28px aparecem na
     tela como um vão vazio embaixo da 5ª linha — o dono viu na hora ("tem um
     espaço sobrando na última linha aí"). Medido: o vão era exatamente os
     28,43px da folga. Folga preventiva não é invisível; ela é meio dedo de
     espaço morto. 3px cobrem o arredondamento de sub-pixel e ninguém enxerga.

     A RÉGUA É A LARGURA MÁXIMA. Dono, 2026-09-06: "eu estou trabalhando na
     maior largura do monitor... depois nós vamos diminuindo, portanto faça o
     que eu estou pedindo exatamente." Então esta altura é calibrada para o
     monitor grande, onde NÃO há barra horizontal. Numa faixa estreita
     (viewport ~1024–1115px, card ~400px) a tabela não cabe na largura e a
     barra horizontal aparece, comendo 10px da altura útil — ali a 5ª linha
     fica ~7px cortada. É consequência conhecida e aceita: ajustar as faixas
     menores é pedido separado, quando ele chegar nelas.

     Medido ao vivo (harness em `web/_scratch-senhas.html`, apagado depois de
     usar): cabeçalho 56,57px (não muda — o `<br>` das colunas Consultas e
     IP/WS já força 2 linhas sempre; a largura da coluna Consultas mudou no
     mesmo dia — ver comentário no `<th>`, em `cliente-senhas.js` — mas a
     altura do cabeçalho não). Linha real: 86px em qualquer largura.
       56,57 + 5×86 = 486,57px → 490px (vão de 3,43px, invisível)
     A 6ª linha pede 572,57px e não cabe: barra aparece, que é o pedido.

     ⚠️ ONDE ESTE NÚMERO MORA: em `.child-list-scroll.row2`, acima — não numa
     regra própria de `.passwords-list`. É de propósito: a linha 2 inteira usa
     a altura de Senhas, então o valor precisa existir UMA vez só, senão
     Senhas e Pagamentos voltam a divergir e o vão reaparece no vizinho. Esta
     seção guarda a CONTA; a regra que aplica está lá em cima.

     O cabeçalho fixo desta grade também mora lá em cima, na regra única de
     `.row1`/`.row2` — não há mais nada específico de `.passwords-list`. */

  .status-dot{ display:inline-flex; align-items:center; gap:6px; font-size:0.8125rem; font-weight:600; }
  .status-dot .dot{ width:7px; height:7px; border-radius:9999px; flex-shrink:0; }

  /* INTERRUPTOR de status do cliente — só na coluna Status da grade de clientes
     (2026-08-13). Antes era `.status-dot`, igual ao resto do painel, e o
     problema não era a bolinha: era que a célula JÁ É UM BOTÃO que bloqueia e
     libera o cliente, e nada na tela dizia isso. O `title` só aparece parando o
     mouse em cima. O interruptor mostra o estado e a ação no mesmo objeto.
     Clique acidental não é risco: a troca passa por confirmação (cliente-ficha).

     Classe PRÓPRIA, e não uma variante de `.status-dot`, porque aquele serve a
     outros cinco lugares onde a bolinha continua certa — status do boleto
     (AB/BT/PG/CA), IP, contato que recebe boleto, lembrete e observação. Ali não
     há nada para alternar. */
  .status-switch{
    display:inline-flex; align-items:center; gap:9px;
    background:none; border:none; padding:0; font:inherit;
  }
  .status-switch .trilho{
    width:30px; height:17px; border-radius:9999px; position:relative; flex-shrink:0;
    border:1px solid; transition: background .18s ease, border-color .18s ease;
  }
  .status-switch .puxador{
    position:absolute; top:2px; width:11px; height:11px; border-radius:9999px;
    transition: left .18s ease, background .18s ease;
  }
  /* O rótulo fica em --muted, e não na cor do estado: quem carrega verde e
     vermelho é o trilho. Repetir a cor na palavra deixava a célula gritando mais
     que a coluna Cliente, que é a que se lê primeiro. */
  .status-switch .rotulo{ font-size:0.78rem; font-weight:600; color:var(--muted); }

  .status-switch[data-on="true"]  .trilho{ background:rgba(var(--ok-rgb),0.22);   border-color:rgba(var(--ok-rgb),0.45); }
  .status-switch[data-on="true"]  .puxador{ left:16px; background:var(--ok); }
  .status-switch[data-on="false"] .trilho{ background:rgba(var(--erro-rgb),0.22); border-color:rgba(var(--erro-rgb),0.45); }
  .status-switch[data-on="false"] .puxador{ left:2px;  background:var(--erro); }

  .status-switch:not(:disabled):hover .trilho{ filter:brightness(1.15); }
  /* A variante SÓ LEITURA (Acompanhamento Mensal) não acende no hover: acender
     promete um clique que não existe. */
  .status-switch[data-leitura="true"]:hover .trilho{ filter:none; }
  .status-switch:disabled{ opacity:.5; cursor:not-allowed; }
  /* Foco visível pelo teclado: sem isto o interruptor é o único controle da
     grade que não mostra onde o Tab parou. */
  .status-switch:focus-visible{ outline:2px solid var(--cyan); outline-offset:3px; border-radius:6px; }
  /* Cor por TOKEN, não por hex: --ok/--erro/--aviso já vêm com o valor certo de
     cada tema, então sumiu a necessidade dos overrides em html.light que
     existiam aqui antes (o verde/vermelho de então eram calibrados para o fundo
     quase preto e perdiam contraste sobre o navy do kit). */
  .status-liberado{ color:var(--ok); } .status-liberado .dot{ background:var(--ok); }
  .status-bloqueado{ color:var(--erro); } .status-bloqueado .dot{ background:var(--erro); }
  /* IP excluído (ip_status = '2' no legado). Cinza de propósito, e não vermelho:
     vermelho é BLOQUEADO, que é um estado do qual se volta com um clique. Este
     não volta — a linha fica como lápide, e a cor precisa dizer "isto saiu de
     cena", não "isto está errado". */
  .status-excluido{ color:var(--muted-2); } .status-excluido .dot{ background:var(--muted-2); }

  /* PERMISSÃO DE CAMPO (RN-17) — as fichas de "Informações confidenciais".
     Usadas em dois lugares: na ficha do cliente (com rótulo) e no formulário da
     senha (só o ícone, o nome no tooltip).

     Dez colunas de largura IGUAL numa linha só, a pedido do dono. O
     `minmax(0,1fr)` e não `1fr` não é detalhe: sem o mínimo zero, "Referências
     Profissionais" impede a coluna de encolher e a grade estoura para fora do
     cartão. Medido a 1.180px de cartão: ficha de 110px, nada transborda. */
  .grade-confid{ display:grid; grid-template-columns:repeat(10, minmax(0,1fr)); gap:5px; }
  @media (max-width: 900px){ .grade-confid{ grid-template-columns:repeat(5, minmax(0,1fr)); } }

  .ficha-confid{
    display:flex; flex-direction:column; align-items:center; gap:8px;
    padding:10px 3px; border-radius:10px; cursor:pointer;
    border:1px solid transparent; color:var(--muted-2);
    transition:background .15s ease, border-color .15s ease, color .15s ease;
  }
  /* Altura fixa de DUAS linhas, que é o pior caso REAL — medido a 1.180px de
     cartão e 110px de ficha: "Referências Profissionais", "Informações
     Comerciais" e "Referências Comerciais" quebram em duas, o resto em uma.
     Reservar três (como estava até 2026-08-31) deixava uma linha vazia embaixo
     de todas e empurrava o olho para cima.
     A altura fixa continua necessária: sem ela, uma ficha de um nome e outra de
     dois deixariam os olhos em alturas diferentes ao longo da fila. */
  .ficha-confid .rotulo{
    font-size:10.5px; line-height:1.2; text-align:center; min-height:2.4em;
    display:flex; align-items:flex-start; justify-content:center;
    overflow-wrap:anywhere; color:var(--muted-2);
  }
  /* O tamanho do olho vive AQUI, e não no `width` do SVG, porque as duas
     variantes o querem diferente: na ficha do cliente ele é o elemento
     principal; no formulário da senha divide espaço com o resto do form. */
  .ficha-confid svg{ width:28px; height:28px; }
  .grade-confid.compacta .ficha-confid svg{ width:20px; height:20px; }
  .ficha-confid[data-on="true"]{
    background:rgba(var(--cyan-accent-rgb),0.12);
    border-color:rgba(var(--cyan-accent-rgb),0.42);
    color:var(--cyan);
  }
  .ficha-confid[data-on="true"] .rotulo{ color:var(--text); }
  .ficha-confid:hover{ border-color:rgba(var(--cyan-accent-rgb),0.5); }

  /* TRAVADA: desligada porque o CLIENTE não libera, não porque a senha negou.
     São coisas diferentes e a tela precisa dizer qual — sem isto o operador
     clicaria a vida toda num campo que nunca vai acender. */
  .ficha-confid[data-travada="true"]{ cursor:not-allowed; opacity:.4; }
  .ficha-confid[data-travada="true"]:hover{ border-color:transparent; }

  /* Variante do formulário da senha: só o ícone, o nome vai no tooltip. O
     espaço ali é curto e o nome já está escrito no nível do cliente. */
  .grade-confid.compacta{ gap:4px; }
  .grade-confid.compacta .ficha-confid{ padding:7px 2px; }
  .grade-confid.compacta .rotulo{ display:none; }
  /* Os três status do boleto (AB / PG / CA) precisam ser distinguíveis entre si
     — é a coluna que o operador lê de relance na grade de pagamentos.
     Com "em aberto" no --aviso eles não eram: aviso e erro são a MESMA família
     de vermelho nesta paleta (ver o aviso em maiúsculas lá no bloco dos tokens,
     decisão de 2026-08-11), então AB e CA saíam quase idênticos.
     A saída NÃO foi mexer no --aviso, que continua valendo para o resto do
     painel: só este status passou para o azul-céu. Decidido com o usuário em
     2026-08-12, e o raciocínio é o do próprio dado — boleto em aberto não é
     alerta, é pendência: ainda não foi pago e nada deu errado. O vermelho fica
     exclusivo do cancelado, que é o único desfecho ruim dos três.
     Só a grade de pagamentos usa estas três classes; liberado/bloqueado (que
     valem para cliente, IP e contato) não são tocados. */
  .status-pago{ color:var(--ok); } .status-pago .dot{ background:var(--ok); }
  .status-em_aberto{ color:var(--cyan); } .status-em_aberto .dot{ background:var(--cyan); }
  .status-cancelado{ color:var(--erro); } .status-cancelado .dot{ background:var(--erro); }
  /* BT (baixa temporária) entrou em 2026-08-12 e é o QUARTO status da mesma
     coluna — daí o âmbar próprio (--provisorio). Ele não é um desfecho: o
     boleto continua devido. Por isso não pode nem parecer PG (verde, quitado)
     nem CA (vermelho, encerrado); é uma pendência com prazo. */
  .status-baixa_temporaria{ color:var(--provisorio); } .status-baixa_temporaria .dot{ background:var(--provisorio); }

  /* Botão "atualizar" da barra de título dos painéis filhos da ficha. Discreto
     por padrão (a barra de título não é lugar de chamar atenção) e só ganha
     contraste no hover. O tamanho segue o do "Gerar em lote", que já morava
     numa dessas barras — dois botões de alturas diferentes na mesma faixa
     desalinham a barra inteira. */
  /* FILTROS DA BARRA DE TÍTULO (js/clienteSecoes.js — Pagamentos e IPs).
     Dono, 2026-09-08: "na linha de título mesmo... com o componente checkbox".

     `flex:1` com `min-width:0` e `flex-wrap`: os filtros ficam entre o título e
     o botão de atualizar e tomam o vão que sobra, mas podem cair para uma
     segunda linha na largura estreita em vez de espremer os vizinhos — a barra
     cresce em altura, que é o único jeito honesto de caber.

     `justify-center` (dono, 2026-09-08: "mantenha esse grupo de componentes no
     centro do título, nos dois cards"). Centraliza no VÃO entre o título e o
     botão de atualizar — não no centro geométrico da barra, que ficaria alguns
     pixels à esquerda porque o título é bem mais largo que o botão. Centrar de
     verdade pediria tirar o grupo do fluxo (position:absolute, como o
     #client-nav-bar faz no topo fino), e aí ele passaria a poder montar em cima
     do título quando a barra apertasse — troca ruim por poucos pixels.

     Cores da BARRA (--titlebar-text), não do card: elas vivem sobre o
     --titlebar-bg, e herdar as do corpo deixaria o rótulo quase invisível no
     tema claro. */
  .secao-filtros{
    display:flex; align-items:center; justify-content:center; flex-wrap:wrap;
    flex:1; min-width:0; gap:0.25rem 0.625rem;
  }
  .secao-filtro{
    display:inline-flex; align-items:center; gap:0.3125rem;
    font-size:0.6875rem; line-height:1; white-space:nowrap;
    color:var(--titlebar-text); opacity:.75; cursor:pointer; user-select:none;
    transition:opacity .15s ease;
  }
  .secao-filtro:hover{ opacity:1; }
  /* 0.8125rem e não 1rem: a barra de título é baixa (py-2), e a caixa padrão do
     navegador empurraria a altura dela. `accent-color` pinta o marcado com o
     ciano do painel sem precisar recriar o controle — continua sendo um
     checkbox de verdade, com teclado e leitor de tela de graça. */
  .secao-filtro input[type="checkbox"]{
    width:0.8125rem; height:0.8125rem; margin:0; flex-shrink:0;
    accent-color:var(--cyan); cursor:pointer;
  }

  .secao-refresh{
    width:20px; height:20px; border-radius:9999px; flex-shrink:0;
    display:inline-flex; align-items:center; justify-content:center;
    color:var(--titlebar-text); opacity:.6; transition:opacity .15s ease, background-color .15s ease;
  }
  .secao-refresh svg{ width:13px; height:13px; }
  .secao-refresh:hover{ opacity:1; background:rgba(var(--hairline-rgb),0.22); }
  .secao-refresh:disabled{ cursor:default; }
  /* Gira enquanto recarrega: é o único retorno de que o clique fez algo quando
     a lista volta igual — e voltar igual é o caso comum. */
  .secao-refresh.girando svg{ animation:secao-refresh-giro .7s linear infinite; }
  /* Mesmo giro para um botão de atualizar que não usa .secao-refresh (o das
     Observações da ficha, que é .icon-btn sobre o card, sem barra de título). */
  .girando-icone svg{ animation:secao-refresh-giro .7s linear infinite; }
  @keyframes secao-refresh-giro{ to{ transform:rotate(360deg); } }

  /* Campo cujo TEXTO DIGITADO sai em maiúsculas, mas o placeholder não. Sem a
     segunda regra o text-transform pega o placeholder junto e a dica vira um
     grito — e placeholder em caixa alta é mais difícil de ler justamente para
     quem ainda não sabe o que o campo quer. */
  .entrada-maiuscula{ text-transform:uppercase; }
  .entrada-maiuscula::placeholder{ text-transform:none; }

  /* --- Barra flutuante de indicadores + gráfico da carteira --- */
  .ind-item{ display:flex; align-items:center; gap:6px; padding:0 8px; white-space:nowrap; }
  .ind-ponto{ width:7px; height:7px; border-radius:9999px; flex-shrink:0; }
  .ind-rotulo{ font-size:0.75rem; color:var(--muted); }
  .ind-num{ font-size:0.8125rem; font-weight:700; color:var(--text); font-variant-numeric:tabular-nums; }
  .ind-sep{ width:1px; height:16px; background:rgba(var(--hair-rgb),var(--fb-20)); flex-shrink:0; }
  /* O item "Atrasados" é um <button> no meio de <div>s. Estas linhas existem só
     para que ele NÃO pareça um botão: sem elas o navegador lhe dá fundo, borda e
     a própria fonte, e ele destoaria dos vizinhos. O pedido foi explícito — não
     mudar o visual, só deixar claro quando está clicado. */
  button.ind-item{ background:none; border:0; font:inherit; color:inherit; cursor:pointer;
                   border-radius:9999px; transition:background .15s, box-shadow .15s; }
  /* ⚠️ O padding continua sendo o do .ind-item (0 8px), IGUAL ao dos <div>
     vizinhos. Quem dá respiro vertical ao fundo é o box-shadow de 3px, que
     desenha para fora da caixa sem ocupar espaço. Com `padding:2px` o botão
     ficaria 4px mais alto que os irmãos e a barra inteira cresceria junto —
     exatamente o "mudar o visual" que o pedido excluía. */
  button.ind-item:hover{ background:rgba(var(--hair-rgb),var(--fb-12));
                         box-shadow:0 0 0 3px rgba(var(--hair-rgb),var(--fb-12)); }
  button.ind-item:focus-visible{ outline:2px solid var(--cyan); outline-offset:3px; }
  /* Ligado: o MESMO desenho, afundado. Fundo neutro (a mesma família das outras
     superfícies) em vez de âmbar, porque a bolinha ao lado já é a cor do
     indicador — repetir o âmbar no fundo faria o item ligado gritar mais que o
     próprio número. O rótulo sobe para a cor de texto normal para o item ativo
     não parecer desabilitado ao lado dos outros três. */
  button.ind-item[aria-pressed="true"]{ background:rgba(var(--hair-rgb),var(--fb-25));
                                        box-shadow:0 0 0 3px rgba(var(--hair-rgb),var(--fb-25)); }
  button.ind-item[aria-pressed="true"] .ind-rotulo{ color:var(--text); }
  #indicadores-abrir:hover{ color:var(--text); background:rgba(var(--cyan-accent-rgb),0.18); }
  #search-clear:hover{ color:var(--text); background:rgba(var(--hair-rgb),var(--fb-20)); }

  /* A barra empilhada. A altura generosa (26px) é o que deixa o número caber
     DENTRO da faixa — rótulo direto na marca em vez de só na legenda. O fundo
     aparece nos 2px entre as faixas, que é o separador: borda entre cores
     saturadas cria uma terceira cor na junta e suja a leitura. */
  .ind-barra{ display:flex; align-items:stretch; height:26px; width:100%; }
  .ind-faixa{ position:relative; display:flex; align-items:center; justify-content:center;
              min-width:3px; transition:filter .12s ease; outline:none; }
  .ind-faixa:hover, .ind-faixa:focus-visible{ filter:brightness(1.12); }
  .ind-faixa:focus-visible{ box-shadow:0 0 0 2px var(--panel), 0 0 0 4px var(--cyan); }
  /* O número vai em branco sobre a faixa nos dois temas: as três cores de fundo
     são saturadas o bastante para isso, e usar o token de texto o tornaria
     ilegível sobre o verde do tema claro. */
  .ind-faixa-num{ font-size:0.6875rem; font-weight:700; color:#fff; font-variant-numeric:tabular-nums;
                  text-shadow:0 1px 2px rgba(0,0,0,.35); }

  .dropdown-panel{
    position:absolute; top:calc(100% + 8px); left:0; min-width:180px;
    background:var(--dropdown-bg); border:1px solid var(--dropdown-border);
    border-radius:12px; padding:6px;
    /* Sombra em duas camadas: a curta e escura desenha o contorno imediato (é
       ela que separa o menu de um card da MESMA cor, no tema claro), e a longa
       e difusa dá a distância. Uma só não faz as duas coisas — a difusa sozinha
       era o que existia aqui, e some sobre fundo claro. */
    box-shadow: 0 2px 6px -1px var(--shadow-color), 0 20px 50px -15px var(--shadow-color);
    z-index:40;
  }
  /* Variante ANCORADA NO RODAPÉ (o menu da conta, na barra lateral): abre para
     CIMA, porque para baixo sairia da tela.
     ⚠️ Precisa vir DEPOIS do .dropdown-panel — mesma especificidade, uma classe
     cada, e quem vence é o último. Escrita antes dele, como estava na primeira
     tentativa, o `top:auto` daqui era desfeito pelo `top:calc(100% + 8px)` de
     lá e o menu abria para baixo, sumindo embaixo da tela (dono, 2026-09-04).
     Segundo caso do mesmo erro no mesmo dia; o primeiro foi o #client-nav-bar. */
  .dropdown-panel-acima{ top:auto; bottom:calc(100% + 8px); }
  /* white-space:nowrap: item de menu não quebra em duas linhas. O painel é
     absoluto, então cresce para caber o rótulo — melhor do que ir aumentando o
     min-width a cada item novo que não coube. */
  .dropdown-item{
    display:flex; align-items:center; gap:9px; width:100%;
    padding:0.5rem 0.625rem; border-radius:8px; font-size:0.84375rem; font-weight:500;
    color:var(--text); text-align:left; transition: background .15s ease;
    white-space:nowrap;
  }
  .dropdown-item:hover{ background:var(--panel-softer); }

  /* Variante ancorada à DIREITA. O padrão alinha pela esquerda, o que funciona
     para o menu Cadastros (à esquerda do cabeçalho) e vazaria para fora da tela
     no menu do usuário, que fica na ponta oposta. */
  .dropdown-panel-right{ left:auto; right:0; }

  /* TOM DO ÍCONE nos menus de ação — a cor diz a CONSEQUÊNCIA do item, não o
     assunto dele. Quatro tons, e só quatro; sem tom declarado o item é leitura.
     Fica aqui, e não em `style` inline no SVG, porque foi o inline que deixou
     "Cancelar" com --aviso e "Excluir" com --erro: dois vermelhos diferentes
     para a mesma ideia, e ninguém notou porque estavam em arquivos distintos.

       (sem data-tom)  leitura, não muda nada        --muted
       data-tom=acao   dispara algo para FORA        --cyan   (a cor de ação do
                       (e-mail, senha nova)                    tema no escuro)
       data-tom=ok     desfecho que encerra bem      --ok
       data-tom=risco  desfaz, apaga ou cancela      --erro

     O padrão subiu de --muted-2 (4,66:1) para --muted (6,86:1): --muted-2 é o
     token mais apagado do tema, pensado para texto terciário, e deixava metade
     do menu parecendo desabilitada ao lado dos dois itens coloridos. */
  .dropdown-item svg{ color:var(--muted); flex-shrink:0; }
  .dropdown-item[data-tom="acao"] svg{ color:var(--cyan); }
  .dropdown-item[data-tom="ok"] svg{ color:var(--ok); }
  .dropdown-item[data-tom="risco"] svg{ color:var(--erro); }
  /* O SUBMENU (.dropdown-sub / .dropdown-subpanel) e a pílula do cabeçalho
     (.nav-pill) saíram em 2026-09-04, com a barra lateral: eram os dois níveis
     que o suspenso "Cadastros" precisava e que a barra dissolveu em rótulos de
     grupo. Recuperáveis pelo histórico (git show 4a28243^:web/css/app.css). */

  button{ cursor:pointer !important; }
  button:disabled{ cursor:not-allowed !important; }
  input:disabled, select:disabled{ opacity:.55; cursor:not-allowed; }
  /* Calendário/relógio nativos: o ícone e o painel do seletor são desenhados pelo
     NAVEGADOR, e ele escolhe a cor pelo `color-scheme` — as nossas variáveis não
     chegam lá. Sem isto o ícone sai escuro sobre o campo escuro.

     Antes havia `filter:invert(1)` numa lista de ids: virava o ícone, mas deixava
     o painel do seletor claro, esquecia todo campo novo (foi o que aconteceu com
     o horário do resumo) e mentia no tema claro, onde o ícone ficava branco sobre
     branco. Por tipo de input e seguindo o tema resolve os quatro casos.

     A cor do TEXTO não vem daqui: `.field-shell input` já fixa var(--text). */
  input[type="date"], input[type="time"], input[type="datetime-local"]{ color-scheme: dark; }
  html.light input[type="date"],
  html.light input[type="time"],
  html.light input[type="datetime-local"]{ color-scheme: light; }
  input[type="date"]::-webkit-calendar-picker-indicator,
  input[type="time"]::-webkit-calendar-picker-indicator,
  input[type="datetime-local"]::-webkit-calendar-picker-indicator{ cursor:pointer; }
  /* Reserva espaço acima ao rolar um campo pra tela (ex: tooltip nativo de
     validação) — sem isso o label/título da seção acima fica cortado. */
  #client-modal-panel input, #client-modal-panel select{ scroll-margin-top:100px; }

  .btn-primary{
    /* O degradê de 3 paradas do kit, via --grad (clareado no escuro — ver a
       nota em :root). A cor do texto vem de --on-grad porque ela MUDA por tema:
       branco sobre o degradê escuro do claro, navy sobre o clareado do escuro. */
    background: var(--grad);
    box-shadow: 0 8px 24px -12px rgba(var(--cyan-accent-rgb),0.5);
    color: var(--on-grad);
    transition: transform .16s ease, box-shadow .16s ease, filter .16s ease;
  }
  .btn-primary:hover{
    filter:brightness(1.08);
    box-shadow: 0 12px 30px -12px rgba(var(--cyan-accent-rgb),0.65);
    transform: translateY(-1px);
  }
  .btn-primary:active{ transform: translateY(0); }
  .btn-primary:disabled{ opacity:.85; cursor:not-allowed; transform:none; }

  .checkbox-custom{
    width:16px; height:16px; border-radius:4px;
    border:1px solid rgba(var(--hair-rgb),var(--fb-40));
    background:var(--panel);
    display:inline-flex; align-items:center; justify-content:center;
    transition: all .15s ease; flex-shrink:0;
  }
  input:checked + .checkbox-custom{
    background: var(--grad);
    border-color: transparent;
  }
  .checkbox-custom svg{ opacity:0; transition: opacity .15s ease; }
  input:checked + .checkbox-custom svg{ opacity:1; }

  .spinner{
    width:18px; height:18px; border-radius:9999px;
    border:2px solid rgba(255,255,255,0.35);
    border-top-color:#fff;
    animation: spin .7s linear infinite;
  }

  @keyframes fadeUp{ from{ opacity:0; transform:translateY(6px);} to{opacity:1; transform:translateY(0);} }
  .fade-up{ animation: fadeUp .5s ease both; }

  /* Esconde os incrementadores nativos dos campos numéricos (as setas ▲▼).
     O ajuste é só visual — subir/descer pelo teclado (▲/▼) segue funcionando. */
  input[type="number"]::-webkit-inner-spin-button,
  input[type="number"]::-webkit-outer-spin-button{ -webkit-appearance:none; margin:0; }
  input[type="number"]{ -moz-appearance:textfield; }

  .modal-view-transition{
    transition: opacity .22s ease, transform .22s ease;
    opacity:1; transform:translateY(0);
  }
  .modal-view-transition.view-exit{
    opacity:0; transform:translateY(6px);
  }

  @media (prefers-reduced-motion: reduce){
    .spinner{ animation:none; }
    .modal-view-transition{ transition:none; }
  }

  /* Selo "Conexão segura" do rodapé do login. Escondido por padrão e revelado só
     quando a página veio por HTTPS de verdade (classe is-https, posta antes do
     paint). Falha FECHADA de propósito: se o JS não rodar, o selo não aparece —
     um selo que promete segurança inexistente é pior que selo nenhum, porque
     ensina o usuário a confiar em algo que não é o cadeado do navegador.
     Seletor por id para vencer o .flex do Tailwind sem depender da ordem. */
  #secure-badge{ display:none; }
  html.is-https #secure-badge{ display:flex; }

    /* O login usa o LOCKUP horizontal (símbolo + nome), não o símbolo sozinho.
       Cada fundo tem a sua versão — o manual proíbe a clara sobre escuro —, e a
       troca é por CSS: sem JS, sem piscar antes do paint. */
    /* Dimensionado pela LARGURA, não pela altura: o lockup é 3:1, e o cartão
       de login tem ~312px de área útil (max-w-sm menos o p-9). Fixar altura
       faria a largura estourar o cartão nas telas estreitas.
       ⚠️ A largura é ABSOLUTA (272px), não `width:100%`. Com 100% o cálculo
       ficava circular: .login-logo-wrap é item de um flex column com
       `items-center`, então a largura dele é fit-content — depende do conteúdo —
       e o conteúdo pedia uma porcentagem dessa mesma largura. O Blink escapava
       chutando o tamanho intrínseco da imagem; o FIREFOX resolvia como ZERO e o
       logo sumia por completo (relatado em 2026-08-11). O `max-width:100%`
       preserva o comportamento responsivo nas telas estreitas, e a wrap ganhou
       largura definida para essa porcentagem ter de que se resolver.
       Os arquivos SVG também passaram a trazer width/height próprios (antes só
       tinham viewBox), para que a imagem tenha tamanho intrínseco de verdade. */
    .login-logo-wrap{ width:100%; }
    /* 17rem = os 272px de antes. Em rem para acompanhar o botão Aa junto com o
       resto da tela — a unidade muda, o eixo não: continua LARGURA absoluta,
       que é o que evita o cálculo circular descrito acima. */
    .lockup{ width:17rem; max-width:100%; height:auto; display:block; margin-inline:auto; }
    .lockup-claro{ display:none; }
    html.light .lockup-claro{ display:block; }
    html.light .lockup-escuro{ display:none; }

    /* Mesmo lockup do login, no cabeçalho do dashboard — substitui o símbolo
       isolado + "Argus"/contagem de registros em texto (2026-08-11, a pedido).
       Classe PRÓPRIA, não reaproveita .lockup: aqui o pai é flex ROW
       (`shrink-0 ... flex items-center`, ver index.html), não a coluna
       centralizada do login, então não existe a mesma armadilha de largura
       circular — dimensiona pela ALTURA sem risco, como qualquer item de
       flex row. Altura escolhida pra caber numa barra de topo sem dominar o
       espaço ao lado da navegação/busca (proporção 3:1 do lockup ⇒ ~186px
       de largura). 52px → 62px em 2026-08-11, a pedido (mais destaque). */
    /* 3.875rem = os 62px de antes, agora acompanhando o botão Aa. */
    .dash-lockup{ height:3.875rem; width:auto; display:block; }
    .dash-lockup-claro{ display:none; }
    html.light .dash-lockup-claro{ display:block; }
    html.light .dash-lockup-escuro{ display:none; }
    /* A compensação de +14px no topo do cartão saiu junto com a argola: ela
       existia só para equilibrar o que o scan-ring extravasava acima do logo. */
    #boot-status{display:none;}
    body.session-checking #login-form{display:none;}
    body.session-checking .login-only{display:none;}
    body.session-checking #boot-status{display:block;text-align:center;}
    #boot-status .boot-status-title{font-size:0.9375rem;color:var(--muted);letter-spacing:.02em;}
    /* Modo checagem: cartão compacto e centrado; logo maior por TAMANHO real
       (não transform, que deixava colado no topo e vazio embaixo) + um respiro
       entre o logo e o texto. */
    body.session-checking .login-hero{margin-bottom:0;}
    /* Escopado ao cartão de login (#login-screen): a classe .glass-card também é
       usada nos botões de tema/fonte — sem o escopo, eles inchavam. */
    body.session-checking #login-screen .glass-card{padding:48px 40px 42px;}
    body.session-checking .login-logo-wrap{margin-bottom:22px;}
    /* No modo checagem o lockup cresce mais: é o único elemento do cartão.
       Mexe em `width` porque agora é ela que dimensiona — o `max-width` virou
       só o teto responsivo em 100%. */
    body.session-checking .lockup{width:18rem;}

    /* ── Caixa de recado (lote de notas) ──────────────────────────────────
       O MESMO elemento serve aos três desfechos de uma geração em lote, e por
       isso a cor sai daqui e não do `style` inline: o JS troca de classe.
       Escrever as três cores inline obrigaria o JS a reescrever fundo, borda e
       texto a cada mensagem, e estilo inline vence folha sem `!important` —
       tropeço que este projeto já pagou duas vezes (ver #clients-scroll).

       ⚠️ O painel resolve "ok x erro" com DOIS elementos (#etest-ok ao lado da
       caixa de erro, e mais quatro pares assim). Aqui não dá: o desfecho de um
       lote pode ser MISTO — "3 emitidas, 1 não saiu" —, e dois elementos ou
       mostram as duas caixas ao mesmo tempo ou escolhem uma e escondem metade
       do que aconteceu.

       ⚠️ O âmbar do misto é o --provisorio, e não o --aviso. Nesta paleta o
       --aviso é da MESMA família do --erro (decisão de 2026-08-11, no bloco dos
       tokens): um lote parcial pintado de --aviso ficaria visualmente igual ao
       lote que falhou inteiro, que é exatamente a confusão a evitar. */
    .caixa-recado{ border:1px solid transparent; }
    .caixa-recado.ok{ color:var(--ok);
      background:rgba(var(--ok-rgb),0.1); border-color:rgba(var(--ok-rgb),0.25); }
    .caixa-recado.parcial{ color:var(--provisorio);
      background:rgba(var(--provisorio-rgb),0.1); border-color:rgba(var(--provisorio-rgb),0.3); }
    .caixa-recado.erro{ color:var(--erro);
      background:rgba(var(--erro-rgb),0.1); border-color:rgba(var(--erro-rgb),0.25); }

  /* ===================== GRADE DE CLIENTES EM TELA GRANDE =====================
     Pedido do dono, 2026-09-05: "quando estiver na largura maxima, na largura
     grande, coloque o numero do cliente e o CNPJ numa coluna nova; diminuindo,
     joga pra baixo do nome de novo".

     ⚠️ AS LARGURAS DAS DUAS COLUNAS SUBIRAM DEPOIS DE UM RELATO DO DONO: a
     primeira versao (64px + 170px) media so o VALOR, e esqueceu que o
     CABECALHO (rotulo + seta de ordenacao) mora na MESMA coluna em
     table-fixed. Resultado: "Codigo" cortado para "Codig", vazando por tras
     do fundo opaco da coluna vizinha, e o CNPJ truncando em ALGUMAS linhas e
     nao em outras do MESMO tamanho -- 170px sobrava ~1px pro pior caso, e
     texto que trunca com text-align:center fica com a elipse fora do lugar,
     parecendo desregulado (nao e so estetica: e um descasamento conhecido
     entre `text-overflow:ellipsis` e centralizacao). Medido de novo com o
     <th> de verdade e a escala de fonte "Maior" (125%, que este painel
     oferece e a folga tem de sobreviver): Codigo pede 98px, CNPJ/CPF pede
     221px no pior caso (todos os digitos largos, ex. "88.888.888/0008-88",
     que fechou em 239 de um teste a 240px — 1px de folga e pouco pra depender
     de renderizacao). As larguras abaixo, 112 e 248, tem folga de verdade
     sobre essas duas contas -- ver o comentario no index.html pelos numeros
     completos.

     O breakpoint tambem subiu, de 1600 para 1700px, para a celula Cliente nao
     ficar espremida pelo aumento das outras duas. Medido no navegador, SEM as
     colunas:

       1366px de janela -> 427px          1700px de janela -> ~745px

     Com as colunas ligadas a 1700px (112+248=360px), a celula Cliente cai
     para ~745-360 = ~385px -- proximo do que ja funciona hoje a 1366px, sem
     reclamacao. Abaixo de 1700 o aperto so cresceria; por isso o corte fica
     ali, e nao antes. */
  @media (min-width:1700px){
    #clients-table .col-grande{ display:table-cell; }
    /* O subtitulo (numero + documento sob o nome, cliente-grade.js) sai
       quando a coluna propria entra — senao a mesma informacao apareceria
       duas vezes na mesma linha. */
    #clients-table .cliente-doc-subtitulo{ display:none; }
  }

  /* O OLHO das três senhas do Painel de Controle (dono, 2026-09-08: "deixa eles
     criptografados e coloca o olhozinho para visualizar a senha quando
     clicar"). Mora DENTRO do campo, à direita, sem borda própria: quem tem
     borda é o `.filter-shell` em volta, e um segundo contorno aqui faria o
     campo parecer dois controles. Mesmo peso visual do olho da grade de Senhas
     — cor `--muted-2` em repouso, `--text` no hover. */
  .senha-olho{
    display:flex; align-items:center; justify-content:center;
    width:1.25rem; height:1.25rem; margin-left:0.25rem;
    color:var(--muted-2); background:transparent; border:none;
    cursor:pointer; transition:color .15s ease;
  }
  .senha-olho:hover{ color:var(--text); }
  /* `.hidden` do Tailwind precisa vencer o `display:flex` acima — sem isto o
     olho apareceria na inclusão, onde não há senha para revelar. */
  .senha-olho.hidden{ display:none; }

  /* GUARDA DO PAINEL DE CONTROLE (dono, 2026-09-05): a ficha juntou os cinco
     campos (Painel de Controle, Usuário, três senhas) numa linha só em
     2xl, usando `2xl:contents` em #client-panel-passwords-edit para
     promover as três senhas até a grade — ver o comentário grande no
     index.html.

     ⚠️ ISTO EXISTE PORQUE `display:contents` E `display:none` DISPUTAM A
     MESMA PROPRIEDADE. #client-panel-passwords-edit é escondido/mostrado
     pelo JS (`syncPanelPasswordVisibility`, cliente-ficha.js) trocando a
     classe `.hidden` — e o Tailwind gera as variantes `2xl:` DEPOIS das
     classes base no CSS compilado, de propósito, para a responsividade
     funcionar. Isso faz `2xl:contents` VENCER `.hidden` na cascata: sem
     esta regra, a partir de 1536px os TRÊS CAMPOS DE SENHA apareceriam na
     tela mesmo com "Painel de Controle" desligado ou o cliente ainda sem
     senha provisionada — o JS diria "esconda" e a tela mostraria mesmo
     assim.

     `!important` aqui é ESCOPADO a um ID só, e por isso é seguro: não é o
     `.hidden` do Tailwind que está sendo alterado (esse continua igual em
     todo o resto do painel) — é uma regra própria, só para este elemento,
     dizendo que ele sempre respeita `.hidden` não importa a largura da
     tela.

     ⚠️ DESDE 2026-09-08 NADA ESCONDE ESTE BLOCO: as três senhas passaram a
     aparecer sempre, com ou sem Painel de Controle (ver o comentário no
     index.html). A regra fica como REDE: o dia em que alguém voltar a
     escondê-lo por JS, o defeito não renasce a 1536px. Guarda inerte custa
     uma linha; o defeito custou uma caçada. */
  #client-panel-passwords-edit.hidden{ display:none !important; }

  /* A DATA-BASE EM "PAGO" SAI ÂMBAR, na conferência do retorno (cobranca.js).
     Pedido do Carlos em 09/09/2026: o certo é quase sempre basear o próximo
     boleto no VENCIMENTO, então a linha sugerida em data de pagamento é exceção
     e ele quer olhar uma a uma antes de efetivar. Numa lista de dezenas de
     linhas, a cor é o único jeito de achar essas sem reler todas.

     Âmbar é --provisorio, o único da paleta — o --aviso é da MESMA família do
     --erro (decisão de 11/08/2026), e pintar de vermelho diria "isto está
     errado", quando é só "confira esta".

     ⚠️ `!important` porque o estilo-base do select é ATRIBUTO style, e atributo
     ganha de qualquer seletor. E o fundo vai em degradê de uma cor só sobre o
     --panel-strong: uma tinta translucida direta deixaria o select transparente
     por cima da linha da grade. */
  select.conf-base.base-pago{
    color:var(--provisorio) !important;
    font-weight:600;
    border-color:rgba(var(--provisorio-rgb),0.55) !important;
    background:linear-gradient(rgba(var(--provisorio-rgb),0.14), rgba(var(--provisorio-rgb),0.14)),
               var(--panel-strong) !important;
  }
