/* ==========================================================================
   Fluxo de Caixa — Design System (tokens.css) — v2 (com tema claro/escuro)
   --------------------------------------------------------------------------
   Origem dos tokens:
   - ESTRUTURA (raio, elevação, sombra, motion, tipografia, componentes):
     hub.asimov.academy (Tailwind v4 compilado) — sem cor de marca deles.
   - CORES: extraídas do site real de um cliente-piloto (inspecionado
     logado/via CSS computado):
       · Ink (preto quase puro) #1e1f20 — cor de texto/logo/botão "COMPRAR" do site.
       · Branco — fundo do site.
       · Vermelho #f13131 — cor FIXA usada nas etiquetas de desconto
         (`.tag-offer-bg`) em toda a loja. É a única cor saturada e consistente
         da marca (o amarelo/laranja do banner da home é arte de campanha
         sazonal — não é token de marca, por isso não entrou aqui).
     Verde/roxo/ciano/âmbar continuam os do Fluxo de Caixa original — o cliente-piloto
     não tem essas cores na identidade, então não havia o que "pegar" pra
     elas; ficam
     mantidas por precisar de mais de 2 cores pra diferenciar categoria/gráfico.
   - TEMA: --ink é reativo ao tema (preto no claro, quase-branco no escuro) —
     é a tradução correta de uma marca "preto & branco" pra um app com dois
     temas (preto/branco sozinhos não funcionam como "accent" em tema escuro).
     --red é FIXO nos dois temas (funciona em cima de claro ou escuro) e fica
     reservado pra despesa/perigo/alerta — nunca pra ação primária neutra,
     pra não confundir "botão" com "número de despesa".
   Ver docs/design-system/DESIGN_SYSTEM.md para o detalhamento.
   ========================================================================== */

:root, :root[data-theme="dark"] {
  /* preto neutro de verdade (sem tom azulado) — coerente com o preto/branco do
     cliente-piloto; não é mais o navy #0a0e1a do Fluxo de Caixa original */
  --bg: #000000;
  --bg-2: #0a0a0a;
  --surface-1: #121212;
  --surface-2: #0d0d0d;
  --border-1: #232323;
  --border-2: rgba(255, 255, 255, .06);

  --text-100: #f4f4f5;
  --text-200: #a1a1aa;
  --text-mute: #71717a;

  --ink: #f4f4f5;              /* accent primário no escuro: quase-branco */
  --ink-contrast: #14161a;     /* texto em cima de botão --ink */

  --overlay-1: rgba(255, 255, 255, .04);
  --overlay-2: rgba(255, 255, 255, .05);
  --overlay-3: rgba(255, 255, 255, .08);
  --line-soft: rgba(255, 255, 255, .10);
  --line-strong: rgba(255, 255, 255, .22);

  --shadow-card: inset 0 1px 0 rgba(255, 255, 255, .05), 0 14px 36px -20px rgba(0, 0, 0, .55);
  --shadow-card-hover: inset 0 1px 0 rgba(255, 255, 255, .08), 0 22px 48px -18px rgba(0, 0, 0, .62);
  --shadow-sm: 0 4px 12px rgba(0, 0, 0, .30);
  --shadow-md: 0 8px 24px rgba(0, 0, 0, .40);

  --ring: 0 0 0 2px rgba(244, 244, 245, .35);
  /* Hover "mais visual" da sidebar (17/08/2026) — no escuro é luz de fundo
     (glow), nunca sombra (invisível em fundo já preto). Regra do projeto:
     todo efeito de cor/luz inverte entre os dois temas, nunca usa o mesmo
     valor cru nos dois (ver memória "fluxo-caixa-tema-claro-escuro"). */
  --nav-hover-fx: 0 0 22px 3px rgba(244, 244, 245, .14);
}

:root[data-theme="light"] {
  --bg: #ffffff;
  --bg-2: #f7f7f7;
  --surface-1: #ffffff;
  --surface-2: #f5f5f6;
  --border-1: #e1e1e1;         /* borda real do site do cliente-piloto */
  --border-2: rgba(0, 0, 0, .06);

  --text-100: #1e1f20;         /* ink real do cliente-piloto */
  --text-200: #55575c;
  --text-mute: #8a8d93;

  --ink: #1e1f20;              /* accent primário no claro: preto do cliente-piloto */
  --ink-contrast: #ffffff;

  --overlay-1: rgba(0, 0, 0, .03);
  --overlay-2: rgba(0, 0, 0, .05);
  --overlay-3: rgba(0, 0, 0, .08);
  --line-soft: rgba(0, 0, 0, .08);
  --line-strong: rgba(0, 0, 0, .18);

  --shadow-card: inset 0 1px 0 rgba(255, 255, 255, .7), 0 10px 24px -16px rgba(0, 0, 0, .16);
  --shadow-card-hover: inset 0 1px 0 rgba(255, 255, 255, .8), 0 16px 32px -14px rgba(0, 0, 0, .20);
  --shadow-sm: 0 2px 8px rgba(0, 0, 0, .06);
  --shadow-md: 0 6px 16px rgba(0, 0, 0, .08);

  --ring: 0 0 0 2px rgba(30, 31, 32, .22);
  /* Par do --nav-hover-fx do tema escuro: no claro é sombra/elevação, nunca
     glow (luz sobre fundo branco não se vê). Mesma regra, efeito invertido. */
  --nav-hover-fx: 0 10px 22px -6px rgba(30, 31, 32, .24);
}

