/* ===========================================================================
   04 · COMPONENTES
   As peças que as telas montam: botão, card, cartão de número, tabela,
   etiqueta de status, formulário, paginação, aviso, modal, estado vazio e o
   painel "Cobrar agora".

   A ORDEM DOS BLOCOS AQUI É A ORDEM QUE ESTAVA NO ARQUIVO ÚNICO. Não é
   capricho: dois pontos dependem dela e não dariam erro nenhum se
   invertessem, só desenhariam diferente.
     1. `@media (max-width: 480px) .btn { padding }` precisa vir DEPOIS de
        `.btn-icon { padding: 0 }`, senão o botão quadrado de ícone ganha
        padding no celular e deixa de ser quadrado
     2. `.cobranca { padding: 0 }` precisa vir DEPOIS dos breakpoints de
        `.card`, porque o painel é `class="card cobranca"` e as duas regras
        têm a mesma especificidade (0,1,0): quem vier por último ganha
   =========================================================================== */

/* ── Botões ────────────────────────────────────────────────────────────── */
.btn {
    display: inline-flex;
    align-items: center;
    /* O conteudo fica centrado quando o botao e mais largo que ele. Acontece
       sempre que um formulario ou um grid estica o botao: o "Adicionar" da
       blacklist mede 214px para um conteudo de ~110px, e sem isto o icone e o
       texto ficavam encostados na borda esquerda, com um vazio a direita. */
    justify-content: center;
    gap: var(--esp-2);
    /* Padding-x menor: a razão x/y era 2,00 e o dono pediu o botão menos
       largo. 20px -> 16px leva a razão a 1,60. Só o x: a altura não depende
       dele, e encolher o y brigaria com os 44px de alvo de toque. */
    padding: 10px var(--esp-4);
    border-radius: var(--raio);
    font-size: var(--txt-corpo);
    font-weight: var(--peso-medio);
    /* `line-height` declarado é metade do conserto das SETE alturas medidas na
       mesma tela de /loans a 1366px (24, 26, 27, 28, 29, 37 e 39px). Sem ele a
       caixa de texto vinha do `normal` da fonte e o botão com ícone saía mais
       alto, porque o <svg> tem `vertical-align: -0.125em`. */
    line-height: 1.25;
    cursor: pointer;
    transition: all var(--dur-rapida) var(--curva);
    /* A outra metade: `border: none` fazia do `.btn-secondary`, único com
       borda, um botão 2px mais alto que todos os vizinhos. Transparente ocupa
       o mesmo espaço sem desenhar nada. */
    border: 1px solid transparent;
    text-decoration: none;
}

/* O desenho dentro da caixa do símbolo varia muito: medido nos 87 símbolos do
   sprite, a fração vertical vai de 0,25 a 1,00, mediana 0,79. Com a caixa em
   1em (14px) o traço mediano saía 11,06px contra uma maiúscula de 11px, e os
   achatados bem abaixo (`eye` 8,17px, `banknote` 7,00px). Em 1,15em a caixa vai
   a 16,09px e o traço mediano a 12,72px, 16% acima da maiúscula, que é a
   proporção que Lucide e Material usam.
   NÃO resolve os achatados, e isso é esperado: para empatar o `eye` o fator
   teria que ser 1,35em, e aí o `trash-2` (11,67px em 1em) sairia grande demais. */
.btn > .icone { width: 1.15em; height: 1.15em; }

.btn-primary {
    background: linear-gradient(135deg, var(--gold) 0%, var(--gold-dark) 100%);
    color: var(--dark);
}

/* REALCE QUE NÃO PROJETA PARA BAIXO, decisão do dono. Era
   `translateY(-2px)` + `box-shadow: 0 8px 20px`: o botão subia e jogava sombra
   8px abaixo de si. No lugar, anel de 1px na própria borda e clareamento leve.
   Os TRÊS gradientes mudam juntos, senão ficam incoerentes entre si. O
   gradiente de 135deg fica como está. */
.btn-primary:hover {
    box-shadow: 0 0 0 1px var(--gold-a40);
    filter: brightness(1.08);
}

.btn-secondary {
    background: var(--dark-lighter);
    color: var(--text);
    border: 1px solid var(--dark-border);
}

.btn-secondary:hover {
    background: var(--dark-border);
    border-color: var(--gold-dark);
}

/* .btn-gold: a variante existia so no CSS do portal, e OITO views do painel ja
   a usavam. Sem a declaracao o <a> nao recebe `color`, e cai no azul padrao do
   navegador: era o lapis de "Editar" na tela de credores, medido em 1,63:1 de
   contraste. O texto e escuro pelo mesmo motivo dos irmaos: o dourado e claro
   demais para branco. */
.btn-gold {
    background: linear-gradient(135deg, var(--gold) 0%, var(--gold-dark) 100%);
    color: var(--dark);
}

.btn-success {
    background: linear-gradient(135deg, var(--secondary) 0%, #059669 100%);
    /* Escuro, nao branco: esta cor de fundo e clara demais e o branco
       reprovava no contraste. Mesma escolha que o .btn-primary ja fazia com o
       gold. Medido: verde 2,54 -> 7,8:1, vermelho 3,76 -> 5,26:1, amarelo
       2,15 -> 9,22:1, contra o minimo de 4,5:1. */
    color: var(--dark);
}

.btn-success:hover {
    box-shadow: 0 0 0 1px var(--success-a40);
    filter: brightness(1.08);
}

.btn-danger {
    /* O gradiente CLAREIA, ao contrario dos irmaos. Com ele escurecendo ate
       #DC2626, o texto escuro caia para 4,1:1 naquela ponta, contra os 4,5
       exigidos; clareando, as duas pontas passam (5,26:1 e 6,43:1). */
    background: linear-gradient(135deg, var(--danger) 0%, #F26565 100%);
    /* Escuro, nao branco: esta cor de fundo e clara demais e o branco
       reprovava no contraste. Mesma escolha que o .btn-primary ja fazia com o
       gold. Medido: verde 2,54 -> 7,8:1, vermelho 3,76 -> 5,26:1, amarelo
       2,15 -> 9,22:1, contra o minimo de 4,5:1. */
    color: var(--dark);
}

.btn-danger:hover {
    box-shadow: 0 0 0 1px var(--danger-a40);
    filter: brightness(1.08);
}

.btn-warning {
    background: linear-gradient(135deg, var(--warning) 0%, #D97706 100%);
    /* Escuro, nao branco: esta cor de fundo e clara demais e o branco
       reprovava no contraste. Mesma escolha que o .btn-primary ja fazia com o
       gold. Medido: verde 2,54 -> 7,8:1, vermelho 3,76 -> 5,26:1, amarelo
       2,15 -> 9,22:1, contra o minimo de 4,5:1. */
    color: var(--dark);
}

/* Mesma razão do `.btn`: 12px -> 10px leva o x/y de 2,00 para 1,67. O 10px é
   literal de propósito, ver a lista de "quase" em 01-tokens.css:154-166. */
.btn-sm {
    padding: 6px 10px;
    font-size: var(--txt-mini);
}

/* Botão quadrado, só ícone. É o componente dos 64 botões de ação das listas,
   que hoje as views montam com `.btn.btn-sm` mais um `<i>`. Ver a lista de
   conversão no relatório da fase. */
.btn-icon {
    width: 36px;
    height: 36px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--raio);
}

.btn-icon.danger {
    background: var(--danger-a10);
    color: var(--danger);
    /* Transparente, não `none`, pela mesma razão do `.btn`: a caixa tem que
       medir igual à dos vizinhos com borda. */
    border: 1px solid transparent;
    cursor: pointer;
    transition: all var(--dur-rapida) var(--curva);
}

.btn-icon.danger:hover {
    background: var(--danger);
    color: white;
}

/* DEPOIS do .btn-icon de propósito: ver o item 1 do cabeçalho.
   O x também encolhe aqui (14 -> 12 e 10 -> 8), levando as razões de 1,75 e
   2,00 para 1,50 e 1,60. O y NÃO desce: é ele que sustenta os 44px de alvo de
   toque que 06-interacao.css garante neste mesmo recorte de tela. */
@media (max-width: 480px) {
    .btn { padding: var(--esp-2) var(--esp-3); font-size: var(--txt-rotulo); }
    .btn-sm { padding: 5px var(--esp-2); font-size: var(--txt-nota); }
}

/* ── Card ──────────────────────────────────────────────────────────────── */
.card {
    background: var(--dark-card);
    border: 1px solid var(--dark-border);
    border-radius: var(--raio-lg);
    padding: var(--esp-6);
    /* Card dentro de grid/flex precisa poder encolher */
    min-width: 0;
}

/* DOIS CARDS EMPILHADOS SE SEPARAM SOZINHOS.
   Antes cada tela resolvia por conta: `mb-*` na view, ou `style="margin-top:
   24px"` escrito a mao (6 vezes so no audit.ejs), e onde ninguem lembrou os
   cards encostavam. Medido em 17 telas: 25 pares irmaos, 2 colados.

   Nao soma onde ja ha espaco: margem vertical de irmaos em fluxo normal
   COLAPSA, entao 24 contra 24 continua 24, e os 23 pares corretos nao mudam
   um pixel.

   SEGURO PORQUE NAO EXISTE PAR LADO A LADO no sistema (conferido na mesma
   varredura): num grid de cards em fila, este `margin-top` desceria o segundo
   e quebraria o alinhamento. Se um dia aparecer uma fila de `.card`, o espaco
   dela e `gap` no pai, e esta regra precisa ser revista junto. */
/* FILHO DIRETO DE `.page-content`, e isso e conserto de um erro meu.
   A regra nasceu como `.card + .card` solto e alcancou dois contextos
   onde nao devia:
     grid (formulario de emprestimo e de venda): o segundo card de cada
     par LADO A LADO descia 24px e ficava 24px mais curto que o irmao.
     Medido: tops 132/156, alturas 313/289.
     flex (formulario de cliente): ali nao ha colapso de margem, entao os
     24px SOMAVAM ao `gap` do contêiner e o espaco virava 48.
   Eu tinha escrito que "nao existe par lado a lado no sistema", apoiado
   numa varredura de 17 telas que media listagens e telas de leitura. Os
   pares lado a lado vivem nos FORMULARIOS, que ficaram de fora.
   Cards empilhados sao filhos diretos do conteudo da pagina; quem esta
   dentro de grid ou flex tem o `gap` do proprio contêiner cuidando. */
.page-content > .card + .card { margin-top: var(--esp-6); }

/* CARD RECOLHIDO: a margem do cabecalho some junto com o conteudo.
   O `.card-header` carrega `margin-bottom` para se separar do conteudo, e quem
   recolhe o card esconde SO o conteudo (`display: none` pelo JS), deixando a
   margem orfa. Medido em /elite-cred/loans: sob o titulo sobravam 44px, os
   20 da margem mais os 24 do padding do proprio card, contra 24px no topo.
   As duas grafias existem porque `style.display = 'none'` escreve
   "display: none;", mas um atributo escrito a mao pode vir sem o espaco. */
.card:has(> [style*="display: none"]) > .card-header,
.card:has(> [style*="display:none"]) > .card-header {
    margin-bottom: 0;
}

.card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--esp-3);
    flex-wrap: wrap;
    margin-bottom: var(--esp-5);
}