:root {
  /* ── Cores fixas (não mudam com o tema) ─────────────────────────────── */
  --red: #f13131; --red-rgb: 241, 49, 49;         /* cliente-piloto — etiqueta de desconto */
  --green: #10b981; --green-rgb: 16, 185, 129;    /* Fluxo de Caixa — não existe no cliente-piloto */
  --purple: #8b5cf6; --purple-rgb: 139, 92, 246;  /* Fluxo de Caixa — não existe no cliente-piloto */
  --cyan: #06b6d4; --cyan-rgb: 6, 182, 212;       /* Fluxo de Caixa — não existe no cliente-piloto */
  --amber: #f59e0b; --amber-rgb: 245, 158, 11;    /* Fluxo de Caixa — não existe no cliente-piloto */
  --blue: #3b82f6; --blue-rgb: 59, 130, 246;      /* mantida p/ compat. (gráficos) */

  /* Semântica financeira (fixa — não muda por tela nem por tema) */
  --receita: var(--green);
  --despesa: var(--red);
  --pendente: var(--amber);
  --neutro: var(--cyan);

  /* ── Raio — hub.asimov.academy ───────────────────────────────────────── */
  --radius-xs: 3px; --radius-sm: 6px; --radius-md: 12px; --radius-lg: 16px;
  --radius-xl: 20px; --radius-2xl: 24px; --radius-pill: 9999px;
  --radius-btn: var(--radius-md);

  /* ── Motion — hub.asimov.academy ────────────────────────────────────── */
  --ease-pop: cubic-bezier(.16, 1, .3, 1);
  --ease-standard: cubic-bezier(.4, 0, .2, 1);
  --dur-fast: .15s; --dur-base: .25s; --dur-slow: .45s;

  /* ── Tipografia ──────────────────────────────────────────────────────── */
  --font-sans: 'Inter', ui-sans-serif, system-ui, sans-serif;
  --text-xs: .75rem; --text-sm: .875rem; --text-base: 1rem;
  --text-lg: 1.125rem; --text-xl: 1.25rem; --text-2xl: 1.5rem; --text-3xl: 1.875rem;

  --nxsw: 240px; --nxhh: 60px; --nxsw-collapsed: 68px;
}

* { box-sizing: border-box; }
html { transition: background var(--dur-base) ease; }
html, body { margin: 0; background: var(--bg); color: var(--text-100); font-family: var(--font-sans); }
body, .card, .btn, .input, .navlink { transition: background var(--dur-base) ease, color var(--dur-base) ease, border-color var(--dur-base) ease; }

/* ==========================================================================
   Botões
   ========================================================================== */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  height: 2.5rem; padding: 0 1.5rem; border: 0; border-radius: var(--radius-btn);
  font: 600 var(--text-sm) var(--font-sans); cursor: pointer; white-space: nowrap;
  text-decoration: none; transition: all var(--dur-base) var(--ease-pop);
}
.btn:focus-visible { outline: none; box-shadow: var(--ring); }
.btn--sm { height: 2rem; padding: 0 1rem; font-size: 13px; }
.btn--lg { padding: 0 2rem; }

/* primário = --ink (preto no claro / quase-branco no escuro) — o mesmo
   padrão do botão "COMPRAR" do cliente-piloto, adaptado pros dois temas */
.btn--primary { color: var(--ink-contrast); background: var(--ink); }
.btn--primary:hover { filter: brightness(1.1); transform: translateY(-1px); }

.btn--secondary { color: var(--text-100); background: var(--overlay-2); border: 1px solid var(--line-soft); }
.btn--secondary:hover { background: var(--overlay-3); }

.btn--soft { color: var(--text-100); background: var(--overlay-1); border: 1px solid var(--border-1); height: 2rem; padding: 0 1rem; font-size: 13px; }
.btn--soft:hover { background: var(--overlay-2); }

.btn--ghost { color: var(--text-200); background: transparent; }
.btn--ghost:hover { background: var(--overlay-1); color: var(--text-100); }

.btn--danger { color: #fff; background: linear-gradient(135deg, #b91c1c, var(--red)); box-shadow: 0 0 18px rgba(var(--red-rgb), .28); }
.btn--success { color: #fff; background: linear-gradient(135deg, #0d9668, var(--green)); box-shadow: 0 0 18px rgba(var(--green-rgb), .28); }

/* ==========================================================================
   Cards
   ========================================================================== */
.card {
  position: relative; border-radius: var(--radius-md);
  background: var(--surface-1); border: 1px solid var(--overlay-3);
  box-shadow: var(--shadow-card); padding: 16px;
  transition: transform var(--dur-slow) var(--ease-standard), box-shadow var(--dur-slow) var(--ease-standard), border-color var(--dur-slow) var(--ease-standard);
}
.card--interactive:hover { transform: translateY(-4px); border-color: var(--line-strong); box-shadow: var(--shadow-card-hover); }
.card:focus-visible { outline: none; box-shadow: var(--shadow-card), var(--ring); }

/* .kpi-grid existia só no <style> do mockup (nunca tinha ido pro tokens.css real) —
   mesma lacuna já encontrada com .shell (Etapa 2) e .filters-row (Etapa 3), fechada
   do mesmo jeito, nos dois arquivos de tokens.css. */
/* minmax(0, 1fr), não só 1fr (achado na auditoria de responsividade,
   17/08/2026): sem o `0`, o mínimo de cada trilha é o min-content do valor
   (ex.: "R$ 164.151,55" sem quebra) — um número grande força a trilha a
   crescer além da fração combinada, e a página estoura a largura. */
.kpi-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; margin-bottom: 20px; }
@media (max-width: 1000px) { .kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 480px) { .kpi-grid { grid-template-columns: minmax(0, 1fr); } }

/* Dashboard como hub (17/08/2026) — cards de entrada pros sub-dashboards
   (Fluxo de Caixa, Cartão Paludo, e o que mais entrar depois). 2 lado a
   lado por padrão; a grade já comporta uma 3ª/4ª entrada sem mudar nada
   aqui, só acrescentando outro `_card_dashboard(...)` em app/paginas.py.

   O card Fluxo de Caixa usa um gráfico pequeno DE VERDADE como prévia
   (dashboard-hub.js, dado real de `evolucao_mensal`) — não uma imagem
   estática: sempre reflete o dado atual, sem precisar recapturar nada
   quando o dashboard mudar. Cartão Paludo fica só com ícone/gradiente — os
   dados dele vêm de outro projeto (INDICADORES CRED), sem schema estável
   daqui pra depender. */
.hub-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
@media (max-width: 720px) { .hub-grid { grid-template-columns: 1fr; } }
.hub-card {
  display: block; text-decoration: none; color: inherit;
  border: 1px solid var(--border-1); border-radius: var(--radius-lg); overflow: hidden;
  background: var(--surface-1);
  transition: transform var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}
.hub-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); }
.hub-card-visual {
  height: 140px; display: flex; align-items: center; justify-content: center;
  font-size: 48px; position: relative; overflow: hidden;
}
.hub-card-visual--caixa { background: linear-gradient(135deg, rgba(var(--green-rgb), .08), rgba(var(--green-rgb), .01)); }
.hub-card-visual--caixa canvas { width: 100% !important; height: 100% !important; }
.hub-card-visual--cred { background: linear-gradient(135deg, rgba(var(--red-rgb), .18), rgba(var(--red-rgb), .02)); color: var(--red); }
.hub-card-corpo { padding: 16px 18px 20px; }
.hub-card-titulo { margin: 0 0 4px; font-size: 15px; font-weight: 600; color: var(--text-100); }
.hub-card-desc { margin: 0; font-size: 12.5px; color: var(--text-mute); }

/* Home — recepção pós-login (19/08/2026), separada do hub acima. Cartão de
   saudação em vidro fosco — mesmo tratamento de .auth-card (blur sobre
   overlay), só mais discreto (blur menor, padding menor): aqui é um
   elemento recorrente de toda entrada no sistema, não um momento único
   como o login. */
.home-recepcao {
  background: var(--overlay-2);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  border: 1px solid var(--border-1); border-radius: var(--radius-md);
  padding: 24px;
}
.home-recepcao h2 { margin: 0 0 4px; }
.home-recepcao p { margin: 0; }
.link-discreto { font-size: 13px; color: var(--text-mute); text-decoration: none; }
.link-discreto:hover { color: var(--text-100); text-decoration: underline; }

/* Seção Administração dentro de Configurações (17/08/2026) — Contas
   bancárias/Usuários/Dispositivos/Auditoria saíram da sidebar, viraram
   links aqui. Lista simples (ícone + rótulo), não card com prévia — são
   atalhos de navegação, não dashboards com dado pra mostrar. */
.config-admin-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
@media (max-width: 560px) { .config-admin-grid { grid-template-columns: 1fr; } }
.config-admin-item {
  display: flex; align-items: center; gap: 12px; padding: 12px 14px;
  border: 1px solid var(--border-1); border-radius: var(--radius-md);
  color: var(--text-100); text-decoration: none; font-size: 14px; font-weight: 500;
  transition: background var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}
/* --nav-hover-fx inverte por tema (glow no escuro, sombra no claro) — mesma
   regra permanente do projeto (ver memória "fluxo-caixa-tema-claro-escuro"). */
.config-admin-item:hover { background: var(--overlay-1); box-shadow: var(--nav-hover-fx); }
.config-admin-ic { font-size: 18px; width: 24px; text-align: center; flex: none; }

/* "← Configurações" (17/08/2026) — telas que saíram da sidebar (Contas
   bancárias, Usuários, Dispositivos, Auditoria, Lojas, Categorias, Agentes
   de alerta) ganham isto no topbar (titulo_extra), senão a única forma de
   voltar seria o botão do navegador. */
.voltar-config {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--text-mute); text-decoration: none; font-size: 13px; font-weight: 500;
  padding: 6px 10px; border-radius: var(--radius-pill); border: 1px solid var(--border-1);
  transition: background var(--dur-fast) ease, color var(--dur-fast) ease;
}
.voltar-config:hover { background: var(--overlay-1); color: var(--text-100); }

.kpi-card { padding: 14px 16px; }
.kpi-card .kpi-label { font-size: var(--text-xs); color: var(--text-mute); text-transform: uppercase; letter-spacing: .04em; margin-bottom: 6px; }
.kpi-card .kpi-value { font-size: var(--text-2xl); font-weight: 700; color: var(--text-100); line-height: 1.2; }
.kpi-card .kpi-delta { font-size: var(--text-xs); margin-top: 6px; display: inline-flex; align-items: center; gap: 4px; }
.kpi-card::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px; border-radius: var(--radius-md) var(--radius-md) 0 0; background: linear-gradient(90deg, var(--ink), transparent); }
.kpi-card.green::before  { background: linear-gradient(90deg, var(--green), transparent); }
.kpi-card.red::before    { background: linear-gradient(90deg, var(--red), transparent); }
.kpi-card.purple::before { background: linear-gradient(90deg, var(--purple), transparent); }
.kpi-card.cyan::before   { background: linear-gradient(90deg, var(--cyan), transparent); }
.kpi-card.amber::before  { background: linear-gradient(90deg, var(--amber), transparent); }

/* .chart-box — novo (o mockup nunca teve gráfico de verdade, só ilustração SVG
   decorativa no login): altura fixa pro <canvas> do Chart.js, que precisa de um
   container com tamanho definido quando maintainAspectRatio:false (Etapa 5). */
.chart-box { position: relative; height: 260px; }
.chart-box canvas { max-width: 100%; }

/* ==========================================================================
   Badges / pills
   ========================================================================== */
.badge { display: inline-flex; align-items: center; gap: 4px; padding: 2px 10px; border-radius: var(--radius-pill); font: 600 11px/1.5 var(--font-sans); text-transform: uppercase; letter-spacing: .03em; }
.badge--green  { background: rgba(var(--green-rgb), .14);  color: var(--green); }
.badge--red    { background: rgba(var(--red-rgb), .14);    color: var(--red); }
.badge--amber  { background: rgba(var(--amber-rgb), .14);  color: var(--amber); }
.badge--blue   { background: rgba(var(--blue-rgb), .14);   color: var(--blue); }
.badge--purple { background: rgba(var(--purple-rgb), .14); color: var(--purple); }
.badge--neutral{ background: var(--overlay-2); color: var(--text-200); }

/* ==========================================================================
   Inputs / forms
   ========================================================================== */
.field { display: flex; flex-direction: column; gap: 6px; }
.field label { font-size: var(--text-xs); color: var(--text-200); font-weight: 500; }
.input, select.input, textarea.input {
  background: var(--surface-2); border: 1px solid var(--border-1); color: var(--text-100);
  border-radius: var(--radius-sm); padding: 9px 12px; font: var(--text-sm) var(--font-sans);
  transition: border-color var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}