.card-title {
    font-size: var(--txt-titulo);
    font-weight: var(--peso-forte);
    color: white;
}

.card-title .icone { color: var(--gold); }

@media (max-width: 768px) {
    .card { padding: var(--esp-4); }
    .card-header { gap: var(--esp-2); }
    .card-title { font-size: var(--txt-destaque); }
}

@media (max-width: 480px) {
    .card { padding: var(--esp-3); border-radius: var(--raio-md); }
}

/* ── Cartões de número (a carteira) ────────────────────────────────────── */
.stats-grid {
    display: grid;
    /* auto-fit acomoda quantos cards couberem em vez de forçar 4 colunas.
       O mínimo de 290px é o necessário para "R$ 152.290,40" caber numa linha
       ao lado do ícone: abaixo disso o valor quebra e o card fica feio.
       O min() evita estouro quando a tela é mais estreita que o mínimo. */
    grid-template-columns: repeat(auto-fit, minmax(min(290px, 100%), 1fr));
    gap: var(--esp-4);
    /* 24px, o mesmo vao que separa todos os outros blocos da pagina. Eram 32px,
       e o degrau aparecia logo abaixo da fila de cards: o espaco ate o bloco
       seguinte era maior que o de qualquer outro par da tela. */
    margin-bottom: var(--esp-6);
}

/* ── ABAS ───────────────────────────────────────────────────────────────────
   Nasceram na tela de Sócios, para as duas grades de quatro cards não ficarem
   empilhadas: oito cards antes do conteúdo é uma rolagem inteira de números no
   celular antes de chegar na tabela.

   A LINHA ROLA NO CELULAR em vez de quebrar. Aba que quebra para a segunda
   linha perde a leitura de "escolha uma destas", e é o mesmo tratamento que o
   índice da página de privacidade recebeu: faixa rolável, não grade.

   O comportamento vive em `public/js/abas.js`, por delegação. A classe que
   esconde é `.oculto` de 05-utilitarios, nunca `style.display` escrito pelo
   JavaScript, pelo mesmo motivo registrado no modais.js. */
.abas {
    display: flex;
    gap: var(--esp-1);
    border-bottom: 1px solid var(--dark-border);
    margin-bottom: var(--esp-5);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    /* A barra de rolagem some, mas o gesto fica: a faixa é curta e a barra
       cortaria a borda de baixo, que é o que liga a aba ao conteúdo. */
    scrollbar-width: none;
}
.abas::-webkit-scrollbar { display: none; }

.aba {
    /* `white-space: nowrap` é o que faz a faixa rolar em vez de espremer. */
    white-space: nowrap;
    background: none;
    border: 0;
    border-bottom: 2px solid transparent;
    color: var(--text-muted);
    font-size: var(--txt-rotulo);
    font-weight: var(--peso-medio);
    letter-spacing: 0.04em;
    padding: var(--esp-3) var(--esp-4);
    cursor: pointer;
    transition: color var(--dur-rapida) ease, border-color var(--dur-rapida) ease;
}

.aba:hover:not(.ativa) { color: var(--text); }

.aba.ativa {
    color: var(--gold);
    border-bottom-color: var(--gold);
}

/* O ícone da aba acompanha o texto e não ganha margem própria: o `gap` do
   contêiner já separa, e margem em item flex SOMA ao gap (a regra que
   05-utilitarios zera em quinze outros lugares). */
.aba > .icone { margin-right: var(--esp-2); vertical-align: middle; }

@media (max-width: 480px) {
    .aba { padding: var(--esp-3) var(--esp-3); }
}

.stat-card {
    background: var(--dark-card);
    border: 1px solid var(--dark-border);
    border-radius: var(--raio-lg);
    padding: var(--esp-6);
    /* Duas colunas: o ícone e o bloco de texto. O `.stat-info` é UM item do
       grid, e é isso que deixa o card imune ao número de filhos que ele tem.
       A VERSÃO ANTERIOR entregava os filhos do `.stat-info` ao grid do card
       (`display: contents`) e herdava três faixas da fila por subgrid, para
       rótulo, valor e nota alinharem entre cards vizinhos. Isso só funciona
       com EXATAMENTE três filhos: medido em /elite-cred/loans, a 1440 e a
       390px, 6 dos 8 cards têm quatro (rótulo, valor, legenda e a nota do
       período), e o quarto, sem faixa livre na coluna 2, caiu NA COLUNA DO
       ÍCONE: no card "Na Rua (No Prazo)" a nota "Todo o período" saiu em x=28
       contra x=137 dos três irmãos. As telas de três filhos (/socios,
       /recuperacao, /clients) não quebravam, o que fazia o defeito passar
       despercebido justamente onde ele era a regra. Alinhamento entre cards não
       paga um card quebrado em 6 de 8. */
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: start;
    column-gap: var(--esp-4);
}

/* SEM ICONE, SEM VAO. O card e um grid de duas colunas e a primeira e a do
   icone; quando ele nao existe ela mede 0px, mas o `column-gap` continua
   valendo e some ao padding. Medido na ficha do cliente: 24px de padding mais
   16 de gap davam 44px antes do texto, contra 24px de quem tem icone de 48px
   (onde o vao faz sentido). */
.stat-card:not(:has(> .stat-icon)) {
    column-gap: 0;
    transition: all var(--dur-media) var(--curva);
    min-width: 0;
}

.stat-card:hover {
    transform: translateY(-4px);
    box-shadow: 0 12px 40px var(--preto-a60);
}

.stat-card.primary { border-left: 4px solid var(--gold); }
.stat-card.success { border-left: 4px solid var(--secondary); }
.stat-card.warning { border-left: 4px solid var(--warning); }
.stat-card.danger { border-left: 4px solid var(--danger); }
.stat-card.gold { border-left: 4px solid var(--gold); }

.stat-icon {
    grid-column: 1;
    grid-row: 1 / -1;
    width: 48px;
    height: 48px;
    flex-shrink: 0;
    border-radius: var(--raio-md);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--txt-titulo-g);
}

.stat-card.primary .stat-icon { background: var(--gold-dim); color: var(--gold); }
.stat-card.success .stat-icon { background: var(--success-a20); color: var(--secondary); }
.stat-card.warning .stat-icon { background: var(--warning-a20); color: var(--warning); }
.stat-card.danger .stat-icon { background: var(--danger-a20); color: var(--danger); }
.stat-card.gold .stat-icon { background: var(--gold-dim); color: var(--gold); }

/* SEM `gap` de propósito: os filhos já trazem a própria margem (4px no
   `.stat-label`, 5px no `.stat-nota`, 8px no `.stat-change`), e os 5px da nota
   são literais em 24 lugares das views. Um gap aqui somaria em cima de todas
   elas e mexeria no espaçamento de cada card do sistema. */
.stat-info {
    grid-column: 2;
    display: flex;
    flex-direction: column;
    min-width: 0;
}
.stat-label { font-size: var(--txt-rotulo); color: var(--text-muted); margin-bottom: var(--esp-1); overflow-wrap: anywhere; line-height: 1.3; }

/* O rótulo do topo do card para em DUAS linhas.
   POR QUE: em /elite-cred/socios os rótulos têm 63, 13, 15 e 18 caracteres. O
   primeiro quebrava em três linhas e empurrava o valor dele 32px abaixo dos
   três vizinhos (medido a 1280, 1366 e 1600px). Os cards têm a mesma altura:
   o que desalinha é o conteúdo dentro deles.
   POR QUE POR CSS e não encurtando o texto: os testes leem os cards pelo
   TÍTULO, com regex em cima do rótulo, justamente porque a grade já mudou de
   tamanho uma vez e os testes por posição quebraram junto.
   Só o PRIMEIRO rótulo: o segundo `.stat-label` de cada card é a legenda que
   vem embaixo do valor, e cortar em duas linhas nela esconderia a legenda.
   AQUI HAVIA UM `align-self: end`, que encostava o rótulo no fundo da faixa do
   subgrid. Com o subgrid fora, o eixo cruzado do `.stat-info` é HORIZONTAL:
   `end` jogaria o rótulo para a direita do card. Saiu junto com as faixas. */