.input::placeholder { color: var(--text-mute); }
.input:focus-visible { outline: none; border-color: var(--ink); box-shadow: var(--ring); }

/* ==========================================================================
   Navegação lateral (sidebar)
   ========================================================================== */
.nx-sidebar { position: fixed; top: 0; left: 0; bottom: 0; width: var(--nxsw); background: var(--surface-2); border-right: 1px solid var(--border-1); display: flex; flex-direction: column; z-index: 1000; }
.navlink {
  display: inline-flex; align-items: center; gap: 10px;
  font: 500 var(--text-sm)/1 var(--font-sans); letter-spacing: -0.01em;
  padding: 9px 14px; margin: 2px 8px; border-radius: var(--radius-btn);
  color: var(--text-mute); text-decoration: none; position: relative;
  transition: background var(--dur-fast) ease, color var(--dur-fast) ease;
}
/* --nav-hover-fx inverte por tema (glow no escuro, sombra no claro) — ver os
   dois :root[data-theme=...] no topo do arquivo. */
.navlink:hover { background: var(--overlay-1); color: var(--text-200); box-shadow: var(--nav-hover-fx); }
.navlink.active { background: var(--overlay-2); color: var(--text-100); font-weight: 600; }
.nav-label { white-space: nowrap; overflow: hidden; }
.navlink.active::before { content: ""; position: absolute; left: -8px; top: 50%; transform: translateY(-50%); width: 3px; height: 18px; background: var(--ink); border-radius: var(--radius-pill); }

/* ==========================================================================
   Tabela de lançamentos
   ========================================================================== */
.tbl { width: 100%; border-collapse: separate; border-spacing: 0; font-size: var(--text-sm); }
.tbl th { text-align: left; color: var(--text-mute); font-weight: 600; font-size: var(--text-xs); text-transform: uppercase; letter-spacing: .04em; padding: 10px 14px; border-bottom: 1px solid var(--border-1); }
.tbl td { padding: 12px 14px; border-bottom: 1px solid var(--overlay-1); color: var(--text-100); }
.tbl tr:hover td { background: var(--overlay-1); }
.tbl .num { text-align: right; font-variant-numeric: tabular-nums; }
.tbl .pos { color: var(--green); font-weight: 600; }
.tbl .neg { color: var(--red); font-weight: 600; }

/* Redesenho do Realizado (18/08/2026, 2 rodadas — a 1ª não resolveu de
   verdade). ACHADO AO VIVO na 2ª rodada: `table-layout:auto` (padrão) mede o
   CONTEÚDO de cada `<th>` pra decidir a largura da coluna, e isso incluía o
   texto inteiro do popover de filtro escondido dentro do `<details>` (todas
   as opções do <select> + botão "OK" concatenados) MESMO com `position:
   absolute` — a medição de conteúdo do algoritmo de auto-layout não respeita
   `position:absolute` em cabeçalho de tabela. Resultado medido: coluna
   "Lançamento" sozinha exigia 722px, a tabela inteira passava de 4000px de
   largura (`.tbl-wrap` com scroll horizontal enorme) — exatamente o "vão"
   que o Eduardo via, e o "rolar pro lado" que ele não queria. `table-layout:
   fixed` ignora conteúdo pra decidir largura (só olha a 1ª linha / CSS
   explícito), resolve os dois problemas de uma vez: sem vão, sem estouro.
   `min-width:0` derruba o `.tbl-wrap .tbl{min-width:max-content}` (pensado
   pro Consolidado, que É pra rolar de lado de propósito — múltiplas
   colunas de banco/categoria — mas não deveria valer aqui) — precisou do
   seletor composto `.tbl-wrap .tbl.tbl--compacta` (especificidade 0,3,0):
   com `.tbl-wrap .tbl--compacta` sozinho (0,2,0), EMPATAVA com a regra de
   `.tbl-wrap .tbl` lá embaixo, e por vir depois no arquivo ela vencia —
   achado ao vivo, a mesma classe de bug que a nota de "watch your selector
   specificities" existe pra evitar. */