.stat-info > .stat-label:first-child {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* O valor não quebra no meio (separar "R$" do número fica horrível). Se não
   couber, ele encolhe pelo clamp em vez de quebrar a linha. */
.stat-value {
    font-size: clamp(18px, 1.6vw + 8px, 28px);
    font-weight: var(--peso-max);
    color: white;
    line-height: 1.15;
    white-space: nowrap;
    overflow-wrap: normal;
}
.stat-change { font-size: var(--txt-mini); margin-top: var(--esp-2); }
.stat-change.positive { color: var(--secondary); }
.stat-change.negative { color: var(--danger); }

@media (max-width: 768px) {
    .stat-value { font-size: 22px; }
}

@media (max-width: 480px) {
    .stat-card { padding: var(--esp-4); gap: var(--esp-3); }
    .stat-icon { width: 40px; height: 40px; font-size: var(--txt-destaque); }
    .stat-value { font-size: var(--txt-titulo-g); }
}

/* ── Tabelas ───────────────────────────────────────────────────────────── */
/* A tabela rola dentro do próprio container em vez de esticar a página */
.table-container { overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; }
table { width: 100%; border-collapse: collapse; }
th { text-align: left; padding: var(--esp-3) var(--esp-4); font-size: var(--txt-nota); font-weight: var(--peso-medio); color: var(--gold-dark); text-transform: uppercase; letter-spacing: 0.5px; border-bottom: 1px solid var(--dark-border); }
td { padding: var(--esp-4); border-bottom: 1px solid var(--dark-border); font-size: var(--txt-corpo); }
tr:hover { background: var(--gold-dim); }

/* No celular a célula para de quebrar palavra e quem rola é o container.

   O QUE ESTAVA ERRADO: `min-width: min-content` sozinho deixa a tabela encolher
   até a MENOR largura possível, que é cada coluna na largura da sua palavra
   mais longa. Medido em /elite-cred/loans a 600px: "Francy Ellem Coelho De
   Souza Neves" ocupava CINCO linhas, uma palavra por linha, e a coluna de data
   saiu partida ao meio ("03/" numa linha, "08/1" na outra). A tabela cabia na
   tela e era ilegível, que é o pior dos dois mundos.
   COM `white-space: nowrap` NA CÉLULA o `min-content` passa a ser a largura
   real do texto: a tabela mantém a largura de que precisa e quem rola é o
   `.table-container`, que já tem `overflow-x: auto` desde sempre.
   NUNCA trocar isto por `overflow-x: hidden` no html/body: aquilo recorta a
   coluna e some com ela, além de mascarar qualquer medição por scrollWidth.

   O `min-content` continua no lugar do `min-width: 620px` fixo que já esteve
   aqui: com 620px igual para todas, um container de 310px ganhava 310px de
   rolagem MORTA em cada tabela que já cabia (2.120px inventados em 10 tabelas,
   medidos a 360px).

   AS 8 TABELAS-CARTÃO FICAM DE FORA, e isso não é zelo: no celular elas deixam
   de ser tabela (a célula vira grid de rótulo + valor, uma embaixo da outra), e
   nowrap ali estouraria a largura do cartão, que é exatamente o que o cartão
   veio resolver. A exclusão sai pela MESMA variável que acende o cartão
   (`--cartao-celula-quebra`, declarada no bloco de acendimento logo abaixo) e
   não por um seletor repetido: quem vira cartão continua escrito num lugar só.

   A CÉLULA COM TEXTO DE VERDADE CONTINUA QUEBRANDO, pelo `small`. Nota longa
   neste sistema é sempre `<small>` dentro da célula, e a maior delas é a
   explicação do acerto manual em /elite-cred/socios ("a regra dava R$ X por
   sócio", a diferença e o motivo escrito à mão), que é justamente uma das duas
   tabelas que NÃO viram cartão. Em nowrap ela viraria uma linha de centenas de
   pixels e arrastaria a tabela inteira junto. Quebrando, a coluna fica com a
   largura da parte que não quebra (o valor) e a nota se acomoda dentro dela.

   O SELETOR CARREGA `.table-container`: as 5 tabelinhas de resumo soltas dentro
   de um card (loans-view e sales-view, duas colunas de rótulo e valor) não têm
   container nem rolagem, e nowrap nelas estouraria o card. */
/* SEM MEDIA QUERY: o mesmo defeito existe no desktop. Medido a 1440px na
   dashboard, onde "Parcelas Vencidas" e "Proximas Parcelas" ficam lado a lado e
   cada uma recebe metade da largura: a coluna Cliente fica com 119px e empilha
   "Erikles Henrique Lima Do Nascimento" em 5 linhas, 26 celulas assim numa
   tabela so. Travar a correcao no celular consertava onde a reclamacao veio e
   deixava o mesmo problema na tela grande.
   O modo cartao nao e afetado: ele so acende abaixo de 600px, e quando acende
   define --cartao-celula-quebra: normal, que vence este nowrap. */
.table-container table { min-width: min-content; }
.table-container td,
.table-container th { white-space: nowrap; }

@media (max-width: 768px) {
    .table-container td small { white-space: normal; }
    td, th { padding: 10px var(--esp-3); }
}

/* AQUI FICAVA O MODO "TABELA VIRA CARTAO" NO CELULAR, removido em 08/10/2026.
   Cada linha da tabela virava um cartao com rotulo e valor, um par por linha de
   tela. O custo e uma linha de tela POR COLUNA, e medido a 390x844 isso deu:
     Credores    210 registros, 15 colunas, 474px cada ... 117,8 telas de rolagem
     Blacklist    50 registros, 12 colunas, 668px cada ....  39,6 telas
     Recuperacao  32 registros,  9 colunas, 582px cada ....  22,1 telas
   Cada registro ocupava meia tela ou mais, e achar alguem numa lista de 210
   virava rolagem sem fim. O dono viu e recusou.
   O que vale agora e a tabela com rolagem HORIZONTAL: ela mostra varios
   registros de uma vez, e quem decide a largura e o `white-space: nowrap` das
   celulas, que esta la em cima, fora de qualquer media query. */

/* ── Etiqueta de status ───────────────────────────────────────────────────
   `cancelled`, `defaulted` e `inactive` parecem órfãs num grep das views, e
   NÃO SÃO: elas chegam por interpolação, em `class="status <%= loan.status %>"`
   e `class="status <%= client.status %>"` (9 views). Apagar qualquer uma tira
   a cor do estado sem que nada acuse. */
/* O lateral e `--esp-2` e nao `--esp-3`: com 11,5px a folga dava 2,9 contra 1
   do vertical, e o dono apontou num print que a pastilha estava larga demais
   para o texto. Medido em "+2 do mesmo IP": 93px de texto numa caixa de 116.
   Fui a 8px, ele pediu de novo, e ai a comparacao em imagem mostrou o que
   faltava: entre 8 e 6 a caixa muda 4px, mas o que pesa na largura e o RAIO.
   Com `--raio-pilula` numa caixa de 24px cada ponta vira um semicirculo de
   12px, e essa curva e massa visual que nao e padding. O padding foi a 6px,
   que e o pedido; o raio fica, porque mexer nele muda a FORMA de 30 badges e
   isso e decisao do dono, nao ajuste.
   O vertical NAO muda junto, senao a altura encolhe e a badge deixa de casar
   com a linha da tabela onde ela mora. */
.status { display: inline-flex; align-items: center; vertical-align: middle; gap: 6px; padding: var(--esp-1) 6px; border-radius: var(--raio-pilula); font-size: var(--txt-mini); font-weight: var(--peso-medio); }
.status.active { background: var(--success-a20); color: var(--secondary); }
.status.paid { background: var(--gold-dim); color: var(--gold); }
.status.pending { background: var(--warning-a20); color: var(--warning); }
.status.overdue { background: var(--danger-a20); color: var(--danger-texto); }
.status.cancelled, .status.blocked, .status.inactive { background: var(--neutro-a20); color: #9CA3AF; }
.status.defaulted { background: rgba(127, 29, 29, 0.3); color: #FCA5A5; }

/* ── Formulários ───────────────────────────────────────────────────────── */
.form-group { margin-bottom: var(--esp-5); min-width: 0; }
.form-label { display: block; font-size: var(--txt-rotulo); font-weight: var(--peso-medio); color: var(--text); margin-bottom: var(--esp-2); }
.form-input, .form-select, .form-textarea { width: 100%; padding: var(--esp-3) var(--esp-4); background: var(--dark-lighter); border: 1px solid var(--dark-border); border-radius: var(--raio); color: var(--text); font-size: var(--txt-corpo); font-family: inherit; transition: all var(--dur-rapida) var(--curva); }
/* Sem `outline: none` aqui: ele é declarado uma vez só, em 06-interacao.css,
   junto do anel que entra no lugar. Solto, ele apagava o contorno e não
   devolvia nada. O par borda dourada + brilho continua sendo o foco visível
   destes três, e continua em `:focus` (não em `:focus-visible`) de propósito:
   é o que o campo já mostra ao clicar, e isso não muda. */
.form-input:focus, .form-select:focus, .form-textarea:focus { border-color: var(--gold); box-shadow: 0 0 0 3px var(--gold-dim); }
.form-input::placeholder { color: var(--text-muted); }
.form-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr)); gap: var(--esp-5); }
.form-hint { font-size: var(--txt-mini); color: var(--text-muted); margin-top: var(--esp-1); }

@media (max-width: 768px) {
    /* Filtros e formulários viram uma coluna só */
    form { width: 100%; }
}

/* ── Envio de arquivo (KYC) ───────────────────────────────────────────────
   Estas quatro classes não são lixo: são o componente DESENHADO e NUNCA
   ADOTADO. `views/elite-cred/clients-form.ejs` monta o mesmo bloco 6 vezes
   com `style="display:flex; align-items:center; gap:8px; margin-bottom:8px"`
   e um `.btn.btn-sm.btn-secondary` dentro, que é exatamente
   `.existing-file` + `.file-link`. Ver a lista de conversão no relatório. */
.file-upload { border: 2px dashed var(--dark-border); border-radius: var(--raio-md); padding: var(--esp-6); text-align: center; cursor: pointer; transition: all var(--dur-rapida) var(--curva); }
.file-upload:hover { border-color: var(--gold); background: var(--gold-dim); }
.file-upload .icone { width: 32px; height: 32px; color: var(--gold-dark); margin-bottom: var(--esp-2); }
.file-upload p { color: var(--text-muted); font-size: var(--txt-corpo); }
.file-preview { display: flex; align-items: center; gap: var(--esp-3); margin-top: var(--esp-3); padding: var(--esp-3); background: var(--dark-lighter); border-radius: var(--raio); }
.file-preview img { width: 60px; height: 60px; object-fit: cover; border-radius: var(--raio); }

.existing-file {
    display: flex;
    align-items: center;
    gap: var(--esp-3);
    margin-bottom: var(--esp-2);
    padding: var(--esp-2);
    background: var(--dark-lighter);
    border: 1px solid var(--dark-border);
    border-radius: var(--raio);
}

.file-link {
    display: flex;
    align-items: center;
    gap: var(--esp-2);
    color: var(--gold);
    text-decoration: none;
    font-size: var(--txt-corpo);
    font-weight: var(--peso-normal);
    flex: 1;
}

.file-link:hover {
    text-decoration: underline;
}

/* ── Paginação ─────────────────────────────────────────────────────────── */
/* flex-wrap sempre: com 40+ páginas os links formavam uma linha de 2000px e
   estouravam a tela inteira no desktop */
.pagination { display: flex; align-items: center; justify-content: center; gap: var(--esp-2); margin-top: var(--esp-6); flex-wrap: wrap; }
.pagination a, .pagination span { padding: var(--esp-2) var(--esp-4); border-radius: var(--raio); font-size: var(--txt-corpo); font-weight: var(--peso-normal); text-decoration: none; transition: all var(--dur-rapida) var(--curva); }
.pagination a { background: var(--dark-lighter); color: var(--text); border: 1px solid var(--dark-border); }
.pagination a:hover { background: var(--gold-dim); border-color: var(--gold-dark); color: var(--gold); }
.pagination .active { background: linear-gradient(135deg, var(--gold) 0%, var(--gold-dark) 100%); color: var(--dark); border: none; }
.pagination .disabled { opacity: 0.5; cursor: not-allowed; }

/* ── Avisos ───────────────────────────────────────────────────────────────
   `.alert-<tipo>` também é montado por JavaScript: `showToast()` em
   layouts/scripts.ejs faz `toast.className = 'alert alert-' + type`. Só
   existem success, danger e warning; qualquer outro tipo cai sem estilo. */
.alert { padding: var(--esp-4) var(--esp-5); border-radius: var(--raio-md); margin-bottom: var(--esp-5); display: flex; align-items: center; gap: var(--esp-3); }
.alert-success { background: var(--success-a20); border: 1px solid var(--secondary); color: var(--secondary); }
.alert-danger { background: var(--danger-a20); border: 1px solid var(--danger); color: var(--danger); }
.alert-warning { background: var(--warning-a20); border: 1px solid var(--warning); color: var(--warning); }

/* ── Modal ────────────────────────────────────────────────────────────────
   ATENÇÃO: `.modal-overlay { display: none }` e `.modal-overlay.active
   { display: flex }` são regras de VISIBILIDADE comandadas por JavaScript
   (`classList.add('active')` nas quatro views com modal). Mudar o valor aqui
   não muda estilo, impede o modal de abrir.

   OS SETE MODAIS DO PAINEL PASSAM POR AQUI, inclusive os dois que até
   08/10/2026 abriam escrevendo `style.display` no elemento (`#editModal` da
   blacklist e `#modalPagamento` dos sócios). Inline vence qualquer regra de
   folha, então naqueles dois nenhuma animação daqui pegaria: eles foram
   convertidos para a mesma classe `.active` dos outros cinco. Dois tipos de
   modal no mesmo sistema era o custo de não converter.

   A ANIMAÇÃO PRECISA DAS DUAS PEÇAS, e nenhuma das duas serve sozinha:

     `allow-discrete` deixa `display` entrar na transição. `display` é
     propriedade DISCRETA: sem ele, pôr `transition` aqui não faz
     absolutamente nada, porque o elemento vai de `none` para `flex` num
     quadro só e a opacidade nem chega a começar.

     `@starting-style` diz de ONDE a entrada parte. Sem ele só a SAÍDA anima:
     na entrada o elemento acabou de passar a ser renderizado e não existe
     estilo anterior de onde interpolar, então o navegador pula direto para o
     estado final, sem erro nenhum.

   Medido nas sete telas, amostrando as transições por `getAnimations()` e
   `currentTime`: 3 transições criadas em cada modal (opacidade do fundo,
   opacidade e transform do painel), 200ms cada, e a opacidade lida em 0, 50 e
   100% da duração devolvendo 0 / 0,802 / 1. O 0,802 no meio é a `--curva`,
   que é `ease`: quem esperar 0,5 ali está testando contra `linear`. */
.modal-overlay {
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    background: var(--preto-a90);
    display: none;
    align-items: center;
    justify-content: center;
    z-index: var(--z-modal);
    opacity: 0;
    transition: opacity var(--dur-rapida) var(--curva),
                display var(--dur-rapida) var(--curva) allow-discrete;
}
.modal-overlay.active { display: flex; opacity: 1; }

/* Os três painéis: o `.modal` dos cinco de contrato, e os painéis próprios da
   blacklist e dos sócios, declarados mais abaixo neste arquivo. Ficam JUNTOS
   aqui de propósito: com a regra de movimento repartida em três lugares, um
   dia os três abrem diferente e ninguém sabe qual é o certo.
   O deslocamento é de 8px e a escala de 0,98: o painel sobe um fio enquanto
   aparece. Mais que isso vira pulo num modal de 500px de largura. */
.modal,
.modal-bl-painel,
.modal-pg-painel {
    opacity: 0;
    transform: translateY(8px) scale(0.98);
    transition: opacity var(--dur-rapida) var(--curva),
                transform var(--dur-rapida) var(--curva);
}

/* PAINEL LARGO, para o formulário que não cabe na largura de um modal comum
   (o fechamento do período tem seis campos e duas linhas de explicação).
   O `.card` dentro do overlay NÃO tem largura própria, e o overlay é flex com
   `align-items: center`: sem um teto aqui, o item estica na largura inteira da
   tela, que foi exatamente o que aconteceu no primeiro corte.

   `max-height` com rolagem porque o conteúdo é alto: sem isso, numa tela baixa
   o botão de registrar fica abaixo da dobra e não há como chegar nele. */
.modal-painel-largo {
    width: 100%;
    max-width: 860px;
    max-height: calc(100vh - var(--esp-6) * 2);
    overflow-y: auto;
    margin: var(--esp-6);
    opacity: 0;
    transform: translateY(8px) scale(0.98);
    transition: opacity var(--dur-rapida) var(--curva),
                transform var(--dur-rapida) var(--curva);
}

.modal-overlay.active .modal,
.modal-overlay.active .modal-bl-painel,
.modal-overlay.active .modal-painel-largo,
.modal-overlay.active .modal-pg-painel {
    opacity: 1;
    transform: none;
}

/* O estado de onde a ENTRADA parte. Fica depois das regras acima porque é
   delas que ele é o ponto de partida, e repete os mesmos valores do estado
   fechado: o painel nasce um pouco abaixo e um pouco menor. */
@starting-style {
    .modal-overlay.active { opacity: 0; }

    .modal-overlay.active .modal,
    .modal-overlay.active .modal-bl-painel,
    .modal-overlay.active .modal-pg-painel {
        opacity: 0;
        transform: translateY(8px) scale(0.98);
    }
}

/* Quem pediu menos movimento não recebe nenhum. O bloco geral de
   07-animacoes.css NÃO basta aqui: ele zera a DURAÇÃO, e com `display` ainda
   na lista de propriedades em transição o fechamento continua passando por um
   quadro com o modal já invisível ocupando a tela inteira. `transition: none`
   tira `display` da lista, e aí abrir e fechar voltam a ser a troca seca de
   sempre, sem quadro intermediário e sem nada preso. */
@media (prefers-reduced-motion: reduce) {
    .modal-overlay,
    .modal-overlay .modal,
    .modal-overlay .modal-bl-painel,
    .modal-overlay .modal-pg-painel {
        transition: none;
    }
}

.modal { background: var(--dark-card); border: 1px solid var(--gold-dark); border-radius: var(--raio-lg); width: 100%; max-width: 500px; max-height: 90vh; overflow-y: auto; }
.modal-header { padding: var(--esp-5) var(--esp-6); border-bottom: 1px solid var(--dark-border); display: flex; align-items: center; justify-content: space-between; }
.modal-title { font-size: var(--txt-titulo); font-weight: var(--peso-forte); color: var(--gold); }
.modal-close { background: none; border: none; color: var(--text-muted); font-size: var(--txt-titulo-g); cursor: pointer; }
.modal-body { padding: var(--esp-6); }
.modal-footer { padding: var(--esp-5) var(--esp-6); border-top: 1px solid var(--dark-border); display: flex; justify-content: flex-end; gap: var(--esp-3); }

@media (max-width: 768px) {
    .modal { margin: var(--esp-3); max-width: calc(100vw - 24px); }
    .modal-body { padding: var(--esp-4); }
    .modal-footer { padding: var(--esp-3) var(--esp-4); flex-wrap: wrap; }
}

@media (max-width: 480px) {
    .modal-footer .btn { flex: 1; justify-content: center; }
}

/* ── Identificação do cliente ──────────────────────────────────────────── */
.avatar { width: 40px; height: 40px; border-radius: var(--raio-circulo); background: linear-gradient(135deg, var(--gold) 0%, var(--gold-dark) 100%); display: flex; align-items: center; justify-content: center; font-size: var(--txt-destaque); font-weight: var(--peso-forte); color: var(--dark); }
.client-badge { display: flex; align-items: center; gap: var(--esp-3); }
.client-info { display: flex; flex-direction: column; gap: var(--esp-1); }
.client-name { font-weight: var(--peso-medio); color: white; }
.client-cpf { font-size: var(--txt-mini); color: var(--text-muted); }

/* ── Dinheiro ──────────────────────────────────────────────────────────── */
.money { font-weight: var(--peso-forte); font-family: var(--fonte-num); }
.money.positive { color: var(--secondary); }
.money.negative { color: var(--danger); }

/* ── Estado vazio ──────────────────────────────────────────────────────── */
.empty-state { text-align: center; padding: var(--esp-15) var(--esp-5); }
/* FILHO DIRETO, nao descendente: o estado vazio ganhou um botao de acao com
   icone, e o seletor descendente alcancava o icone DELE tambem, inflando um
   `plus` de 14px para 64x64 com 16px de margem embaixo. Achado pela categoria
   de auditoria `icone-fora-do-centro`, que mediu -8px de desvio vertical no
   centro do botao. So o icone grande do proprio estado vazio deve crescer.

   48px e nao 64: o dono apontou que a 64 ele fica maior que o titulo e o
   texto do bloco somados, e no card estreito do portal vira a primeira coisa
   que se ve, antes da mensagem. */
.empty-state > .icone { width: 48px; height: 48px; color: var(--gold-dark); margin-bottom: var(--esp-4); }
.empty-state h3 { color: var(--text); margin-bottom: var(--esp-2); }

/* LISTA DE ROTULO E VALOR (o bloco "Informacoes da Conta" do portal).
   Nao tinha estilo nenhum: era `<dl>/<dt>/<dd>` cru sobre o reset, e o
   resultado media 0px entre o rotulo e o proprio valor contra 11,5px ate o
   par seguinte, que e a margem padrao do <dd>. Os quatro itens liam como
   quatro coisas soltas em vez de dois pares.

   Grid de uma coluna com `row-gap` pequeno, e a separacao ENTRE pares vem da
   margem do <dt> que nao e o primeiro: assim a distancia dentro do par e
   sempre menor que a distancia entre pares, que e o que agrupa. */