.tbl-wrap .tbl.tbl--compacta {
  table-layout: fixed; width: 100%; min-width: 0;
}
.tbl--compacta th, .tbl--compacta td { padding: 6px 8px; }
.tbl--compacta td { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Barra de cima do Realizado (18/08/2026, 2ª rodada — "apertar mais os
   filtros"; 19/08/2026 — Banco/Lançamento voltaram pra cá, o Eduardo não
   gostou da caixinha de filtro embutida no cabeçalho da coluna, ver
   PLANO_FLUXO_CAIXA.md): seletor Agrupado/Consolidado ao lado de TODOS os
   filtros (Banco/Lançamento/Tipo/Descrição/De-Até — Subcategoria e Loja
   continuam fora, pedido anterior). Campos bem mais estreitos que o padrão
   de formulário do resto do sistema (150px) de propósito: são campos
   curtos, não um cadastro — a régua aqui é "planilha", não "formulário". */
/* `align-items:center`, não `flex-end` (achado ao vivo): o seletor
   Agrupado/Consolidado é um "pill" baixo, sem rótulo acima — alinhado pelo
   fundo contra um campo com label+input (mais alto), ele fica visualmente
   "puxado pra baixo", parecendo estar numa 2ª linha mesmo estando na mesma
   (mesmo eixo X, só descolado no Y). Centralizado, os dois convivem numa
   linha só sem esse efeito. */
.realizado-topo { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.filters-row--compacta { margin-bottom: 0; gap: 8px; }
/* `.filters-row.filters-row--compacta` (composto, 0,3,0) — `.filters-row
   .field{min-width:150px}` mais abaixo no arquivo empata em especificidade
   com um `.filters-row--compacta .field` sozinho (0,2,0) e, por vir depois,
   vencia (achado ao vivo, mesma classe de bug do .tbl--compacta acima). */
.filters-row.filters-row--compacta .field { min-width: 0; gap: 3px; }
.filters-row--compacta .field label { font-size: 11px; }
.filters-row--compacta .input { padding: 6px 8px; font-size: 13px; }
.filters-row--compacta select.input { width: 92px; }
/* Banco/Lançamento carregam nome de verdade (ex. "Banco do Brasil",
   "Despesas administrativas") — mais largos que o resto, senão o texto
   selecionado trunca sem dar pra ler qual é. */
.filters-row--compacta select[name="conta_id"].input,
.filters-row--compacta select[name="categoria_id"].input { width: 148px; }
.filters-row--compacta input[type="text"].input { width: 150px; }
.filters-row--compacta input[type="date"].input { width: 128px; }
.filters-row--compacta .btn { padding: 6px 12px; }

/* Tabela larga (Consolidado: ~20 colunas). O scroll fica NA TABELA, nunca no
   body — a página inteira rolando de lado tira a sidebar e o topbar do lugar.
   A 1ª coluna gruda porque, com 30 linhas de dia, perder a data ao rolar
   deixa a matriz ilegível. */
/* Sem margem negativa: ela deixa o wrapper 28px mais largo que o card e faz a
   PÁGINA INTEIRA rolar de lado — exatamente o que este bloco existe pra evitar.
   `max-width:100%` + `min-width:0` garantem que o wrapper respeite o card
   mesmo com uma tabela larguíssima dentro (sem o min-width:0, um filho em
   grid/flex se recusa a encolher abaixo do conteúdo). */
.tbl-wrap { overflow-x: auto; max-width: 100%; min-width: 0; }
.tbl-wrap .tbl { min-width: max-content; }
.tbl-wrap .tbl th:first-child,
.tbl-wrap .tbl td:first-child { position: sticky; left: 0; background: var(--bg-2); z-index: 1; }
.tbl-wrap .tbl tr:hover td:first-child { background: var(--overlay-2, var(--overlay-1)); }
.tbl-wrap .tbl th { white-space: nowrap; }

/* ==========================================================================
   Auth / login
   ========================================================================== */
/* Redesenho de 17/08/2026: era grid de 2 colunas (painel decorativo "Fluxo de
   Caixa" à esquerda + cartão de login à direita) — virou um cartão único,
   centralizado, efeito de vidro fosco (frosted glass) sobre o fundo da
   página. O fundo de tela de verdade (imagem/arte) fica pra depois; por ora
   é só a cor de fundo padrão do tema, mas o cartão já está pronto pra
   flutuar sobre qualquer fundo que vier. */
.auth-shell { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px; }
.auth-card {
  width: 100%; max-width: 380px; padding: 36px 32px;
  background: var(--overlay-2);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border-1); border-radius: var(--radius-lg);
  box-shadow: 0 20px 60px rgba(0, 0, 0, .28);
}

/* ==========================================================================
   Alternador de tema (claro/escuro) — vive dentro do .user-menu (Seção 2.4/2.5
   do plano: tema + configurações ficam no menu de usuário, não mais na sidebar)
   ========================================================================== */
.theme-switch {
  display: inline-flex; align-items: center; gap: 2px; padding: 3px;
  background: var(--overlay-1); border: 1px solid var(--border-1); border-radius: var(--radius-pill);
}
.theme-switch button, .theme-switch a {
  border: 0; background: transparent; color: var(--text-mute); cursor: pointer;
  width: 30px; height: 30px; border-radius: var(--radius-pill); font-size: 14px;
  display: flex; align-items: center; justify-content: center; transition: all var(--dur-fast) ease;
  text-decoration: none;
}
.theme-switch button.on, .theme-switch a.on { background: var(--surface-1); color: var(--text-100); box-shadow: var(--shadow-sm); }
/* variante com rótulo de texto (não só ícone) — alternador Realizado/Planejado
   no topbar da aba Fluxo de caixa (app/paginas.py:alternador_realizado_planejado) */
.theme-switch--text a { width: auto; height: 26px; padding: 0 12px; font-size: 12.5px; font-weight: 600; }

.title-wrap { display: flex; align-items: center; gap: 14px; }

/* ==========================================================================
   Logo — carregado de arquivo (app/static/branding/), não hardcoded no HTML
   ========================================================================== */
/* 28px/168px eram dimensionados pro placeholder SVG (texto pequeno) — uma
   foto de verdade (logo.png, Seção 2.6) ficava minúscula dentro disso, achado
   em 17/08/2026 com o logo real da empresa na tela de login. A logo real
   usada (1586x992px, proporção ~1.6:1 — mais "quadrada" que o 320x80 bem
   largo que o LEIA-ME recomendava) ainda ficava pequena e colada à esquerda
   com só o height aumentado — height maior (200px) deixa a largura chegar
   perto do limite de 320px pra ESSA proporção, e justify-content: center
   centraliza o CONTEÚDO dentro da caixa — mas isso não bastava (achado
   17/08, 2ª rodada): a caixa em si, com max-width menor que o .auth-card,
   ficava colada à esquerda por padrão (bloco sem width:100%/margin não se
   autocentraliza no pai). `margin: 0 auto` resolve a caixa; justify-content
   resolve o conteúdo dentro dela — precisa dos dois. Continua
   aspect-ratio-agnóstico: uma logo bem larga no futuro esbarra no
   max-width antes do height, do mesmo jeito. */
.brand-logo-slot {
  display: flex; align-items: center; justify-content: center;
  height: 200px; max-width: 320px; margin: 0 auto;
}
.brand-logo-slot img { max-height: 100%; max-width: 100%; object-fit: contain; display: block; }

/* ==========================================================================
   Menu de usuário (topo direito) — nome/perfil, abre com tema + configurações
   ========================================================================== */
.user-menu { position: relative; }
.user-menu-trigger {
  display: flex; align-items: center; gap: 10px; padding: 6px 10px 6px 6px;
  border-radius: var(--radius-pill); background: transparent; border: 1px solid transparent;
  cursor: pointer; transition: all var(--dur-fast) ease;
}
.user-menu-trigger:hover, .user-menu.open .user-menu-trigger { background: var(--overlay-1); border-color: var(--border-1); }
.user-menu-trigger .av { width: 30px; height: 30px; border-radius: 50%; background: var(--red); display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; color: #fff; flex-shrink: 0; object-fit: cover; }
.user-menu-trigger .meta { text-align: left; line-height: 1.25; }
.user-menu-trigger .name { font-size: 13px; font-weight: 600; color: var(--text-100); }
.user-menu-trigger .role { font-size: 11px; color: var(--text-mute); }
.user-menu-trigger .chev { font-size: 10px; color: var(--text-mute); margin-left: 2px; }

.user-menu-panel {
  position: absolute; top: calc(100% + 8px); right: 0; width: 240px;
  background: var(--surface-1); border: 1px solid var(--border-1); border-radius: var(--radius-md);
  box-shadow: var(--shadow-card-hover); padding: 10px; z-index: 40;
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: all var(--dur-fast) var(--ease-standard);
}
.user-menu.open .user-menu-panel { opacity: 1; visibility: visible; transform: translateY(0); }
.user-menu-panel .um-head { padding: 6px 8px 10px; border-bottom: 1px solid var(--border-1); margin-bottom: 8px; }
.user-menu-panel .um-head .name { font-size: 13.5px; font-weight: 600; color: var(--text-100); }
.user-menu-panel .um-head .role { font-size: 11.5px; color: var(--text-mute); margin-top: 2px; }
.user-menu-panel .um-row { display: flex; align-items: center; justify-content: space-between; padding: 6px 8px; font-size: 12.5px; color: var(--text-200); }
.user-menu-panel .um-item {
  display: flex; align-items: center; gap: 10px; width: 100%; padding: 9px 8px; border-radius: var(--radius-sm);
  background: transparent; border: 0; color: var(--text-100); font: 500 13px var(--font-sans);
  text-align: left; cursor: pointer; transition: background var(--dur-fast) ease;
}
.user-menu-panel .um-item:hover { background: var(--overlay-1); }
.user-menu-panel .um-item.danger { color: var(--red); }
.user-menu-panel .um-sep { height: 1px; background: var(--border-1); margin: 6px 0; }

/* ==========================================================================
   Casca do app (shell) — sidebar + topbar + área de conteúdo
   Portado do mockup (docs/mockup/mockup_fluxo_caixa.html) na Etapa 2: essas
   classes existiam só no HTML do mockup, nunca tinham ido pro tokens.css
   oficial (só o `.navlink` que fica dentro da sidebar tinha sido portado antes).
   ========================================================================== */
.shell { display: flex; }
.sidebar {
  position: fixed; top: 0; left: 0; bottom: 0; width: var(--nxsw);
  background: var(--surface-2); border-right: 1px solid var(--border-1);
  display: flex; flex-direction: column; z-index: 10;
  transition: width var(--dur-base) var(--ease-standard);
}
.sidebar .brand {
  display: flex; align-items: center; padding: 0 18px; height: var(--nxhh);
  border-bottom: 1px solid var(--border-1); width: 100%; border-left: 0; border-right: 0; border-top: 0;
  background: none; cursor: pointer; text-align: left;
}
.sidebar .brand:hover { background: var(--overlay-1); }
.sidebar .brand img { max-height: 32px; max-width: 100%; object-fit: contain; display: block; }
.sidebar nav { flex: 1; padding-top: 10px; padding-bottom: 14px; overflow-y: auto; }
.sidebar .grp-label { font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--text-mute); padding: 14px 20px 6px; white-space: nowrap; overflow: hidden; }
/* Badge redondo (17/08/2026, referência: sistema Linx Seta) — mesma ideia de
   tamanho/presença do exemplo (ícone grande, redondo, igual recolhida ou
   expandida), mas com os NOSSOS ícones (emoji já usados por item) — sem
   adotar as cores por categoria do exemplo, que destoariam do preto/branco
   do resto da identidade visual. */
.nav-ic {
  width: 34px; height: 34px; flex: none; display: flex; align-items: center; justify-content: center;
  font-size: 16px; border-radius: 50%; background: var(--overlay-2);
  transition: background var(--dur-fast) ease, color var(--dur-fast) ease;
}
.navlink.active .nav-ic { background: var(--ink); color: var(--bg); }

.main { margin-left: var(--nxsw); flex: 1; min-width: 0; transition: margin-left var(--dur-base) var(--ease-standard); }

/* Instância isolada do painel Cartão Cred (25/08/2026, ver app/perfil_app.py
   e app/ui.py:casca_painel_cred) — essa instância não tem .sidebar nenhuma
   (a única tela de verdade é o painel; uma barra lateral pra navegar entre
   telas que nem existem mais aqui seria só link morto). .main reserva
   var(--nxsw) de margem pra sidebar por padrão — sem esta regra o conteúdo
   ficaria deslocado, com um vão vazio à esquerda do tamanho da sidebar que
   nunca é desenhada. */
.shell--sem-sidebar .main { margin-left: 0; }

/* Sidebar retrátil (17/08/2026) — clique no logo (topo) alterna. Estado
   persiste entre páginas via localStorage: é preferência leve de UI, não dado
   de negócio (mesmo critério que já vale pra decisão de não auditar troca de
   tema) — por isso não precisa virar coluna no banco. */
/* `.sidebar .brand img` (2 classes + elemento) tem mais especificidade que
   `.brand-icon`/`.brand-icon-fallback` sozinhos (1 classe) — sem o prefixo
   `.sidebar .brand` aqui, o `display:block` daquela regra genérica vencia e o
   ícone pequeno ficava sempre visível, sobreposto à logo cheia, mesmo com a
   sidebar expandida (achado de 17/08/2026). */
.sidebar .brand .brand-icon, .sidebar .brand .brand-icon-fallback { display: none; flex: none; }
.brand-icon { width: 30px; height: 30px; object-fit: contain; border-radius: var(--radius-sm); }
.brand-icon-fallback { width: 30px; height: 30px; align-items: center; justify-content: center; font-size: 18px; }

#appShell.sidebar-collapsed .sidebar { width: var(--nxsw-collapsed); }
#appShell.sidebar-collapsed .main { margin-left: var(--nxsw-collapsed); }
#appShell.sidebar-collapsed .sidebar .brand { justify-content: center; padding: 0; }
#appShell.sidebar-collapsed .sidebar .brand-full { display: none; }
#appShell.sidebar-collapsed .sidebar .brand-icon,
#appShell.sidebar-collapsed .sidebar .brand-icon-fallback { display: flex; }
#appShell.sidebar-collapsed .navlink { justify-content: center; padding: 0; }
#appShell.sidebar-collapsed .nav-label,
#appShell.sidebar-collapsed .grp-label { display: none; }

/* Tooltip customizado — substitui o texto que some quando a sidebar está
   recolhida (ícone sozinho não diz qual aba é qual).

   Achado de 17/08/2026: a 1ª versão era um `::after` puro em CSS
   (`position:absolute` relativo ao `.navlink`) — funcionava, mas
   `.sidebar nav` tem `overflow-y:auto` (pro dia que a lista crescer demais
   pra caber na tela), e por spec um eixo com overflow não-visible força o
   OUTRO eixo também a cortar — o tooltip, que precisa "vazar" pra fora da
   sidebar (`left: calc(100% + 10px)`), ficava cortado bem na borda,
   praticamente ilegível. `position:fixed` (calculado por JS a partir da
   posição real do ícone, ver `_tooltip_navegacao_js` em app/ui.py) escapa
   desse recorte porque é posicionado relativo à viewport, não a nenhum
   ancestral com overflow. */
.nav-tooltip {
  position: fixed; display: none;
  background: var(--surface-1); color: var(--text-100); border: 1px solid var(--border-1);
  padding: 6px 10px; border-radius: var(--radius-sm); font-size: 12.5px; white-space: nowrap;
  box-shadow: var(--shadow-md); pointer-events: none; z-index: 1000;
}
.nav-tooltip.show { display: block; }
.topbar {
  height: var(--nxhh); display: flex; align-items: center; justify-content: space-between;
  padding: 0 24px; border-bottom: 1px solid var(--border-1); background: var(--surface-2);
  position: sticky; top: 0; z-index: 5;
}
.topbar .title { font-size: 16px; font-weight: 600; }
.topbar .actions { display: flex; align-items: center; gap: 12px; }

/* Chat de IA inline no topbar (17/08/2026) — atalho pro Assistente sem sair
   da tela atual: emoji abre a aba sozinho, digitar + Enter abre já com a
   pergunta enviada (ver _topbar_ia/_topbar_ia_keydown_js em app/ui.py e
   _autoenviar_pergunta_pendente_js em app/paginas.py). */
.topbar-ia { display: flex; align-items: center; gap: 8px; margin-left: 20px; padding-left: 20px; border-left: 1px solid var(--border-1); }
.topbar-ia-icone { font-size: 17px; cursor: pointer; line-height: 1; padding: 6px; border-radius: var(--radius-sm); transition: background var(--dur-fast) ease, box-shadow var(--dur-fast) ease; }
/* Mesmo par glow/sombra do hover da sidebar (--nav-hover-fx) — regra do
   projeto: todo efeito de cor/luz inverte entre os dois temas. */
.topbar-ia-icone:hover { background: var(--overlay-1); box-shadow: var(--nav-hover-fx); }
.topbar-ia-input {
  width: 220px; background: var(--surface-1); border: 1px solid var(--border-1); color: var(--text-100);
  border-radius: var(--radius-pill); padding: 7px 14px; font-size: 13px;
  transition: width var(--dur-fast) ease, border-color var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}
.topbar-ia-input::placeholder { color: var(--text-mute); }
.topbar-ia-input:focus-visible { outline: none; border-color: var(--ink); box-shadow: var(--ring); width: 280px; }

/* Tela estreita — tablet/celular (17/08/2026, achado numa auditoria de
   responsividade, não pedido específico) — sem isto, a sidebar de 240px
   fixos sozinha já não cabia num celular (confirmado: `scrollWidth` bem
   maior que a viewport, o app ficava com scroll horizontal, inutilizável).
   Reaproveita o MESMO visual de "recolhida" que o botão do topo já usa
   (ícone só, sem rótulo) — só que como PADRÃO aqui embaixo de 780px, não
   como preferência salva. Redefinir `--nxsw` (em vez de duplicar as regras
   de largura de `.sidebar`/`.main`) já basta pra elas, que usam a variável;
   só falta esconder rótulo/logo cheia do mesmo jeito que `.sidebar-collapsed`
   já faz. Tooltip ao passar o mouse (JS) não é replicado aqui de propósito
   — tela de toque não tem hover, não haveria como mostrá-lo mesmo. Alternar
   pelo botão do topo fica sem efeito visual nesta faixa (os dois estados já
   são a mesma largura) — aceitável: o objetivo aqui é só parar de quebrar,
   não portar o toggle inteiro pra toque. */
@media (max-width: 780px) {
  :root { --nxsw: var(--nxsw-collapsed); }
  .sidebar .brand-full { display: none; }
  .sidebar .brand-icon, .sidebar .brand-icon-fallback { display: flex; }
  .sidebar .brand { justify-content: center; padding: 0; }
  .navlink { justify-content: center; padding: 0; }
  .nav-label, .grp-label { display: none; }
  .topbar-ia-input { display: none; }
  .topbar-ia { border-left: 0; padding-left: 0; margin-left: 10px; }
  /* `.topbar` tem altura fixa (`--nxhh`) — em página com `titulo_extra`
     (alternador Realizado/Planejado, "← Configurações") o título já não
     cabia numa linha só nessa largura e empurrava o menu do usuário pra
     fora da tela (achado na mesma auditoria). Deixa quebrar linha em vez
     de estourar a largura. */
  .topbar { flex-wrap: wrap; height: auto; min-height: var(--nxhh); padding: 10px 16px; row-gap: 8px; }
  .title-wrap { flex-wrap: wrap; row-gap: 6px; }
}
/* Auto-ajuste em telas largas (17/08/2026) — sem `margin:auto`, o `max-width`
   deixava o conteúdo grudado à esquerda (o resto da largura virava espaço
   morto do lado direito, achado numa tela maior que a de desenvolvimento).
   `margin:0 auto` centraliza a sobra; o teto subiu de 1280px pra 1520px pra
   dar mais respiro a tabela/gráfico em tela grande, sem esticar a ponto de
   ficar rala numa ultrawide. */
.body { padding: 24px; max-width: 1520px; margin: 0 auto; }

/* Cartão Cred (Etapa 7, 14/08/2026) — o painel embutido por iframe tem rail
   lateral própria e foi desenhado pra largura cheia; os 1280px do .body padrão
   o deixariam apertado. Opt-in via shell(classe_corpo=...), nenhuma outra
   página é afetada. 48px = padding vertical do .body (24px topo + 24px base). */
.body--full { max-width: none; }
.painel-embed {
  display: block; width: 100%; height: calc(100vh - var(--nxhh) - 48px);
  border: 0; border-radius: var(--radius-md); background: var(--surface-1);
}

.empty-state { text-align: center; padding: 70px 20px; color: var(--text-mute); }
.empty-state .ic { font-size: 34px; margin-bottom: 14px; opacity: .6; }
.empty-state h3 { font-size: 15px; color: var(--text-200); font-weight: 600; margin-bottom: 6px; }
.empty-state p { font-size: 13.5px; max-width: 420px; margin-inline: auto; line-height: 1.6; }

/* ==========================================================================
   Cabeçalho de seção (título + contador/ação) — existia só no HTML do mockup
   (Etapa 3: telas de Categorias/Contas bancárias/Importar/Realizado)
   ========================================================================== */
/* flex-wrap (17/08/2026, achado na auditoria de responsividade): em tela
   estreita, título + badge (ex.: "Fechamento" + "30 linha(s)") não cabiam
   numa linha só e o badge estourava a largura da página. Inofensivo em
   tela larga — só quebra quando realmente não cabe. */
.section-head { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; margin-bottom: 14px; gap: 12px; }
.section-head h2 { font-size: 15px; font-weight: 600; }

/* ==========================================================================
   Aviso pós-ação (sucesso/erro) — Etapa 3, generalizado do banner ad-hoc que
   só a tela de login (Etapa 1) tinha
   ========================================================================== */
.flash { padding: 10px 14px; border-radius: var(--radius-sm); margin-bottom: 16px; font-size: 13.5px; }
.flash--erro { background: rgba(var(--red-rgb), .12); color: var(--red); }
.flash--ok { background: rgba(var(--green-rgb), .12); color: var(--green); }

/* Filtros de período/conta/categoria (Realizado/Planejado) — existia só no
   HTML do mockup, igual ao .section-head acima */
.filters-row { display: flex; gap: 10px; align-items: flex-end; margin-bottom: 18px; flex-wrap: wrap; }
.filters-row .field { min-width: 150px; }

/* ==========================================================================
   Assistente — chat com histórico (Fase 1 da IA, 08/08/2026)
   ========================================================================== */
.chat-shell { display: flex; flex-direction: column; }
/* Altura própria (não mais 100vh-menos-topbar): desde 10/08/2026 o cartão de
   Análises pode aparecer ACIMA do chat na mesma página, com altura variável —
   um cálculo baseado em viewport quebraria (thread cortada ou vazamento por
   baixo da tela) dependendo de quantas observações houver. */
.chat-thread { flex: 1; min-height: 320px; max-height: 55vh; overflow-y: auto; padding: 4px 4px 12px; display: flex; flex-direction: column; gap: 14px; }
.chat-msg { display: flex; flex-direction: column; max-width: 72%; }
.chat-msg--usuario { align-self: flex-end; align-items: flex-end; }
.chat-msg--assistente { align-self: flex-start; align-items: flex-start; }
.chat-bubble { padding: 10px 14px; border-radius: var(--radius-md); font-size: 14px; line-height: 1.5; white-space: pre-wrap; }
.chat-msg--usuario .chat-bubble { background: var(--ink); color: var(--ink-contrast); border-bottom-right-radius: 4px; }
.chat-msg--assistente .chat-bubble { background: var(--surface-1); border: 1px solid var(--border-1); border-bottom-left-radius: 4px; }
.chat-hora { font-size: 11px; color: var(--text-mute); margin-top: 4px; padding: 0 2px; }
.chat-vazio { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; color: var(--text-mute); text-align: center; }
.chat-sugestoes { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; max-width: 520px; }
.chat-sug { padding: 7px 14px; border-radius: var(--radius-pill); border: 1px solid var(--border-1); background: var(--overlay-1); color: var(--text-200); font-size: 13px; text-decoration: none; cursor: pointer; }
.chat-sug:hover { background: var(--overlay-2); color: var(--text-100); }
.chat-form { display: flex; gap: 10px; padding-top: 12px; border-top: 1px solid var(--border-1); }
.chat-form input { flex: 1; }
.chat-disc { font-size: 12px; color: var(--text-mute); text-align: center; padding-top: 8px; }

/* Insights / Revisor de categoria / Agentes de alerta (Fase 1 da IA, parte 2,
   10/08/2026) — cartão de observação, reaproveitado pelas 3 fontes (só o
   conteúdo interno muda; alerta de agente nunca tem botão de ação). */
.ia-lista { display: flex; flex-direction: column; gap: 10px; }
.ia-lista + .ia-lista { margin-top: 16px; }
.ia-item { display: flex; gap: 12px; padding: 12px 14px; border-radius: var(--radius-md); background: var(--overlay-1); border: 1px solid var(--border-1); }
.ia-ic { font-size: 20px; line-height: 1.3; flex-shrink: 0; }
.ia-corpo { flex: 1; min-width: 0; }
.ia-tt-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ia-tt { font-weight: 600; font-size: 13.5px; color: var(--text-100); }
.ia-ds { font-size: 13px; color: var(--text-mute); margin-top: 4px; line-height: 1.5; }
.ia-acoes { margin-top: 8px; display: flex; gap: 8px; }

/* ==========================================================================
   Utilitários
   ========================================================================== */
.text-mute { color: var(--text-mute); }
.text-200 { color: var(--text-200); }
.flex { display: flex; }
.gap-2 { gap: 8px; } .gap-3 { gap: 12px; } .gap-4 { gap: 16px; }
.grid { display: grid; }