.conta-dados { display: grid; row-gap: var(--esp-1); }
.conta-dados dt {
    font-size: var(--txt-rotulo);
    font-weight: var(--peso-medio);
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.conta-dados dt:not(:first-child) { margin-top: var(--esp-5); }
.conta-dados dd { margin: 0; color: var(--text); }
.empty-state p { color: var(--text-muted); margin-bottom: var(--esp-6); }

/* ── Carregando ───────────────────────────────────────────────────────────
   Sem usuário hoje: as 4 telas que mostram espera usam `fa-spinner fa-spin`
   do Font Awesome e um `id` com `style.display` no JavaScript. Fica porque é
   o único indicador de espera que não depende de CDN, e porque a alternativa
   (apagar) não devolve nada: são 2 regras e 1 animação. */
.loading { display: flex; align-items: center; justify-content: center; padding: var(--esp-10); }
.spinner { width: 40px; height: 40px; border: 3px solid var(--dark-border); border-top-color: var(--gold); border-radius: var(--raio-circulo); animation: spin 1s linear infinite; }

/* ── Dica (tooltip) ────────────────────────────────────────────────────── */
[data-tooltip] { position: relative; }
[data-tooltip]:hover::after { content: attr(data-tooltip); position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); padding: 6px var(--esp-3); background: var(--dark-lighter); border: 1px solid var(--gold-dark); border-radius: var(--raio-sm); font-size: var(--txt-mini); white-space: nowrap; z-index: var(--z-modal); color: var(--gold); }

/* ── Ações rápidas e voltar ────────────────────────────────────────────── */
.quick-actions { display: flex; gap: var(--esp-2); }

/* O FORM QUE SO ENVOLVE UM BOTAO NAO OCUPA LARGURA PROPRIA.
   Varias acoes sao POST e por isso vivem num `<form>` de um botao so. Medido
   na tela de credores a 390px: o form saia 49px para um botao de 43, e a
   sobra de 6px caia DEPOIS do botao, somando ao `gap`: o vao antes do ultimo
   botao ficava 14px contra os 8 dos outros.
   So no celular porque e la que a regra de toque (`pointer: coarse`) da
   `min-width: 40px` ao botao e a caixa do form passa a sobrar; no desktop o
   botao mede 35,8 e a caixa casa.
   `contents` e nao `flex`: com `flex` a caixa do form ainda media 49px para
   um botao de 43, porque o `gap` que ele herda do grupo se aplica dentro
   dele. Com `contents` nao ha caixa intermediaria nenhuma: o botao vira item
   direto do grupo e recebe o mesmo `gap` dos outros.
   O FORM CONTINUA FUNCIONANDO: `contents` remove a caixa de LAYOUT, nao o
   elemento. `action`, `method`, o `<input type="hidden">` e o submit do botao
   seguem iguais; o que se perde e poder dar fundo ou borda ao form, que aqui
   ninguem quer. */
.quick-actions > form,
.em-fila > form { display: contents; }

@media (max-width: 768px) {
    .quick-actions { flex-wrap: wrap; }
    /* ...MENOS dentro de tabela. La a quebra empilha os botoes e estica a
       linha (medido na lista de vendas a 390px: 61px de altura contra os ~40
       de uma linha normal), e nao resolve nada, porque a tabela ja rola na
       horizontal dentro de `.table-container`: o espaco existe, so nao estava
       sendo usado. Fora de tabela o `wrap` continua valendo, que e onde ele
       foi escrito para servir. */
    td .quick-actions { flex-wrap: nowrap; }
    .pagination { flex-wrap: wrap; }
}

.back-link { display: inline-flex; align-items: center; gap: var(--esp-2); color: var(--text-muted); text-decoration: none; font-size: var(--txt-corpo); margin-bottom: var(--esp-6); transition: color var(--dur-rapida) var(--curva); }
.back-link:hover { color: var(--gold); }

/* ── Painel "Cobrar agora" (dashboard de empréstimos) ──────────────────────
   Prefixo cobranca- porque este CSS é carregado por todas as telas do painel.
   Sem <table> de propósito: dentro de .table-container a tabela herda
   min-width de 620px e estoura no celular. Aqui as linhas quebram.
   FICA DEPOIS dos breakpoints de `.card`: o painel é `class="card cobranca"`
   e `padding: 0` só vence `@media (max-width: 768px) .card { padding: 16px }`
   por vir depois. Ver o item 2 do cabeçalho deste arquivo. */
.cobranca {
    min-width: 0;
    border-left: 4px solid var(--warning);
    background: linear-gradient(135deg, #2d2a1a 0%, #3a3218 100%);
    margin-bottom: var(--esp-6);
    padding: 0;
    overflow: hidden;
}
.cobranca.vazio {
    border-left-color: var(--secondary);
    background: var(--dark-card);
}
.cobranca-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--esp-3);
    padding: var(--esp-4) var(--esp-5);
    border-bottom: 1px solid var(--dark-border);
}
.cobranca.vazio .cobranca-head { border-bottom: none; }
.cobranca-total {
    font-size: var(--txt-titulo-g);
    font-weight: var(--peso-forte);
    /* Branco, por decisao do dono. Era `--warning`, que sobre o fundo do card
       de cobranca dava 2,54:1 de contraste; o branco ali da 9,1:1. */
    color: white;
    overflow-wrap: anywhere;
}
.cobranca-sub {
    flex: 1 1 100%;
    font-size: var(--txt-rotulo);
    color: var(--text-muted);
    line-height: 1.5;
}
.cobranca-item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--esp-3);
    padding: var(--esp-3) var(--esp-5);
    border-bottom: 1px solid var(--dark-border);
    min-width: 0;
}
.cobranca-item:last-child { border-bottom: none; }

/* NO CELULAR O ITEM COMPACTA. Medido a 390px: cada pessoa ocupava 140px, entao
   cabiam duas das 23 por tela e a lista virava rolagem. Tres mudancas, nenhuma
   tira informacao:
     - a etiqueta de prazo e o valor dividem a primeira linha, em vez de uma
       linha cada;
     - o padding vertical cai de 12 para 8px;
     - os botoes encolhem para o tamanho do conteudo e dividem a largura, em vez
       de cada um esticar.
   O alvo de toque de 44px e preservado: quem define a altura do botao e a regra
   de `pointer: coarse` em 06-interacao.css, e ela continua valendo. */
@media (max-width: 600px) {
    .cobranca-item {
        padding: var(--esp-2) var(--esp-4);
        gap: var(--esp-2);
        row-gap: var(--esp-1);
    }
    /* O NOME FICA SOZINHO NA PRIMEIRA LINHA, e o valor com a etiqueta descem
       para a linha dos detalhes, a pedido do dono.

       Antes os tres dividiam a linha de cima: a 390px o nome disputava a
       faixa com o valor e com a etiqueta e sobrava um terco da tela para
       cada. A linha de detalhes ("Parcela 1 · juros R$ 268,00") e curta e
       tinha a largura inteira sobrando ao lado.

       `display: contents` no `.cobranca-quem` e o que torna isso possivel: o
       nome e os detalhes moram DENTRO dele, e sem isso o bloco inteiro e um
       item so do grid, sem onde encaixar o valor na segunda linha. */
    .cobranca-item {
        display: grid;
        grid-template-columns: 1fr auto auto;
        align-items: center;
    }
    .cobranca-quem { display: contents; }

    /* A LINHA VAI DECLARADA, e nao e detalhe: `.status` e o PRIMEIRO filho no
       DOM, e sem `grid-row` o navegador o punha na linha 1 coluna 3. O nome,
       que pede a largura inteira, nao cabia mais ali e descia, empurrando
       tudo: a 390px cada peca terminava numa linha propria. A 600px cabia e
       parecia certo, que e como esse tipo de erro se esconde. */
    .cobranca-nome  { grid-column: 1 / -1; grid-row: 1; }
    .cobranca-det   { grid-column: 1;      grid-row: 2; }
    .cobranca-valor { grid-column: 2;      grid-row: 2; margin-left: 0; }
    .cobranca-item > .status { grid-column: 3; grid-row: 2; }

    /* Estes dois ficam em `auto` DE PROPOSITO: os dois pedem a largura
       inteira, entao caem na primeira linha livre. Linha fixa abriria uma
       faixa vazia em toda pessoa que nao tem renovacao pendente. */
    .cobranca-det.txt-alerta { grid-column: 1 / -1; grid-row: auto; }
    .cobranca-acoes { grid-column: 1 / -1; grid-row: auto; }

    /* O VALOR ENCOLHE: na linha do nome ele era o numero de maior peso do
       bloco; ao lado de um detalhe de 12px, o tamanho de corpo fica grande
       demais para o que ele e ali. */
    .cobranca-valor { font-size: var(--txt-rotulo); }

    /* A etiqueta encolhe: no celular ela divide a linha com tres botoes. */
    .cobranca-item > .status {
        font-size: var(--txt-nota);
        padding: 2px var(--esp-2);
    }

    /* Botao mais baixo. O alvo de toque de 44px vale para alvo ISOLADO; aqui
       sao tres lado a lado numa fila propria, com 8px de intervalo, e o que o
       dedo erra e a vizinhanca, nao a altura. O conteudo tambem para de
       esticar: com `flex: 1 1 auto` os tres dividiam os 362px da linha e
       ficavam com ~118px cada, bem mais do que o texto pede. */
    .cobranca-acoes .btn {
        flex: 0 1 auto;
        min-height: 36px;
        /* Padding-x menor tambem, e nao so o vertical: a etiqueta precisa caber
           na MESMA linha dos tres botoes, e faltavam 14px. Medido a 390px:
           etiqueta 107 + botoes 261 + gap 8 = 376 numa linha de 362. Com 10px
           de padding lateral os botoes somam 225 e sobra folga. */
        padding: 4px 10px;
    }
}
.cobranca-item.feito { opacity: .45; }
.cobranca-quem { flex: 1 1 220px; min-width: 0; }
.cobranca-nome { font-weight: var(--peso-medio); overflow-wrap: anywhere; }
.cobranca-det { font-size: var(--txt-mini); color: var(--text-muted); overflow-wrap: anywhere; margin-top: 2px; }
.cobranca-valor {
    font-weight: var(--peso-forte);
    white-space: nowrap;
    margin-left: auto;
}
.cobranca-acoes { display: flex; flex-wrap: wrap; gap: var(--esp-2); align-items: center; }
.cobranca-fone { color: var(--text-muted); font-size: var(--txt-rotulo); white-space: nowrap; text-decoration: none; }
.cobranca-fone:hover { color: var(--gold); }
.cobranca-pe { padding: var(--esp-3) var(--esp-5); font-size: var(--txt-rotulo); color: var(--text-muted); }
.cobranca-pe a { color: var(--gold); }

/* ── Fase 5: o que saiu de dentro de `style=` ──────────────────────────────
   Padrão com nome no domínio vira componente aqui; respiro e alinhamento
   anônimos viram utilitário em 05. */

/* Grade de cartões de número mais estreita que a padrão. A `.stats-grid` pede
   290px porque precisa caber "R$ 152.290,40" numa linha ao lado do ícone;
   onde o card é só um contador de duas casas, 240px cabe mais coluna. */
.stats-grid.estreita { grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); }

/* A legenda que vem DEPOIS do valor do cartão (24 ocorrências nas views, todas
   com `margin-top: 5px`). Os 5px ficam literais: 4px é o degrau da grade e
   encostar neles moveria os 24 lugares. */
.stat-nota { margin-top: 5px; }

/* Parágrafo de explicação dentro de um card (o aviso da ficha de outro
   operador, a nota da blacklist). */
.p-explica {
    color: var(--text-muted);
    font-size: var(--txt-rotulo);
    line-height: 1.6;
}

/* Card com a tarja dourada à esquerda, igual ao `.stat-card.gold`. */
.card-gold { border-left: 4px solid var(--gold); }

/* O aviso de CPF na blacklist na ficha do cliente. Não reusa `.alert-danger`:
   aquele é `display: flex` e tem fundo a20, e este empilha o motivo de cada
   credor embaixo do título, com fundo a15. */
.aviso-blacklist {
    background: var(--danger-a15);
    border: 1px solid var(--danger-a40);
    border-radius: var(--raio-md);
    padding: var(--esp-4) var(--esp-5);
    margin-bottom: var(--esp-5);
}
.aviso-blacklist-item {
    background: var(--preto-a20);
    border-radius: var(--raio);
    /* 10px/14px ficam literais: são "quase" 8/16 e encostar moveria a caixa. */
    padding: 10px 14px;
    font-size: var(--txt-rotulo);
    color: var(--text-muted);
}

/* As linhas do endereço na ficha. Os 6px estão fora da grade de 4px e ficam
   literais: 8px separaria as linhas mais do que hoje, e esta fase não muda
   pixel. A classe vai em cada <p> em vez de num wrapper porque envolver os
   três mudaria a árvore, e a verificação desta fase compara elemento a
   elemento por posição no documento. */
.endereco-linha { font-size: var(--txt-corpo); margin-bottom: 6px; }

/* Primeira coluna de tabela de ficha (rótulo à esquerda, valor à direita). */
.col-rotulo { width: 40%; }

/* A galeria de documentos do KYC. */
.docs-grade {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(160px, 100%), 1fr));
    gap: var(--esp-4);
    padding: var(--esp-2) 0;
}
.doc-cartao {
    background: var(--dark-lighter);
    border: 1px solid var(--dark-border);
    border-radius: var(--raio-md);
    padding: var(--esp-4);
    text-align: center;
}
/* O icone do documento centraliza por MARGEM, nao pelo `text-align: center` do
   cartao: ele e `display: block` com 48px de largura, e text-align so alinha
   conteudo inline. Medido antes: 53px a esquerda do centro.
   A regra do <img> saiu junto: o cartao nao mostra mais previa, so o icone. */
/* FILHO DIRETO: `.doc-cartao .icone` alcancava tambem o icone dentro do botao
   "Ver", que ganhava `margin-bottom` e engordava o botao de 29 para 39px. */
.doc-cartao > .icone {
    margin-inline: auto;
    margin-bottom: var(--esp-3);
}
.doc-nome {
    font-weight: var(--peso-medio);
    color: var(--gold);
    font-size: var(--txt-mini);
    margin-bottom: var(--esp-2);
}

/* ── Variante compacta do valor do cartão ──────────────────────────────────
   O valor normal usa `clamp(18px, 1.6vw + 8px, 28px)`; onde o cartão mostra
   quatro valores de carteira lado a lado, ele é travado em 20px.

   É UM ATRIBUTO, E NÃO UMA CLASSE A MAIS, de propósito:
   `scripts/testar-recuperacao.js:48` casa com `<div class="stat-value"` com a
   aspa colada no nome. Escrever `class="stat-value t-titulo-g"` deixa a tela
   certa e o teste cego, sem erro em lugar nenhum.
   A especificidade (0,2,0) também é o que mantém os 20px dentro dos
   `@media` de 768 e 480px, que é o que o `style=` fazia antes. */
.stat-value[data-compacto] { font-size: var(--txt-titulo-g); }
/* Quatro cards da janela futura acrescentam 0.5px de espaçamento entre letras
   para o valor respirar nos 20px. */
.stat-value[data-compacto="largo"] { letter-spacing: 0.5px; }

/* ── Recuperação (/elite-cred/recuperacao) ─────────────────────────────── */
/* Tarja de cor à esquerda do card, 3px. A família de 4px (.card-aviso e
   companhia) fica logo abaixo: as duas espessuras existem na tela de hoje e
   igualar moveria pixel. */
.card-faixa-fraca  { border-left: 3px solid var(--text-muted); }
.card-faixa-aviso  { border-left: 3px solid var(--warning); }
.card-faixa-perigo { border-left: 3px solid var(--danger); }
.card-faixa-gold   { border-left: 3px solid var(--gold); }

/* A caixa dourada que declara que a multa é simulação. */
.nota-simulacao {
    flex: 1 1 100%;
    /* 10px fica literal: é "quase" 8 e encostar moveria a caixa. */
    padding: 10px var(--esp-3);
    margin-top: var(--esp-1);
    border-radius: var(--raio-sm);
    background: var(--gold-a08);
    border: 1px solid var(--gold-a25);
    font-size: var(--txt-rotulo);
}
/* 6px em vez dos 8px de `.icone`: o ícone encosta mais no texto da nota. */
.nota-simulacao .icone { color: var(--gold); margin-right: 6px; }

/* A MESMA NOTA, GRITANDO, quando a janela não é a do período em aberto.
   Os cards mudam de significado conforme a janela, e quem filtra por um mês
   precisa ver que está olhando outro período. Sem isso o defeito é conhecido
   nesta família de telas: o dono escolhia "Próximo Mês" e os cards seguiam
   dizendo "Todo o período", o que lê como filtro quebrado. */
.nota-simulacao.nota-destacada {
    background: var(--warning-a08, rgba(245, 158, 11, 0.1));
    border-color: var(--warning);
    color: var(--text);
}
.nota-simulacao.nota-destacada .icone { color: var(--warning); }

/* ── MENU DE AÇÕES ──────────────────────────────────────────────────────────
   Um `<details>` e não um menu com JavaScript: ele abre, fecha no Escape e
   entra na ordem de tabulação sem uma linha de script. O que o CSS faz é tirar
   a setinha nativa do `summary` e posicionar a lista.

   A lista é `position: absolute` e o pai é `relative`, então ela não empurra o
   conteúdo ao abrir. Alinhada à DIREITA (`right: 0`) porque o botão fica no
   canto direito: alinhada à esquerda, ela sairia da tela no celular. */
.menu-acoes { position: relative; }

.menu-acoes > summary {
    list-style: none;
    cursor: pointer;
    /* O `summary` vira botão: sem isto ele é um bloco de largura total e o
       `.btn` não consegue encolher para o tamanho do texto. */
    display: inline-flex;
    align-items: center;
    gap: var(--esp-2);
}
.menu-acoes > summary::-webkit-details-marker { display: none; }
.menu-acoes > summary::marker { content: ''; }

.menu-acoes-lista {
    position: absolute;
    right: 0;
    top: calc(100% + var(--esp-2));
    min-width: 260px;
    z-index: var(--z-topbar);
    background: var(--dark-card);
    border: 1px solid var(--dark-border);
    border-radius: var(--raio-lg);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
    padding: var(--esp-2);
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.menu-acoes-item {
    display: flex;
    align-items: center;
    gap: var(--esp-2);
    width: 100%;
    text-align: left;
    background: none;
    border: 0;
    color: var(--text);
    font-size: var(--txt-corpo);
    padding: var(--esp-3);
    border-radius: var(--raio-sm);
    cursor: pointer;
    text-decoration: none;
}
.menu-acoes-item:hover { background: var(--gold-a08); color: var(--gold); }
.menu-acoes-item > .icone { margin-right: 0; flex: 0 0 auto; }

/* No celular a lista ocupa a largura toda da tela menos a margem, em vez de
   um menu estreito encostado na borda. */
@media (max-width: 480px) {
    .menu-acoes-lista {
        min-width: 0;
        width: calc(100vw - var(--esp-6) * 2);
        max-width: 320px;
    }
}

/* Campo numérico curto (multa por dia, teto). */
.campo-curto { max-width: 130px; }

/* A régua de botões de faixa e ordem, dentro de um card sem padding próprio. */
/* O ENDERECO QUEBRA, ao contrario das outras celulas. Medido na recuperacao:
   546px de uma tabela de 1821, 30% da largura, empurrando sete colunas de
   dinheiro para fora da tela. E o unico dado da tabela que e um texto corrido,
   e os outros (nome, telefone, valores) precisam do nowrap para nao empilhar.
   O teto em ch e proporcional a fonte, nao a tela. */
/* O SELETOR CARREGA `.table-container td` para vencer na especificidade. Com
   `.recup-col-endereco` sozinho (0,1,0) a regra perdia para
   `.table-container td { white-space: nowrap }` (0,2,0), o nowrap continuava
   valendo e o texto ESTOURAVA a celula: medido, 454px de conteudo numa celula
   de 200, vazando 254px por cima das colunas de Atraso e Atrasado. */
.table-container td.recup-col-endereco {
    white-space: normal;
    max-width: 26ch;
    overflow-wrap: anywhere;
}

.barra-filtros {
    /* Padding vertical menor que o horizontal: a barra e uma FILA DE BOTOES,
       nao um bloco de conteudo, e os botoes ja trazem 10px de altura propria.
       Eram 16px em cima e embaixo, o que somava 32px de folga em volta de
       elementos de 34px: mais espaco vazio que barra. */
    padding: var(--esp-2) var(--esp-5);
    display: flex;
    gap: var(--esp-2);
    flex-wrap: wrap;
    align-items: center;
}

/* DENTRO DE UM CARD a barra nao traz padding horizontal proprio: o card ja da o
   dele, e os dois somavam. Medido: 24px do card mais 20px da barra, 45px antes
   do primeiro botao, numa barra cujos itens tem 34px de altura. */
.card > .barra-filtros {
    padding-left: 0;
    padding-right: 0;
}
.barra-filtros .rotulo {
    color: var(--text-muted);
    font-size: var(--txt-rotulo);
    margin-right: var(--esp-1);
}
.barra-filtros .rotulo.depois { margin-left: var(--esp-4); }

/* O parágrafo que explica a diferença entre "Atrasado" e as colunas de
   quitação, encaixado entre o cabeçalho do card e a tabela. */
.nota-tabela {
    padding: 0 var(--esp-5) var(--esp-3);
    font-size: var(--txt-rotulo);
    color: var(--text-muted);
}

/* As duas colunas da tabela que não podem espremer. */
.recup-col-cliente  { min-width: 190px; }
.recup-col-endereco { min-width: 200px; }
/* "R$ 1.000,00 a 40%" embaixo do telefone. Os 3px são ajuste óptico, não
   espaçamento: ver o cabeçalho de 01-tokens.css. */
.recup-taxa {
    font-size: var(--txt-nota);
    color: var(--text-muted);
    margin-top: 3px;
}
.recup-fone2 { opacity: 0.8; }

/* ── Blacklist (/elite-cred/blacklist) ─────────────────────────────────── */
/* Card com tarja de cor à esquerda. O ícone do título precisa do seletor
   descendente: `.card-title .icone` já pinta de dourado com especificidade
   (0,2,0), e uma classe solta no <svg> perderia a disputa em silêncio. */
.card-aviso  { border-left: 4px solid var(--warning); }
.card-aviso  .card-title .icone { color: var(--warning); }
.card-perigo { border-left: 4px solid var(--danger); }
.card-perigo .card-title .icone { color: var(--danger); }

/* O formulário de inclusão: grade de campos curtos, encostados pela base para
   o botão alinhar com os inputs e não com os rótulos. */
.form-grade {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr));
    gap: var(--esp-4);
    align-items: flex-end;
}

/* O quadro amarelo-claro que explica o que a blacklist faz. É a única peça
   clara do painel escuro, e as duas cores não saem de token nenhum: `--warning-bg`
   nunca existiu, então o que está no ar é o fallback `#fff3cd`, e o texto é o
   `#856404` que acompanha. Ficam literais porque são o que a tela mostra. */
/* Era `background: #fff3cd` com texto `#856404`, as cores de alerta do tema
   CLARO do Bootstrap, num sistema que e dark-only: o bloco virava uma mancha
   creme no meio de uma tela preta. Agora segue o padrao dos outros avisos,
   fundo translucido da propria cor de alerta sobre o escuro. */
.card-lgpd {
    margin-top: var(--esp-6);
    background: var(--warning-a15);
    border-left: 4px solid var(--warning);
}
.card-lgpd h3 {
    margin: 0 0 var(--esp-2) 0;
    color: var(--warning);
    font-size: var(--txt-destaque);
}
.card-lgpd p {
    margin: 0;
    color: var(--text);
    font-size: var(--txt-corpo);
    line-height: 1.6;
}

/* O modal de edição. Desde 08/10/2026 o elemento é `class="modal-overlay
   modal-bl"`: toda a visibilidade (o `display`, a transição e o
   `@starting-style`) vem do bloco Modal lá em cima, e o que sobra aqui é só
   o que ESTE modal tem de diferente, o fundo mais claro e o painel de 560px
   em vez de 500px. Antes ele abria por `style.display` inline, que vence
   qualquer regra de folha e deixava a animação sem efeito.
   As duas regras valem porque vêm DEPOIS de `.modal-overlay` no arquivo: a
   especificidade é a mesma (0,1,0) e empate quem resolve é a ordem. */
.modal-bl {
    background: var(--preto-a70);
}
.modal-bl-painel {
    /* O MESMO FUNDO DO `.modal` COMUM. Era `#1A1A2E`, um azul-marinho num
       sistema preto e dourado, e o proprio comentario daqui ja dizia que ele
       era o fallback de um `--bg-card` que nunca existiu. Fallback de token
       inexistente nao da erro: a tela usa a cor de fora e, lendo o codigo,
       parece que ha um token por tras. */
    background: var(--dark-card);
    border: 1px solid var(--dark-border);
    border-radius: var(--raio-md);
    padding: var(--esp-8);
    width: 100%;
    max-width: 560px;
    margin: var(--esp-5);
    max-height: 90vh;
    overflow-y: auto;
}
.botao-fechar {
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    font-size: var(--txt-titulo-g);
    padding: var(--esp-1) var(--esp-2);
}

/* RECUPERACAO: o contato (icone do WhatsApp + telefone).
   O vao e UM valor declarado aqui. Antes os dois links ficavam soltos lado a
   lado e o espaco entre eles somava 23,4px de tres origens: a `margin-right`
   que a classe `.icone` carrega, o espaco em branco entre as tags no HTML e a
   folga do `inline-flex` do link. A margem do icone e zerada porque dentro de
   um contêiner com `gap` ela so duplica a separacao, que e o mesmo motivo da
   lista de `05-utilitarios.css`. */
.recup-contato {
    display: inline-flex;
    align-items: center;
    gap: var(--esp-2);
}
.recup-contato > .txt-ok > .icone { margin-right: 0; }

/* O ALVO DE TOQUE CRESCE SEM OCUPAR LARGURA.
   Medido a 390px: o link do WhatsApp saia 44x44 com um icone de 12px dentro.
   Os 44 vem da regra de `pointer: coarse` (06-interacao) e estao certos, o
   dedo precisa deles; o que estava errado e eles ocuparem LARGURA, deixando
   16px de folga de cada lado do icone mais os 8 do gap, com o telefone
   nascendo a 24px.
   Com o alvo num pseudo-elemento posicionado, que nao entra no fluxo, o link
   volta a medir o icone e o dedo continua com a area inteira. */
.recup-contato > .txt-ok {
    position: relative;
    min-width: 0;
    min-height: 0;
    display: inline-flex;
    align-items: center;
}
.recup-contato > .txt-ok::after {
    content: '';
    position: absolute;
    /* Metade da diferenca entre os 44px do alvo e os 12 do icone. */
    inset: -16px;
}

/* No celular a linha encolhe. Eram 105px de altura para tres linhas de texto,
   e esta e a tela que se percorre atras de quem ligar: cada linha alta e um
   nome a menos por tela. */
@media (max-width: 768px) {
    .recup-tabela td { padding-top: var(--esp-2); padding-bottom: var(--esp-2); }
}

/* ── Detalhe do empréstimo (/elite-cred/loans/:id) ─────────────────────── */
/* Badge de status maior, na barra do topo, onde ele é o título do estado do
   contrato e não uma etiqueta de linha de tabela. */
.status.grande { padding: var(--esp-2) var(--esp-4); font-size: var(--txt-corpo); }
.avatar.grande { width: 48px; height: 48px; font-size: var(--txt-titulo); }

/* "3/7" em tamanho de cartaz. 48px é ornamento e fica literal, pelo motivo do
   cabeçalho de 01-tokens.css. */
.contador-parcelas { font-size: 48px; font-weight: var(--peso-max); color: var(--gold); }

/* Corpo que encosta nas bordas do card porque o card já tem padding próprio:
   o que falta é só o recuo lateral e o pé. */
.card-corpo { padding: 0 var(--esp-5) var(--esp-5); }
.renov-grade {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(160px, 100%), 1fr));
    gap: var(--esp-4);
    margin-bottom: var(--esp-4);
}
/* A barra que enche conforme o cliente paga. A LARGURA continua inline porque
   é dado, não estilo: ela vem do percentual calculado no controller. */
.barra-progresso {
    height: 8px;
    background: #1a1a1a;
    border-radius: var(--raio-xs);
    overflow: hidden;
    margin-bottom: var(--esp-3);
}
.barra-progresso-cheia { height: 100%; background: var(--secondary); }

/* O resumo do modal de renovação. Os 6px entre as linhas ficam literais: são
   "quase" 4 e "quase" 8, e encostar moveria as cinco linhas. */
.renov-resumo {
    background: var(--dark-lighter);
    border: 1px solid var(--dark-border);
    border-radius: var(--raio-sm);
    padding: var(--esp-3);
    margin-bottom: var(--esp-4);
}
/* `.renov-linha` NÃO declara `display` de propósito: a linha "Já recebido"
   nasce com `style="display:none"` e o JavaScript a liga escrevendo
   `style.display = 'flex'`. Sem display na classe, o inline não disputa nada
   com ela, e some a chance de a regra nova parar de pegar sem erro. */
.renov-linha { justify-content: space-between; margin-bottom: 6px; }
.renov-linha.topo { border-top: 1px solid var(--dark-border); padding-top: 6px; }
.renov-linha.ultima { margin-bottom: 0; }
.renov-resultado {
    font-size: var(--txt-rotulo);
    color: var(--text-muted);
    padding: 10px var(--esp-3);
    background: var(--gold-a08);
    border-radius: var(--raio-sm);
}

/* Etiqueta de referência do pagamento avulso (a parcela que ele quitou). */
.etiqueta {
    color: white;
    padding: var(--esp-1) var(--esp-2);
    border-radius: var(--raio-xs);
    font-size: var(--txt-mini);
}
/* Texto escuro, nao o branco da classe base: sobre este amarelo o branco da
   2,15:1 e o escuro da 9,22:1. A .etiqueta-neutra fica com o branco, que ali
   esta correto. */
.etiqueta-aviso  { background: var(--warning); color: var(--dark); }
.etiqueta-neutra { background: rgb(var(--neutro-rgb)); }

/* Campo só de leitura que mostra um total calculado pelo próprio formulário. */
.campo-calculado {
    background: var(--dark-border);
    font-weight: var(--peso-medio);
    color: var(--gold);
}

/* ── Sócios (/elite-cred/socios) ───────────────────────────────────────── */
/* Caixa de aviso vermelha, irmã da `.nota-simulacao` dourada. Sem `font-size`
   nem `margin-top`: aqui o tamanho vem do <span> de dentro. */
.nota-perigo {
    padding: 10px var(--esp-3);
    border-radius: var(--raio-sm);
    background: var(--danger-a08);
    border: 1px solid var(--danger-a30);
}
/* Rótulo de caixa de seleção: o texto alinha pelo topo porque são 4 linhas ao
   lado de uma caixinha. Os 10px e os 3px ficam literais (respiro "quase" 8 e
   ajuste óptico de 3px), pelo motivo do cabeçalho de 01-tokens.css. */
.rotulo-check { display: flex; gap: 10px; align-items: flex-start; cursor: pointer; }
.check-alinhado { margin-top: 3px; }

/* Bloco separado por um fio dentro do mesmo formulário. */
.secao-separada {
    border-top: 1px solid var(--dark-border);
    margin-top: var(--esp-1);
    padding-top: var(--esp-3);
}

/* Nota de rodapé do card, fora da tabela. */
.nota-rodape {
    padding: var(--esp-3) var(--esp-5);
    font-size: var(--txt-rotulo);
    color: var(--text-muted);
}
.nota-pe {
    color: var(--text-muted);
    font-size: var(--txt-rotulo);
    margin: var(--esp-4) var(--esp-5);
}
/* A mesma nota da tabela, com o pé mais curto. */
.nota-tabela.curta { padding-bottom: var(--esp-2); }

/* Linhas de tabela que marcam soma e separação.

   O SELETOR CARREGA `.table-container` DE PROPÓSITO, e isto não é zelo: dentro
   do `@media (max-width: 600px)` deste mesmo arquivo existe
   `.table-container tr { border: var(--cartao-tr-borda, 0) }`, com
   especificidade (0,1,1). Uma classe solta (0,1,0) perde para ele, e o fio do
   total some NO CELULAR e só lá. Enquanto a regra morava num `style=` ela
   ganhava por ser inline, e foi assim que o fio sobreviveu até agora.
   Medido ao converter: a linha "Total repartido" encolhia 1px (o fio de 2px
   colapsado vale 1px de cada lado) e a página inteira descia junto. */
.table-container tr.linha-total { border-top: 2px solid var(--dark-border); }
.table-container tr.linha-sep   { border-top: 1px solid var(--dark-border); }
/* Destino desativado: continua na tabela porque o acumulado dele é fato. */
tr.inativo { opacity: .55; }
/* Recuo das linhas da ladeira de conferência. Os 44px estão fora da grade e
   ficam literais: são o recuo do recuo, e 40px juntaria as duas ladeiras. */
.recuo-1 { padding-left: var(--esp-6); }
.recuo-2 { padding-left: 44px; }

/* Badge menor. A irma `.colado` (margin-left: 6px) saiu: afastar a pastilha
   do texto anterior e espacamento comum, e ja ha a escada `.ml-*` para isso.
   Classe de caso particular com valor proprio e como nascem duas respostas
   para a mesma pergunta. */
.status.mini   { font-size: 10px; }

/* Larguras de campo. Os quatro valores são os que estão no ar; unificá-los é
   trabalho de uma fase que possa mover pixel, e esta não pode. */
.campo-120 { max-width: 120px; }
.campo-140 { max-width: 140px; }
.campo-150 { max-width: 150px; }
/* `color-scheme: dark` não é enfeite: sem ele o navegador desenha o seletor
   nativo em tema claro, o ícone do calendário fica preto no fundo preto e o
   campo PARECE não ser editável. O cliente já fechou um período na data errada
   por causa disso. */
.campo-data-hora { color-scheme: dark; min-width: 220px; }

/* O modal de pagamento a sócio. Mesma história do modal da blacklist: o
   elemento é `class="modal-overlay modal-pg"` e a visibilidade inteira vem
   do bloco Modal. Aqui fica só o fundo mais claro e o respiro lateral, que o
   `.modal-overlay` não tem porque o `.modal` dele já traz margem própria. */
.modal-pg {
    background: var(--preto-a70);
    padding: var(--esp-4);
}
.modal-pg-painel { max-width: 420px; width: 100%; margin: 0; }

/* ── Dashboard de empréstimos (/elite-cred/loans) ──────────────────────── */
/* A faixa do acerto da banca, no topo da dashboard de quem opera com capital
   da empresa. */
.faixa-acerto { display: flex; flex-wrap: wrap; gap: var(--esp-6); align-items: center; justify-content: space-between; }
/* 28px fora da grade: é o respiro entre os três números do acerto, e 32px
   quebraria a linha mais cedo numa tela de 1366. Fica literal. */
.faixa-numeros { display: flex; gap: 28px; flex-wrap: wrap; }
.faixa-rotulo  { color: var(--text-muted); font-size: var(--txt-mini); }
.faixa-valor   { font-size: var(--txt-titulo); font-weight: var(--peso-forte); white-space: nowrap; }

/* Cartão de número em estado de atraso: fundo avermelhado próprio, mais forte
   que o `.stat-card.danger` da lista. O `.stat-icon` precisa dos três níveis
   de classe para vencer `.stat-card.danger .stat-icon` (0,2,0). */
.stat-card.atrasado {
    background: linear-gradient(135deg, #2d1a1a 0%, #3a1a1a 100%);
    border-left-color: var(--danger);
}
.stat-card.atrasado .stat-icon { background: var(--danger-a10); }
/* O --danger-a90 (vermelho a 90%) dava 3,63:1 sobre o fundo do card vermelho.
   O --danger-texto da 5,59:1 e dispensa a transparencia. */
.rotulo-atrasado { color: var(--danger-texto); }

/* Contagem ao lado do título do card (atrasadas, vencendo). */
/* Sem `color`: a etiqueta herda o texto da página (#E5E5E5). Declarar
   `white` aqui clareava os dois badges, que é mudança de pixel. */
.badge-conta {
    font-size: var(--txt-corpo);
    padding: var(--esp-1) 10px;
    border-radius: 100px;
}
/* Texto escuro nos dois: sobre o vermelho o claro dava 2,99:1 e sobre o
   amarelo 1,70:1, que era o pior par de todo o sistema. Escuro da 5,26:1 e
   9,22:1. */
.badge-conta.perigo { background-color: var(--danger);  color: var(--dark); }
.badge-conta.aviso  { background-color: var(--warning); color: var(--dark); }

/* A grade dos campos de filtro. Não reusa `.form-row`: aquela tem gap de 20px
   e esta tem 16px, e os 10px do pé estão fora da grade. */
.filtros-grade {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
    gap: var(--esp-4);
    margin-bottom: 10px;
}
.rodape-contagem { margin-bottom: 10px; }

/* O seletor de meses do histórico, dentro do cabeçalho clicável do card. */
.select-periodo {
    background: var(--dark-lighter);
    border: 1px solid var(--dark-border);
    color: var(--text);
    border-radius: var(--raio);
    padding: 6px var(--esp-3);
    font-size: var(--txt-rotulo);
    cursor: pointer;
}

/* Ícone grande de estado vazio e de espera. 48px e 32px são ornamento e ficam
   literais, pelo motivo do cabeçalho de 01-tokens.css. */
.icone-g { font-size: 48px; margin-bottom: var(--esp-3); }
.icone-m { font-size: 32px; margin-bottom: var(--esp-3); }
/* A caixa do gráfico do histórico. Sem `display`: o `style="display: none"` do
   estado inicial continua inline porque quem liga o bloco é o JavaScript. */
.grafico-caixa { position: relative; height: 320px; }
/* A seta de variação do histórico mensal, montada pelo JavaScript. O verde é
   #22c55e e NÃO é `--secondary` (#10B981): são dois verdes diferentes no mesmo
   sistema. Esta fase não pode igualá-los (mudaria a cor na tela), mas o lugar
   do segundo verde é aqui, à vista de quem for podar a paleta, e não escondido
   dentro de um template string. */
.var-sobe  { color: #22c55e; }
.var-desce { color: var(--danger); }

/* ── Cor do ícone no título de um card ─────────────────────────────────────
   `.card-title .icone` pinta o ícone de dourado com especificidade (0,2,0).
   Uma classe de cor solta no <svg> tem (0,1,0) e PERDE, sem erro nenhum: a
   tela abre, o ícone fica dourado e ninguém sabe por quê. Era por isso que as
   views escreviam a cor dentro de `estilo:`, que ganhava por ser inline.
   Estas quatro linhas devolvem a disputa para a classe, que é o que quem
   escreve `classe: 'txt-erro'` espera que aconteça. */
.card-title .icone.txt-erro   { color: var(--danger); }
.card-title .icone.txt-alerta { color: var(--warning); }
.card-title .icone.txt-ok     { color: var(--secondary); }
.card-title .icone.txt-fraco  { color: var(--text-muted); }

/* ── Caixa de aviso ────────────────────────────────────────────────────────
   Substitui o `alert()` do navegador (ver public/js/aviso.js).

   Fica no topo porque embaixo está a barra de navegação do celular
   (--z-barra-inf), e um aviso que cobre o menu é pior que o problema que
   resolve. Acima do modal de propósito: várias ações confirmam dentro de um
   modal, e o resultado precisa aparecer por cima dele.

   `position: fixed` com `pointer-events: none` no recipiente e `auto` em cada
   aviso: assim a faixa vazia no topo da tela não rouba clique de nada. */
.avisos {
    position: fixed;
    top: var(--esp-4);
    left: 50%;
    transform: translateX(-50%);
    z-index: calc(var(--z-modal) + 10);
    display: flex;
    flex-direction: column;
    gap: var(--esp-2);
    width: min(440px, calc(100vw - var(--esp-8)));
    pointer-events: none;
}

.aviso {
    pointer-events: auto;
    display: flex;
    align-items: flex-start;
    gap: var(--esp-3);
    padding: var(--esp-3) var(--esp-4);
    border-radius: var(--raio-lg);
    background: var(--dark-card);
    border: 1px solid var(--dark-border);
    /* A faixa colorida à esquerda é o que dá o tipo num relance, no lugar do
       "✅"/"❌" que cinco chamadas carregavam dentro do texto. */
    border-left: 3px solid var(--text-muted);
    box-shadow: 0 10px 30px rgba(0, 0, 0, .55);
    color: var(--text-light, #E5E5E5);
    font-size: var(--txt-corpo);
    line-height: 1.45;
    /* Mensagem de erro do servidor pode vir com identificador longo e sem
       espaço, que de outro modo estica a caixa. */
    overflow-wrap: anywhere;
    min-width: 0;
}

.aviso > span { flex: 1; min-width: 0; }

.aviso > .icone {
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    /* Alinha com a primeira linha do texto, não com o bloco inteiro: numa
       mensagem de três linhas o ícone centralizado fica solto no meio. */
    margin-top: 2px;
}

.aviso-ok   { border-left-color: var(--success); }
.aviso-erro { border-left-color: var(--danger); }
.aviso-info { border-left-color: var(--gold); }

.aviso-ok   > .icone { color: var(--success); }
.aviso-erro > .icone { color: var(--danger); }
.aviso-info > .icone { color: var(--gold); }

.aviso-fechar {
    flex-shrink: 0;
    background: none;
    border: 0;
    color: var(--text-muted);
    font-size: 20px;
    line-height: 1;
    padding: 0 var(--esp-1);
    cursor: pointer;
    transition: color var(--dur-rapida) ease;
}

.aviso-fechar:hover { color: white; }
