/* Estilos além do Tailwind — itens de menu, cards, tabela e utilitários */

/* ======================================================================
   TOKENS — a identidade em um lugar só

   A tela de acesso (fim deste arquivo) fixou o registro do app: grafite
   quase-preto, dourado champanhe, papel levemente quente e fio de 1px em vez
   de sombra pesada. Estas variáveis são esse acordo escrito uma vez, para as
   ~40 telas herdarem em vez de cada uma escolher o seu cinza.

   Por que variáveis e não utilitários do Tailwind: o tema escuro precisa
   trocar quinze valores de uma vez. Com `--linha` isso é um bloco; com
   `dark:border-...` seriam centenas de `class=` para caçar quando o tom mudar.
   ====================================================================== */
:root{
  --ouro:#bf9b4e;  --ouro-claro:#d0ac5c;  --ouro-escuro:#a8873c;
  --ouro-fraco:rgba(191,155,78,.16);
  --fundo:#f5f5f2;              /* papel: levemente quente, não o cinza-azul */
  --superficie:#ffffff;         /* card */
  --superficie-2:#faf9f6;       /* faixa de filtro, cabeçalho de lista */
  --linha:#e5e3dc;              /* fio de 1px — a borda de tudo */
  --linha-forte:#d5d3cb;        /* borda de campo, que precisa se ver */
  --tinta:#1f2937;
  /* Os dois cinzas de apoio são o mais claro que ainda passa AA (4,5:1) sobre
     a superfície — e não um tom "bonitinho" escolhido no olho. Quase tudo que
     usa estes tokens é texto PEQUENO (rótulo de coluna em versalete de 11px,
     legenda de campo), justamente o que mais sofre com cinza claro. */
  --tinta-fraca:#5b6270;        /* ~6,4:1 — rótulo, legenda, texto de apoio */
  --tinta-tenue:#6f7583;        /* 4,6:1 — o degrau mais leve que ainda serve */
  --sombra:0 1px 2px rgba(23,20,12,.05), 0 1px 12px rgba(23,20,12,.03);
  --raio:.85rem;

  /* ====================================================================
     ELEVAÇÃO — três degraus, e só três

     Antes havia UMA sombra (`--sombra`) para tudo, e ela era quase nada:
     card, modal e popover chegavam à tela com o mesmo peso, então nada
     parecia estar "acima" de nada. O olho lê profundidade antes de ler
     texto — sem degraus, uma tela de doze cards vira um mosaico plano.

     Cada degrau tem DUAS camadas de propósito: um contato curto e escuro
     (a beirada, que ancora o objeto na página) e um halo longo e diluído
     (a sombra distante, que dá o ar). Uma sombra só sempre parece adesivo.

     · e1 — o que descansa na página: card, campo, pílula.
     · e2 — o que se levanta ao ser tocado: card em hover, popover, chip.
     · e3 — o que flutua sobre tudo: modal, gaveta, tooltip.
     ==================================================================== */
  --e1:0 1px 2px rgba(28,22,10,.045), 0 2px 8px -2px rgba(28,22,10,.05);
  --e2:0 2px 4px -1px rgba(28,22,10,.06), 0 10px 24px -8px rgba(28,22,10,.13);
  --e3:0 10px 20px -8px rgba(28,22,10,.14), 0 28px 56px -20px rgba(28,22,10,.22);
  /* Halo dourado — a elevação da MARCA. Só para o que é primário
     (botão de ação, tile em destaque): dourado em tudo vira purpurina. */
  --e-ouro:0 2px 6px -1px rgba(140,108,32,.22), 0 12px 28px -10px rgba(140,108,32,.35);

  /* Escala de raio. Três valores, proporcionais: o card é o meio, o que
     vive dentro dele é menor, o que flutua sobre ele é maior. Raio igual
     em objeto grande e pequeno faz o pequeno parecer inflado. */
  --r-xs:.4rem; --r-sm:.55rem; --r-lg:1.15rem; --r-xl:1.5rem;

  /* Realce de topo: o fio branco de 1px no alto de uma superfície clara.
     É como material real pega a luz — sem ele o card é um retângulo
     recortado; com ele, uma placa. No escuro é o que separa dois grafites
     que a borda sozinha não separa. */
  --brilho:inset 0 1px 0 rgba(255,255,255,.65);

  /* Curvas. `--mola` tem um leve ultrapasse no fim: é o que faz um
     painel "assentar" em vez de simplesmente parar. */
  --sai:cubic-bezier(.4,0,.2,1);
  --mola:cubic-bezier(.34,1.4,.64,1);

  /* ====================================================================
     COR DE GRÁFICO — quatro paletas, cada uma com UM trabalho

     Antes, cada gráfico escolhia o próprio hex no meio do app.js: um usava
     #10b981, outro #f43f5e, um terceiro #22c55e. Eram quinze escolhas
     independentes, e nenhuma delas pertencia a esta marca — vinham do
     paletão padrão do Tailwind.

     Aqui elas viram QUATRO paletas nomeadas pelo trabalho que fazem, e
     cada valor foi MEDIDO, não escolhido no olho (validador do dataviz:
     banda de luminosidade, piso de croma, separação para daltonismo em
     TODOS os pares, e contraste contra a superfície).

     O tema escuro tem passos PRÓPRIOS — não é o claro invertido. Um verde
     que passa sobre papel branco pode sumir sobre grafite.
     ==================================================================== */

  /* 1. IDENTIDADE (rosca, séries de linha). Cinco, e cinco é o limite:
        com seis, um par qualquer fica indistinguível para quem tem
        daltonismo — foi medido, não suposto. Além de cinco, o app agrupa
        o resto em "Outros" (mais legível de todo jeito). Ordem FIXA: a
        classe 3 é sempre a mesma cor, mude o filtro que mudar. */
  --g-cat-1:#9d9100;  --g-cat-2:#007e68;  --g-cat-3:#0092f3;
  --g-cat-4:#a851bc;  --g-cat-5:#bb311a;

  /* 2. POLARIDADE (entrou x saiu). Não são "duas cores da lista": são os
        dois polos de uma mesma régua, e por isso vivem à parte.
        O DEGRAU DE LUMINOSIDADE ENTRE ELAS É OBRIGATÓRIO (ΔL 0,20):
        verde e vermelho de mesmo claro são a definição do que o daltônico
        NÃO enxerga — quatro pares "elegantes" foram reprovados antes
        deste passar. Quem não vê a cor ainda vê qual é o mais escuro. */
  --g-entrada:#68b274;  --g-saida:#9b4440;

  /* 3. MAGNITUDE / ORDEM (Meta -> Realizado -> A vencer). Uma matiz só —
        o ouro da marca —, do claro ao escuro. Rampa, nunca arco-íris:
        a ordem tem de se ler sem legenda. */
  --g-ordem-1:#cbb06a;  --g-ordem-2:#a8873c;  --g-ordem-3:#68501a;

  /* 4. ESTADO (dentro / apertado / estourou). Reservadas: nunca viram
        "série 4". Andam sempre com rótulo ou ícone, jamais só a cor. */
  --g-bom:#68b274;  --g-atencao:#a8873c;  --g-critico:#9b4440;

  /* A moldura do gráfico é RECESSIVA: a grade orienta, não compete. */
  --g-grade:rgba(31,41,55,.10);
  --g-eixo:#6f7583;
  /* Referência (a coluna "meta" atrás do realizado): cinza, não cor. Uma
     meta não é uma categoria — é o pano de fundo contra o qual se lê. */
  --g-referencia:#cfcdc4;
}
html.dark{
  --fundo:#131418;
  --superficie:#191a1f;
  --superficie-2:#1e1f25;
  --linha:rgba(255,255,255,.08);
  --linha-forte:rgba(255,255,255,.14);
  --tinta:#e5e7eb;
  --tinta-fraca:#a8aeba;
  --tinta-tenue:#878d99;
  --sombra:none;
  /* No escuro a sombra não some — ela ESCURECE. Um card sem sombra sobre
     grafite flutua sem peso; o que muda é que o halo precisa ser bem mais
     opaco (não há branco de página para ele contrastar) e o realce de topo
     vira um fio de luz de 8%, não de 65%. */
  --e1:0 1px 2px rgba(0,0,0,.35), 0 2px 8px -2px rgba(0,0,0,.30);
  --e2:0 2px 6px -1px rgba(0,0,0,.45), 0 12px 28px -10px rgba(0,0,0,.55);
  --e3:0 12px 24px -10px rgba(0,0,0,.6), 0 32px 64px -24px rgba(0,0,0,.75);
  --e-ouro:0 2px 8px -2px rgba(191,155,78,.30), 0 14px 32px -12px rgba(191,155,78,.40);
  --brilho:inset 0 1px 0 rgba(255,255,255,.06);

  /* Passos PRÓPRIOS do tema escuro — revalidados contra a superfície
     #191a1f, não derivados dos de cima. As matizes são as mesmas (a
     identidade não muda com o tema); o claro e o croma é que sobem, senão
     o mesmo verde que canta no papel some no grafite. */
  --g-cat-1:#a59800;  --g-cat-2:#008e67;  --g-cat-3:#0099ff;
  --g-cat-4:#bf54be;  --g-cat-5:#cd4000;
  --g-entrada:#58a365;  --g-saida:#a94e49;
  --g-ordem-1:#8a6c20;  --g-ordem-2:#bf9b4e;  --g-ordem-3:#e0c98d;
  --g-bom:#58a365;  --g-atencao:#bf9b4e;  --g-critico:#a94e49;
  --g-grade:rgba(255,255,255,.08);
  --g-eixo:#878d99;
  --g-referencia:#3a3b42;
}

/* Faz o navegador desenhar os controles nativos na versão escura. Sem isto o
   ícone do <input type="month"> (competência, no topo) é preto sobre fundo
   escuro e some — junto com as barras de rolagem. */
html.dark{ color-scheme:dark; }

/* Números em fonte tabular: coluna de valores só alinha quando o "1" ocupa a
   mesma largura do "8". Vale para KPI, tabela e qualquer célula à direita. */
.kpi-value, table.tbl td.text-right, table.tbl th.text-right,
.tabular{ font-variant-numeric:tabular-nums; }

/* ---------------------------------------------------------------------
   A CASCA — sidebar e topbar
   --------------------------------------------------------------------- */
/* O papel do app. Vale para o <main> e para o #loader do boot — o instante
   entre "abriu" e "montou" não pode piscar num cinza diferente.

   O FUNDO É ILUMINADO, não chapado. Era uma cor sólida, e um plano de cor
   única não tem direção: os cards flutuavam num vazio sem fonte de luz e a
   página inteira lia como um wireframe pintado. São duas camadas presas ao
   topo (`background-attachment:fixed`, para a luz não rolar junto com o
   conteúdo e denunciar que é textura):

   · um bafo dourado no alto à esquerda, pertinho do menu — é de lá que a
     marca vem, e é de lá que a luz passa a vir;
   · uma queda vertical de ~2% para o pé da tela, que dá o eixo.

   A soma é fraquíssima de propósito (o dourado chega a 5% de alfa). Não é
   para ser vista; é para ser sentida quando ela some. */
.app-main{
  background:
    radial-gradient(130% 78% at 6% -8%,  rgba(191,155,78,.075) 0%, rgba(191,155,78,.018) 34%, transparent 62%),
    linear-gradient(180deg, #fbfaf7 0%, var(--fundo) 46%, #f0efea 100%);
  background-attachment:fixed;
}
html.dark .app-main{
  background:
    radial-gradient(130% 78% at 6% -8%, rgba(191,155,78,.10) 0%, rgba(191,155,78,.025) 34%, transparent 62%),
    linear-gradient(180deg, #1a1b21 0%, var(--fundo) 48%, #0f1013 100%);
  background-attachment:fixed;
}

/* A sidebar é o mesmo painel de marca da tela de acesso: grafite com brilho
   dourado difuso e um fio de ouro na divisa. É o que costura login e app. */
#sidebar{
  background:radial-gradient(125% 100% at 10% 0%, #26262e 0%, #191920 45%, #0e0e11 100%);
  position:relative;
}
#sidebar::after{
  content:''; position:absolute; top:0; right:0; bottom:0; width:1px; pointer-events:none;
  background:linear-gradient(180deg, transparent, rgba(191,155,78,.45) 22%, rgba(191,155,78,.45) 78%, transparent);
}
/* Cabeçalho da sidebar: marca + assinatura serifada, igual à tela de acesso. */
.side-mark{
  width:2.25rem; height:2.25rem; border-radius:.6rem; background:#fff; flex:0 0 auto;
  display:grid; place-items:center; box-shadow:0 3px 12px rgba(0,0,0,.35);
}
.side-word{
  font-family:Georgia,'Times New Roman',serif; font-size:1rem; font-weight:700;
  letter-spacing:.2em; color:#fff; line-height:1.1;
}
.side-tag{
  font-size:.6rem; letter-spacing:.16em; text-transform:uppercase;
  color:var(--ouro); margin-top:.1rem;
}
/* Rótulo do grupo de itens ("Operação", "Análise", "Configuração"). Divide o
   menu por intenção — quem procura o DRE não varre a lista inteira. */
.nav-sec + .nav-sec{ margin-top:.5rem; }

/* ---------------------------------------------------------------------
   GRUPOS RECOLHÍVEIS DA BARRA LATERAL
   O rótulo do grupo é um BOTÃO: as abas ficam recolhidas dentro dele e
   aparecem ao passar o mouse ou ao clicar. Antes eram 11 itens sempre
   abertos — uma lista que se varre, não um menu que se navega.

   TRÊS DECISÕES que a primeira versão errou, e por quê:

   1. ACORDEÃO (um grupo aberto por vez, em `abrirGrupo` no app.js). Abrir
      um grupo sem fechar os outros empurrava tudo para baixo: o item que
      o usuário estava mirando FUGIA do cursor. Com um por vez a barra
      mantém a altura e nada foge.
   2. HOVER COM ATRASO (~170ms para abrir, ~380ms para voltar). Sem ele,
      atravessar a barra a caminho do conteúdo abria e fechava grupos no
      caminho — a barra "piscava" sozinha.
   3. ALTURA MEDIDA, não um teto chutado. O `max-height:32rem` fixo fazia
      a transição de um grupo de 2 itens parecer instantânea e a de 6
      parecer lenta (a duração é a mesma para percursos diferentes). O JS
      mede a lista e escreve em `--alt`; a animação passa a ser sempre a
      mesma velocidade. O fallback 32rem cobre o caso de o JS não rodar.

   A técnica é max-height + overflow:hidden. A "moderna"
   (grid-template-rows 0fr->1fr) foi tentada e NÃO interpola aqui: o grupo
   ganhava a classe e continuava com 0px de altura.

   O clique é o que manda (funciona no toque e no teclado); o hover é
   atalho de desktop e vive no JS, atrás de um matchMedia(hover:hover).
   --------------------------------------------------------------------- */
.nav-group{
  display:flex; align-items:center; gap:.5rem; width:100%;
  padding:.5rem 1rem .5rem .7rem; min-height:2.25rem;
  font-size:.72rem; font-weight:700; letter-spacing:.11em;
  text-transform:uppercase; color:#8f8a82; text-align:left; cursor:pointer;
  border-radius:.4rem; transition:color .15s, background .15s;
}
.nav-group:hover{ color:#fff; background:rgba(255,255,255,.06); }
.nav-group:focus-visible{ outline:2px solid var(--ouro); outline-offset:-2px; }
.nav-group-txt{ flex:1 1 auto; min-width:0; }
/* O chevron ficou à ESQUERDA, apontando para a direita quando fechado: é a
   convenção de árvore (▸ pasta), e ela diz "tem coisa aqui dentro" antes de
   o usuário clicar. À direita ele era só um enfeite no fim da linha. */
.nav-group-chev{
  width:.8rem; height:.8rem; flex:0 0 auto; opacity:.55;
  transition:transform .2s ease, opacity .15s;
}
/* Quantas abas o grupo esconde — some quando ele está aberto, porque aí
   a resposta está à vista. */
.nav-group-n{
  font-size:.65rem; font-weight:600; letter-spacing:0; color:#7d7871;
  background:rgba(255,255,255,.07); border-radius:999px;
  padding:.05rem .4rem; transition:opacity .15s;
}
/* Ponto dourado: a aba ABERTA está dentro deste grupo fechado. Sem ele o
   usuário perde a orientação — o menu inteiro fica cinza e nada diz onde
   ele está. Some quando o grupo abre (aí o item ativo aparece marcado). */
.nav-group-dot{
  width:.4rem; height:.4rem; flex:0 0 auto; border-radius:999px;
  background:var(--ouro); opacity:0; transition:opacity .15s;
}
.nav-sec.tem-ativa:not(.aberta) > .nav-group .nav-group-dot{ opacity:1; }
.nav-sec.tem-ativa > .nav-group{ color:#cfc9be; }

.nav-list{ max-height:0; overflow:hidden; transition:max-height .22s ease; }
.nav-sec.aberta > .nav-list{ max-height:var(--alt, 32rem); }
.nav-sec.aberta > .nav-group{ color:#fff; }
.nav-sec.aberta > .nav-group .nav-group-chev{ transform:rotate(90deg); opacity:.9; }
.nav-sec.aberta > .nav-group .nav-group-n{ opacity:0; }
/* Sem JS nada recolhe: a classe `js-nav` só entra quando o script assume o
   menu. Se o app.js falhar, o usuário vê as 11 abas — feio, mas navegável. */
#nav:not(.js-nav) .nav-list{ max-height:none; }
/* Fio de guia ligando as abas ao seu grupo. É o que faz a lista parecer
   filha do título em vez de um bloco solto embaixo dele. */
.nav-list-in{ position:relative; }
.nav-list-in::before{
  content:''; position:absolute; left:1.15rem; top:.1rem; bottom:.1rem;
  width:1px; background:rgba(255,255,255,.09);
}

/* Itens de navegação da sidebar */
.nav-item{
  display:flex; align-items:center; gap:.65rem;
  width:100%; text-align:left; position:relative;
  padding:.5rem 1.25rem .5rem 1.9rem; color:#a8a49c; font-size:.875rem;
  transition:background .15s, color .15s;
}
/* Ícone de linha do item de menu: tamanho fixo, não encolhe, herda a cor. */
.nav-ico{ width:1.05rem; height:1.05rem; flex:0 0 auto; opacity:.9; }
.nav-item:hover{ background:rgba(255,255,255,.05); color:#fff; }
/* Ativo: fio dourado à esquerda + tinta clara. A barra é um ::before em vez de
   border-left para os itens não "pularem" 3px ao trocar de aba. */
.nav-item.active{ background:var(--ouro-fraco); color:#fff; font-weight:600; }
/* O fio dourado cai EM CIMA do fio de guia do grupo (mesma coluna, 1.15rem):
   a linha que liga as abas ao título acende onde o usuário está, em vez de
   haver dois traços verticais concorrendo. */
.nav-item.active::before{
  content:''; position:absolute; left:1.1rem; top:.25rem; bottom:.25rem; width:2px;
  border-radius:2px; background:var(--ouro);
}
.nav-item.active .nav-ico{ color:var(--ouro-claro); opacity:1; }
/* Contador de alertas. `margin-left:auto` o joga para a direita do item (o
   .nav-item é flex); min-width + padding lateral mantêm o círculo redondo com
   1 dígito e o deixam virar pílula com 2 ou 3, sem espremer o número. */
.nav-badge{
  margin-left:auto; min-width:1.25rem; padding:0 .35rem;
  border-radius:999px; background:#dc2626; color:#fff;
  font-size:.68rem; font-weight:700; line-height:1.25rem; text-align:center;
}

/* Botão de recolher/expandir a barra (modo rail). Chevron aponta para a
   esquerda (recolher) e gira 180° quando já está recolhida (expandir). */
.rail-toggle{
  margin-left:auto; width:1.75rem; height:1.75rem; flex:0 0 auto;
  display:grid; place-items:center; border-radius:.5rem; color:#a8a49c;
  transition:background .15s, color .15s;
}
.rail-toggle:hover{ background:rgba(255,255,255,.06); color:#fff; }
.rail-chevron{ width:1.1rem; height:1.1rem; transition:transform .2s; }

/* ---- Barra recolhida: só os ícones (logo, abas e foto do usuário) ----
   A regra #sidebar.rail vence o .w-60 do Tailwind (id+classe > classe), então
   a largura encolhe sem !important. Tudo que é texto some; o que fica é ícone. */
#sidebar.rail{ width:4.75rem; }
#sidebar.rail .side-head{ flex-direction:column; gap:.75rem; padding-left:0; padding-right:0; }
#sidebar.rail .side-words{ display:none; }
#sidebar.rail .rail-toggle{ margin-left:0; }
#sidebar.rail .rail-chevron{ transform:rotate(180deg); }
#sidebar.rail .nav-group{ display:none; }
/* No modo rail o rótulo do grupo some — e sem ele não há como abrir o
   grupo. Então ali os itens ficam SEMPRE visíveis: a barra de ícones é o
   próprio menu recolhido, recolher duas vezes não faria sentido. */
#sidebar.rail .nav-list{ max-height:none; }
/* Sem os títulos, o que separa um grupo do outro é um fio. Sem ele os 11
   ícones viram uma coluna única e a divisão por intenção se perde. */
#sidebar.rail .nav-list-in::before{ display:none; }
#sidebar.rail .nav-sec + .nav-sec{
  margin-top:.45rem; padding-top:.45rem; border-top:1px solid rgba(255,255,255,.08);
}
#sidebar.rail .nav-item{ justify-content:center; padding-left:0; padding-right:0; }
#sidebar.rail .nav-item > span:not(.nav-badge){ display:none; }
#sidebar.rail .nav-item.active::before{ left:0; }
/* O contador de alertas vira um ponto no canto do ícone (o número não cabe). */
#sidebar.rail .nav-badge{
  position:absolute; top:.35rem; right:1.05rem; margin:0;
  width:.5rem; height:.5rem; min-width:0; padding:0; font-size:0; line-height:0;
}
#sidebar.rail #sidebarProfile{ padding-left:0; padding-right:0; }
#sidebar.rail #sidebarProfile > .flex{ justify-content:center; }
#sidebar.rail .sb-meta,
#sidebar.rail .sb-tip,
#sidebar.rail #pfBackup,
#sidebar.rail #sessaoInfo{ display:none; }
#sidebar.rail .sessao-bar{ justify-content:center; }

/* ---------------------------------------------------------------------
   TOPBAR — a régua de contexto

   Ela é o único elemento que fica na tela o tempo todo junto com o menu, e
   estava resolvida como uma faixa translúcida com um fio embaixo. Duas
   coisas mudam:

   · o fio ganha um GRADIENTE dourado no trecho da esquerda, encostando na
     divisa da sidebar. É a mesma costura que liga a barra ao conteúdo — o
     dourado atravessa a quina em vez de parar nela;
   · quando a página desce, a faixa ganha sombra (classe `.rolou`, posta
     pelo app.js). Uma barra fixa sem sombra sobre conteúdo que passa por
     baixo dela parece um pedaço da página que ficou preso.
   --------------------------------------------------------------------- */
header.app-top{
  position:relative;
  background:color-mix(in srgb, var(--superficie) 78%, transparent);
  border-bottom:1px solid var(--linha);
  transition:box-shadow .2s var(--sai), background-color .2s var(--sai);
}
header.app-top::after{
  content:''; position:absolute; left:0; bottom:-1px; height:1px; width:14rem;
  pointer-events:none;
  background:linear-gradient(90deg, rgba(191,155,78,.55), transparent);
}
header.app-top.rolou{
  background:color-mix(in srgb, var(--superficie) 92%, transparent);
  box-shadow:0 1px 0 var(--linha), 0 8px 20px -14px rgba(28,22,10,.5);
}
.dark header.app-top.rolou{ box-shadow:0 1px 0 var(--linha), 0 10px 26px -14px rgba(0,0,0,.85); }

/* A linha da barra. Era `h-16` do Tailwind (altura fixa de 4rem) escrito no
   HTML; virou classe porque no celular ela precisa de DUAS linhas, e altura
   fixa e quebra de linha não convivem. Aqui a altura vira mínima: no desktop
   dá exatamente os mesmos 4rem de antes. */
.top-linha{ min-height:4rem; }
.top-title{ font-size:1.05rem; font-weight:600; letter-spacing:-.01em; }
.top-eyebrow{
  font-size:.6rem; font-weight:700; letter-spacing:.16em; text-transform:uppercase;
  color:var(--tinta-tenue); line-height:1;
}
.top-btn{
  display:grid; place-items:center;
  padding:.45rem; border-radius:var(--r-sm); color:var(--tinta-fraca);
  border:1px solid transparent;
  transition:background .15s var(--sai), color .15s var(--sai), border-color .15s var(--sai);
}
.top-btn:hover{ background:var(--ouro-fraco); color:var(--ouro-escuro); border-color:color-mix(in srgb, var(--ouro) 30%, transparent); }
.top-btn:focus-visible{ outline:2px solid var(--ouro); outline-offset:1px; }
.dark .top-btn:hover{ color:var(--ouro-claro); }

/* ---------------------------------------------------------------------
   O CAMPO DE BUSCA DA BARRA — um alvo, não um enigma

   Era uma lupa de 20px. Uma lupa não diz o que se pode procurar, não
   anuncia que existe um atalho e ocupa a mesma área de um botão de tema —
   ou seja, o caminho mais curto para qualquer coisa no app tinha o mesmo
   destaque que o interruptor de cor.

   Isto é um <button> vestido de campo. Não é um <input> de verdade porque
   ele não digita nada: ele ABRE a paleta de busca. Um input que rouba o
   foco e depois transfere o texto para outro lugar é a receita do cursor
   piscando no campo errado.
   --------------------------------------------------------------------- */
.top-busca{
  display:none; align-items:center; gap:.55rem;
  min-width:16rem; max-width:22rem; padding:.42rem .5rem .42rem .65rem;
  border:1px solid var(--linha-forte); border-radius:var(--r-sm);
  background:var(--superficie); color:var(--tinta-tenue);
  font-size:.8rem; text-align:left; cursor:pointer; box-shadow:var(--e1);
  transition:border-color .15s var(--sai), box-shadow .15s var(--sai), color .15s var(--sai);
}
@media (min-width:900px){ .top-busca{ display:flex; } }
.dark .top-busca{ background:rgba(255,255,255,.04); box-shadow:none; }
.top-busca:hover{ border-color:var(--ouro); color:var(--tinta-fraca); box-shadow:var(--e2); }
.top-busca:focus-visible{ outline:2px solid var(--ouro); outline-offset:1px; }
.top-busca-ico{ width:1rem; height:1rem; flex:0 0 auto; opacity:.8; }
.top-busca-txt{ flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* A tecla desenhada como tecla: fundo recuado, fio embaixo. É o que faz
   "Ctrl K" ser lido como algo para APERTAR e não como mais um rótulo. */
.top-busca-tecla{
  flex:0 0 auto; font-family:inherit; font-size:.62rem; font-weight:650; letter-spacing:.04em;
  padding:.15rem .35rem; border-radius:.3rem; color:var(--tinta-tenue);
  background:var(--superficie-2); border:1px solid var(--linha);
  box-shadow:0 1px 0 var(--linha-forte);
}
.dark .top-busca-tecla{ background:rgba(255,255,255,.06); box-shadow:0 1px 0 rgba(0,0,0,.4); }
/* Abaixo de 900px o campo some e a lupa volta a ser o botão de sempre. */
@media (max-width:899px){
  .top-busca{
    display:grid; place-items:center; min-width:0; max-width:none; width:2.15rem; height:2.15rem;
    padding:0; border-color:transparent; background:transparent; box-shadow:none;
  }
  .top-busca-txt, .top-busca-tecla{ display:none; }
  .top-busca-ico{ width:1.25rem; height:1.25rem; }
}

/* O par sol/lua: um está sempre escondido. Trocar o ícone (e não só a
   cor) é o que diz PARA ONDE o clique leva — no tema claro mostra-se a
   lua, que é o destino, não o sol, que é o estado atual. */
.top-tema .ico-sol, .top-tema .ico-lua{ width:1.2rem; height:1.2rem; }
.top-tema .ico-sol{ display:none; }
.dark .top-tema .ico-sol{ display:block; }
.dark .top-tema .ico-lua{ display:none; }

/* ---------------------------------------------------------------------
   O SELETOR DE COMPETÊNCIA — mês é uma sequência, não uma data qualquer

   Era um `<input type=month>` cru: para ver o mês anterior o usuário
   abria o calendário nativo do sistema, achava a coluna do mês e clicava
   — três gestos para a operação que ele mais repete no app. Agora o campo
   vive entre duas setas, e "mês anterior" é UM clique.

   O grupo se lê como uma peça só (uma borda em volta, o campo sem borda
   própria por dentro), que é o que faz três controles não parecerem três
   controles soltos empilhados na barra. */
.mes-nav{
  display:inline-flex; align-items:stretch;
  border:1px solid var(--linha-forte); border-radius:var(--r-sm);
  background:var(--superficie); box-shadow:var(--e1); overflow:hidden;
}
.dark .mes-nav{ background:#1f2026; box-shadow:none; }
.mes-nav:focus-within{ border-color:var(--ouro); box-shadow:0 0 0 3px rgba(191,155,78,.18); }
.mes-seta{
  flex:0 0 auto; width:1.85rem; display:grid; place-items:center;
  color:var(--tinta-fraca); cursor:pointer;
  transition:background .15s var(--sai), color .15s var(--sai);
}
.mes-seta:hover{ background:var(--ouro-fraco); color:var(--ouro-escuro); }
.dark .mes-seta:hover{ color:var(--ouro-claro); }
.mes-seta svg{ width:.95rem; height:.95rem; }
/* O campo por dentro do grupo perde a moldura própria: a moldura é a do
   grupo. `!important` porque o index.html traz utilitários do Tailwind
   (`!w-auto !py-1.5`) nesse mesmo elemento. */
.mes-nav .field{
  border:0 !important; border-radius:0 !important; box-shadow:none !important;
  background:transparent !important; padding:.4rem .3rem !important;
  font-size:.82rem; font-weight:600; text-align:center; min-width:8.5rem;
}
.mes-nav .field:focus{ box-shadow:none !important; }

/* ---------------------------------------------------------------------
   CARTÃO BASE — o objeto que a tela inteira repete

   Ele era um retângulo branco com fio de 1px e uma sombra tão fraca que
   não chegava a existir. Numa tela de doze cards isso vira um mosaico
   plano: nada está acima de nada, e o olho não tem por onde começar.

   Agora o card é uma PLACA: fio de topo pegando a luz (--brilho), sombra
   em dois tempos (--e1) e a borda de 1px continuando ali para segurar a
   forma onde a sombra não alcança. O conjunto é o que faz a mesma tela
   parecer montada em vez de desenhada.
   --------------------------------------------------------------------- */
.card{
  position:relative;
  background:var(--superficie); border:1px solid var(--linha); border-radius:var(--raio);
  padding:1.15rem 1.3rem; box-shadow:var(--e1), var(--brilho);
  transition:box-shadow .2s var(--sai), border-color .2s var(--sai), transform .2s var(--sai);
}
/* Título de seção dentro do card: um degrau menor e mais firme que o texto,
   com o mesmo aperto de letra dos títulos da tela de acesso. */
.card h3{ font-size:.95rem; font-weight:600; letter-spacing:-.005em; }

/* ---------------------------------------------------------------------
   CABEÇALHO DE CARD — título, contexto e ações na mesma régua

   Cada card resolvia o próprio cabeçalho com um `flex justify-between` no
   `class=`, e por isso nenhum dois ficavam iguais: um tinha a legenda
   colada no título, outro tinha o botão 4px mais alto. Aqui é um objeto:
   sobrancelha opcional (o RECORTE — "agosto/2026", "6 meses"), título, e
   o que dá para fazer, empurrado para a direita.

   O fio embaixo é o que separa o comando do dado. Sem ele o cabeçalho é
   só a primeira linha do conteúdo.
   --------------------------------------------------------------------- */
.card-cab{
  display:flex; align-items:flex-start; gap:.75rem 1rem; flex-wrap:wrap;
  padding-bottom:.8rem; margin-bottom:1rem; border-bottom:1px solid var(--linha);
}
.card-cab-tit{ min-width:0; }
.card-cab .card-cab-tit > h3{ margin:0; }
.card-eyebrow{
  display:block; font-size:.62rem; font-weight:700; letter-spacing:.14em;
  text-transform:uppercase; color:var(--tinta-tenue); margin-bottom:.25rem;
}
.card-cab-acoes{ margin-left:auto; display:flex; align-items:center; gap:.4rem; flex-wrap:wrap; }
/* Nota de rodapé do card: a régua, a fonte, a ressalva. Cabe embaixo do
   conteúdo, não no título — quem lê isso já leu o número. */
.card-pe{
  margin-top:.85rem; padding-top:.7rem; border-top:1px solid var(--linha);
  font-size:.72rem; line-height:1.45; color:var(--tinta-tenue);
}

/* Card CLICÁVEL (o que leva a outra tela) se levanta sob o cursor. Só ele:
   levantar tudo que tem sombra faz a página inteira tremer à toa. */
.card-int{ cursor:pointer; }
.card-int:hover{ box-shadow:var(--e2), var(--brilho); border-color:var(--linha-forte); transform:translateY(-2px); }
.card-int:focus-visible{ outline:2px solid var(--ouro); outline-offset:2px; }

/* KPI — o número é o assunto: grande, tabular e com um traço de ouro em cima
   do rótulo, que é a assinatura da marca repetida no lugar mais visto. */
.kpi-label{
  font-size:.68rem; text-transform:uppercase; letter-spacing:.1em;
  font-weight:600; color:var(--tinta-fraca);
}
.kpi-label::before{
  content:''; display:block; width:1.5rem; height:2px; border-radius:1px;
  background:var(--ouro); margin-bottom:.55rem;
}
/* O CORPO DO NÚMERO É ELÁSTICO, e tem de ser. Um valor de dinheiro em pt-BR
   ocupa 13 caracteres ("R$ 122.380,00") e o cartão de uma fileira de quatro
   mede ~225px num monitor de 1280 — corpo fixo grande garante que ALGUM
   mês vai estourar a caixa. O clamp deixa o número usar o tamanho cheio
   onde cabe e recuar sozinho onde não cabe, sem nenhum ponto de quebra
   escrito à mão. */
.kpi-value{
  font-size:clamp(1.2rem, .6rem + 1.02vw, 1.8rem);
  font-weight:700; line-height:1.08; letter-spacing:-.025em;
  margin-top:.3rem;
}

/* ---------------------------------------------------------------------
   O TRILHO DO KPI — a assinatura sai do rótulo e vai para a borda

   O traço de ouro de 1,5rem em cima do rótulo era discreto demais para o
   trabalho que tinha: numa fileira de quatro cartões, ele desaparecia. O
   trilho ocupa a largura inteira do topo do cartão — a mesma assinatura,
   no lugar onde o olho entra no objeto — e, o que o traço nunca fez, ele
   CARREGA O SINAL: dourado quando é só um número, verde quando entrou
   dinheiro, vinho quando saiu.

   Repare que a cor do trilho vem do MESMO token da barra do gráfico logo
   abaixo (--g-entrada / --g-saida). O cartão "Receitas" e a coluna
   "Receitas" passam a ser a mesma cor porque leem o mesmo valor.

   `:has()` é o que permite fazer isso sem tocar em uma linha do HTML já
   gerado nas ~40 telas: a regra pergunta ao cartão se ele tem um rótulo
   de KPI dentro. Onde não tiver, nada muda.

   POR QUE O TRILHO É FUNDO E NÃO UM ::before. A primeira versão era um
   pseudo-elemento absoluto, e para ele não escapar das quinas o cartão
   precisava de `overflow:hidden` — que decepou o "R$ 22.380,00" na
   primeira tela de 1280px em que ele foi olhado. Fundo não tem esse
   problema: o navegador já recorta as camadas de background pela curva da
   borda, de graça, e nada mais dentro do cartão fica preso. */
.card:has(> .kpi-label){
  padding-top:1.25rem;
  /* `isolation` cria o contexto de empilhamento do cartão. Sem ele a
     faísca em `z-index:-1` cairia atrás do FUNDO do card (o card é
     `position:relative` mas com z-index automático, que não abre contexto
     nenhum) e simplesmente sumiria. */
  isolation:isolate;
  /* Coluna, para o RODAPÉ DO CARTÃO ANCORAR NA BASE (ver .kpi-pe). Numa
     fileira em que um cartão é mais alto que os outros — o de abertura, ou
     o que ganhou uma nota a mais —, as variações ficavam cada uma numa
     altura diferente e a linha de leitura horizontal se perdia. */
  display:flex; flex-direction:column;
  background-image:linear-gradient(90deg,
    var(--ouro) 0%, var(--ouro-claro) 42%, color-mix(in srgb, var(--ouro-claro) 25%, transparent) 100%);
  background-repeat:no-repeat; background-size:100% 3px; background-position:top left;
}
/* Com o trilho no topo, o tracinho acima do rótulo vira eco: duas marcas
   douradas a 12px uma da outra. Some — mas só DENTRO do cartão; onde o
   rótulo aparece solto (bloco de alertas, aporte a distribuir) ele
   continua sendo a única assinatura que existe. */
.card:has(> .kpi-label) > .kpi-label::before{ display:none; }

/* O sinal do trilho segue o tom do VALOR, que é onde a polaridade já foi
   decidida (tom-entrada/tom-saida vêm do kpiRico). */
.card:has(.kpi-value.tom-entrada){
  background-image:linear-gradient(90deg, var(--g-entrada) 0%,
    color-mix(in srgb, var(--g-entrada) 28%, transparent) 100%);
}
.card:has(.kpi-value.tom-saida){
  background-image:linear-gradient(90deg, var(--g-saida) 0%,
    color-mix(in srgb, var(--g-saida) 28%, transparent) 100%);
}

/* ---------------------------------------------------------------------
   KPI COM JUÍZO — o número, a tendência e o veredicto no mesmo cartão

   O cartão antigo dizia "R$ 9.842,18" e parava. A pergunta que o usuário
   faz não é quanto: é se melhorou. Aqui a resposta cabe em três peças
   que se leem em ordem — valor, faísca (é tendência?), variação nomeada
   ("▲ 12,4% vs julho").

   Os tons de valor vêm dos TOKENS de gráfico, não de `text-emerald-600`:
   assim o cartão "Receitas" e a barra "Receitas" logo abaixo são a mesma
   cor, medida no mesmo lugar. Antes eram dois verdes diferentes, um do
   Tailwind e outro do Chart.js, e ninguém notava porque nunca estavam
   lado a lado — só que estavam.
   --------------------------------------------------------------------- */
/* ---------------------------------------------------------------------
   A FAÍSCA SAI DA LINHA DO NÚMERO E VAI PARA O CANTO

   Ela era um item flex ao lado do valor, e as duas coisas disputavam a
   mesma largura. Numa fileira de quatro cartões a 1024px, o cartão mede
   ~172px e sobram ~130px por dentro: "R$ 22.380,00" quer 175px, a faísca
   quer 72px. O resultado era o número DECEPADO na borda — não em teoria,
   foi assim que ele apareceu na primeira medição.

   Tirando a faísca do fluxo (canto superior direito, atrás do conteúdo),
   o número passa a ter a largura inteira do cartão e a faísca deixa de
   competir por um espaço que não existia. É o mesmo tratamento da onda no
   cartão de abertura: a tendência é FUNDO, o número é o assunto.
   --------------------------------------------------------------------- */
.kpi-linha{ display:block; }
/* O valor não quebra linha: um número de dinheiro partido ao meio ("R$
   4.610," numa linha e "91" noutra) é ilegível. */
.kpi-linha .kpi-value{ min-width:0; white-space:nowrap; }
.kpi-sufixo{
  font-size:.85rem; font-weight:600; letter-spacing:0;
  color:var(--tinta-tenue); margin-left:.2rem; white-space:nowrap;
}
/* A faísca herda a cor do valor (currentColor no SVG) e fica de propósito
   apagada: ela é contexto, não protagonista. */
.kpi-spark{
  position:absolute; top:1.2rem; right:1.2rem; z-index:-1;
  opacity:.8; line-height:0; pointer-events:none;
}
.kpi-faisca{ display:block; overflow:visible; }

.tom-entrada{ color:var(--g-entrada); }
.tom-saida{ color:var(--g-saida); }

.kpi-pe{
  display:flex; align-items:center; flex-wrap:wrap; gap:.4rem;
  margin-top:auto; padding-top:.7rem; font-size:.72rem; line-height:1.25;
}
/* A VARIAÇÃO VIRA PÍLULA. Como texto colorido solto ela se confundia com
   o rodapé cinza ao lado — dois textos de 11px, um do lado do outro, e o
   que importa era o primeiro. O fundo tingido (14% da própria cor) a
   destaca sem precisar aumentar o corpo nem gritar em negrito.

   O tingimento sai da MESMA cor do texto via color-mix: não há um segundo
   hex para manter em dia quando o verde mudar, e o tema escuro acerta
   sozinho porque --g-bom já é outro lá. */
.kpi-delta{
  display:inline-flex; align-items:center; gap:.22rem; font-weight:650;
  padding:.12rem .45rem; border-radius:999px; line-height:1.4;
}
/* A seta é menor que o número e não some no zoom: é reforço do sinal, não
   a informação. Quem não distingue a cor lê a direção na seta e o valor
   no texto ao lado — nunca só na cor. */
.kpi-seta{ font-size:.6em; line-height:1; transform:translateY(-.05em); }
.delta-bom  { color:var(--g-bom);     background:color-mix(in srgb, var(--g-bom) 14%, transparent); }
.delta-ruim { color:var(--g-critico); background:color-mix(in srgb, var(--g-critico) 14%, transparent); }
.delta-neutro{ color:var(--tinta-tenue); background:color-mix(in srgb, var(--tinta-tenue) 12%, transparent); }
/* No escuro o mesmo 14% quase não aparece sobre grafite: sobe para 22%. */
.dark .delta-bom  { background:color-mix(in srgb, var(--g-bom) 22%, transparent); }
.dark .delta-ruim { background:color-mix(in srgb, var(--g-critico) 22%, transparent); }
.dark .delta-neutro{ background:rgba(255,255,255,.08); }
.kpi-comp, .kpi-nota{ color:var(--tinta-tenue); font-weight:500; }

/* ---------------------------------------------------------------------
   O CARTÃO PRINCIPAL — um número manda na tela, os outros a apoiam

   Quatro cartões idênticos lado a lado não têm hierarquia: o olho não sabe
   onde começar e acaba lendo da esquerda para a direita, que é a ordem do
   código, não a da importância. O primeiro cartão do painel passa a ser o
   PAINEL DE ABERTURA — grafite com o dourado da marca, do tamanho de dois,
   com o resultado do mês em corpo grande e a série do semestre desenhada
   atrás dele.

   É o mesmo material do menu lateral e do painel de acesso. A tela deixa
   de começar em branco: ela começa na marca.
   --------------------------------------------------------------------- */
.kpi-hero{
  position:relative; overflow:hidden; isolation:isolate;
  border:1px solid rgba(191,155,78,.28); border-radius:var(--raio);
  padding:1.35rem 1.5rem 1.25rem;
  background:radial-gradient(125% 130% at 8% 0%, #2a2a33 0%, #1c1c23 46%, #101014 100%);
  color:#f1efea; box-shadow:var(--e2);
  display:flex; flex-direction:column; min-height:11.5rem;
}
/* No tema escuro o cartão de abertura é grafite sobre grafite: a diferença
   de superfície que separava os dois no papel branco praticamente some, e
   o cartão que deveria mandar na tela vira só mais um retângulo. Quem faz
   a separação ali é a BORDA — mais dourada — e um halo de ouro difuso em
   volta, que é o mesmo recurso que o botão primário usa. */
.dark .kpi-hero{
  border-color:rgba(191,155,78,.40);
  box-shadow:var(--e2), 0 0 34px -12px rgba(191,155,78,.28);
}
/* A mesma trama gravada do painel de acesso, no mesmo ângulo. É o detalhe
   que faz o cartão pertencer à tela de login em vez de ser um retângulo
   preto qualquer. */
.kpi-hero::before{
  content:''; position:absolute; inset:0; z-index:-1; pointer-events:none; opacity:.55;
  background:
    repeating-linear-gradient(115deg, rgba(191,155,78,.075) 0 1px, transparent 1px 14px),
    repeating-linear-gradient(65deg,  rgba(255,255,255,.035) 0 1px, transparent 1px 24px);
  -webkit-mask-image:radial-gradient(85% 80% at 20% 15%, #000 20%, transparent 88%);
          mask-image:radial-gradient(85% 80% at 20% 15%, #000 20%, transparent 88%);
}
/* Bafo dourado no canto oposto ao texto — a luz vem de onde o número não
   está, senão ela lava justamente o que se quer ler. */
.kpi-hero::after{
  content:''; position:absolute; z-index:-1; right:-18%; bottom:-42%;
  width:32rem; height:32rem; pointer-events:none;
  background:radial-gradient(circle, rgba(191,155,78,.24) 0%, rgba(191,155,78,.07) 40%, transparent 70%);
}
.kpi-hero-label{
  font-size:.68rem; font-weight:700; letter-spacing:.14em; text-transform:uppercase;
  color:var(--ouro-claro);
}
.kpi-hero-label::before{
  content:''; display:block; width:2.25rem; height:2px; border-radius:1px;
  background:var(--ouro); margin-bottom:.6rem;
}
/* O número não quebra NUNCA; o qualificador ao lado dele quebra sempre que
   precisar. `white-space:nowrap` no contêiner protege o valor (que é um nó
   de texto solto, sem elemento próprio onde pendurar a regra) e
   `flex-wrap:wrap` deixa o sufixo cair para a linha de baixo em vez de ser
   decepado — que foi o que aconteceu com "39,8% da receita" a 1024px. */
.kpi-hero-valor{
  display:flex; flex-wrap:wrap; align-items:baseline; column-gap:.55rem;
  font-size:clamp(1.9rem, 1.1rem + 2vw, 2.9rem);
  font-weight:700; line-height:1.05; letter-spacing:-.035em;
  margin-top:.55rem; color:#fff; font-variant-numeric:tabular-nums; white-space:nowrap;
}
.kpi-hero-sufixo{
  font-size:.95rem; font-weight:600; letter-spacing:0; color:var(--ouro-claro);
}
.kpi-hero-pe{
  display:flex; align-items:center; flex-wrap:wrap; gap:.5rem;
  margin-top:.7rem; font-size:.76rem;
}
/* No grafite os tons claros dos tokens perdem contraste; a pílula do herói
   usa os passos do tema escuro e um fundo mais opaco. */
.kpi-hero .kpi-delta{ padding:.18rem .55rem; font-size:.76rem; }
.kpi-hero .delta-bom  { color:#7fc98d; background:rgba(104,178,116,.20); }
.kpi-hero .delta-ruim { color:#e08b86; background:rgba(155,68,64,.28); }
.kpi-hero .delta-neutro{ color:#b6b2a9; background:rgba(255,255,255,.09); }
.kpi-hero .kpi-comp, .kpi-hero .kpi-nota{ color:#a5a099; }
/* A série do semestre desenhada rente ao pé do cartão: contexto sem
   ocupar uma linha de texto. Fica atrás do conteúdo (z-index) e não
   captura clique. */
/* A onda é TEXTURA, não desenho: o traço passa por trás dos rótulos do pé
   ("entrou", "saiu", "em caixa"), e a 55% de opacidade ele cortava as
   palavras ao meio. A máscara vertical apaga a onda justamente na faixa
   onde os rótulos vivem e a deixa cheia embaixo, onde não há texto —
   assim ela continua dando a tendência sem disputar a leitura. */
.kpi-hero-onda{
  position:absolute; left:0; right:0; bottom:0; height:4.75rem; z-index:-1;
  pointer-events:none; opacity:.5;
  -webkit-mask-image:linear-gradient(180deg, transparent 0%, #000 55%, #000 100%);
          mask-image:linear-gradient(180deg, transparent 0%, #000 55%, #000 100%);
}
.kpi-hero-onda svg{ width:100%; height:100%; display:block; }
/* Fileira de números miúdos no pé do herói (o que compõe o resultado). */
.kpi-hero-linhas{
  display:flex; flex-wrap:wrap; gap:.35rem 1.5rem; margin-top:auto; padding-top:1rem;
}
.kpi-hero-item{ min-width:0; }
.kpi-hero-item b{
  display:block; font-size:.95rem; font-weight:650; color:#fff;
  font-variant-numeric:tabular-nums; letter-spacing:-.01em;
}
.kpi-hero-item span{
  display:block; font-size:.62rem; letter-spacing:.12em; text-transform:uppercase;
  color:#8d8981; margin-top:.1rem;
}

/* ---------------------------------------------------------------------
   ABAS DE TELA — a tira que não pula de altura

   Eram botões soltos num `flex-wrap` dentro de um card. Dois defeitos que
   se viam a olho nu: um rótulo comprido ("Balanço Patrimonial") quebrava
   em duas linhas e a tira inteira dobrava de altura — a página pulava ao
   trocar de aba —, e a aba ativa era um BLOCO dourado sólido, que pesava
   mais na tela do que o relatório embaixo dela.

   Agora: linha única que ROLA na horizontal (altura constante, nada fica
   inalcançável) e a ativa marcada por um traço de ouro embaixo. A aba é
   navegação; quem tem de pesar é o conteúdo.
   --------------------------------------------------------------------- */
.abas{
  display:flex; gap:.15rem; margin-bottom:1rem;
  border-bottom:1px solid var(--linha);
  overflow-x:auto; scrollbar-width:none;
}
.abas::-webkit-scrollbar{ display:none; }
.aba{
  flex:0 0 auto; position:relative; white-space:nowrap;
  padding:.6rem .85rem; border:0; background:transparent; cursor:pointer;
  font-size:.875rem; font-weight:500; color:var(--tinta-fraca);
  border-radius:.5rem .5rem 0 0; transition:color .15s, background-color .15s;
}
.aba:hover{ color:var(--tinta); background:var(--superficie-2); }
.aba:focus-visible{ outline:2px solid var(--ouro); outline-offset:-2px; }
.aba.ativa{ color:var(--tinta); font-weight:650; }
/* O traço fica 1px ABAIXO da borda do contêiner (bottom:-1px) para cobri-la:
   sem isso o fio cinza atravessa a marca da aba ativa. */
.aba.ativa::after{
  content:''; position:absolute; left:.6rem; right:.6rem; bottom:-1px; height:2px;
  background:var(--ouro); border-radius:1px;
}

/* ---- A tira que rola precisa DIZER que rola --------------------------
   Medido a 375px: "Lançamentos" tem 5 sub-abas e 2 ficavam fora da tela;
   "Investimentos" e "Relatórios", 3 de 6. Como a barra de rolagem está
   escondida (`scrollbar-width:none`, e no toque ela nem existe), não havia
   NENHUM sinal de que houvesse mais coisa — "Cartões", "Contas a pagar" e
   "Contas a receber" simplesmente não existiam para quem só olha.

   O aviso é a própria tira desbotando na beirada em que ainda há aba. As
   classes vêm do app.js (`pintarRolagem`), medidas de verdade: sem elas o
   desbote apareceria também quando não há para onde rolar, que é pior do
   que não ter aviso nenhum — passaria a mentir. */
.abas{ scroll-behavior:smooth; }
.abas.tem-dir{
  -webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 2.75rem),transparent);
          mask-image:linear-gradient(90deg,#000 calc(100% - 2.75rem),transparent);
}
.abas.tem-esq{
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 2.75rem);
          mask-image:linear-gradient(90deg,transparent,#000 2.75rem);
}
.abas.tem-esq.tem-dir{
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 2.75rem,#000 calc(100% - 2.75rem),transparent);
          mask-image:linear-gradient(90deg,transparent,#000 2.75rem,#000 calc(100% - 2.75rem),transparent);
}
@media (prefers-reduced-motion:reduce){ .abas{ scroll-behavior:auto; } }

/* Faixa de apoio: o que se está vendo à esquerda, o que dá para fazer à
   direita. Fina de propósito — ela serve o relatório, não compete com ele. */
.barra-apoio{
  display:flex; align-items:center; flex-wrap:wrap; gap:.5rem .75rem;
  margin-bottom:1rem; padding:.15rem .1rem;
  font-size:.8rem; color:var(--tinta-fraca);
}
.barra-recorte{ font-weight:550; color:var(--tinta); }
.barra-check{ display:flex; align-items:center; gap:.35rem; font-size:.75rem; cursor:pointer; }
.barra-acoes{ margin-left:auto; display:flex; align-items:center; gap:.3rem; flex-wrap:wrap; }
.barra-rotulo{ font-size:.7rem; text-transform:uppercase; letter-spacing:.08em; color:var(--tinta-tenue); }

/* Tabela.
   NÃO renomear para `.grid`: é uma utilidade do Tailwind (`display:grid`), e
   ela vencia estas regras — a tabela virava container grid, thead e tbody
   viravam blocos independentes e cada um calculava suas próprias larguras de
   coluna. Resultado: o cabeçalho nunca alinhava com os valores. */
table.tbl{ width:100%; border-collapse:collapse; font-size:.875rem; }
/* Cabeçalho em versalete: lido como rótulo, não como mais uma linha de dado —
   é o mesmo tratamento do rótulo de campo da tela de acesso. */
table.tbl th{
  text-align:left; font-weight:600; color:var(--tinta-fraca);
  font-size:.68rem; text-transform:uppercase; letter-spacing:.08em;
  padding:.5rem .75rem; border-bottom:1px solid var(--linha); white-space:nowrap;
  vertical-align:middle;
}
/* ---------------------------------------------------------------------
   O CABEÇALHO DA TABELA — e por que ele NÃO é `sticky`

   A tentação era prender o rótulo no topo: num razão de cem linhas, rolar
   trinta apaga o cabeçalho e a terceira coluna numérica fica sem nome.
   Foi tentado, e não funciona nesta casca — está escrito aqui para não
   ser tentado uma segunda vez.

   Quem rola no app é o <main>, mas quase toda tabela está dentro de um
   `.overflow-x-auto` que rola na horizontal. Um contêiner com overflow em
   um eixo vira SCROLLPORT nos dois, e é a ele que o `sticky` obedece —
   não ao <main>. Como esse contêiner tem exatamente a altura da tabela,
   não há nada de onde o cabeçalho descolar: com `top:0` ele fica parado
   (inofensivo, e inútil), e com `top:4rem` — a altura da topbar, posta
   para ele não encostar atrás dela — o navegador o EMPURRA 64px para
   baixo, porque o deslocamento de um sticky num contêiner não rolado é
   `top` puro. O cabeçalho desce e vai cobrir a primeira linha. Foi
   exatamente o que apareceu na tela de Lançamentos.

   Prender de verdade exigiria dar altura fixa e rolagem vertical própria
   ao contêiner de cada tabela — outra decisão, com outros custos (a
   página passa a ter dois rolamentos aninhados). Até lá, o cabeçalho é
   estático e o que ele ganha é PESO: fundo próprio e um fio firme
   embaixo, para se ler como rótulo mesmo sem acompanhar a rolagem. */
table.tbl thead th{
  background:var(--superficie);
  border-bottom:1px solid var(--linha-forte);
}
/* A faixa de filtro e o cabeçalho de tabela são o mesmo registro visual —
   "isto não é dado, é onde o dado se organiza". */
table.tbl.tbl-faixa thead th{ background:var(--superficie-2); }
.dark table.tbl.tbl-faixa thead th{ background:#1e1f25; }

table.tbl td{
  padding:.62rem .75rem; border-bottom:1px solid var(--linha); vertical-align:middle;
}
table.tbl tbody tr:last-child td{ border-bottom:0; }

/* ---------------------------------------------------------------------
   A LINHA SOB O CURSOR — um trilho, não só um cinza

   O realce era um cinza 2% de diferença: em tabela de sete colunas, o olho
   perde a linha entre a data (esquerda) e o valor (direita) mesmo com ele
   ligado. Agora a linha mirada ganha um FIO DOURADO na margem esquerda,
   que é uma âncora — e o cinza continua, mais firme, para o corpo.

   O fio é `box-shadow:inset` na primeira célula em vez de `border-left`:
   borda muda a largura da coluna e faz a tabela inteira dar um pulo de
   3px a cada linha que o mouse atravessa. */
table.tbl tbody tr{ transition:background-color .12s var(--sai); }
table.tbl tbody tr:hover > td:first-child{ box-shadow:inset 2px 0 0 var(--ouro); }
.dark table.tbl tbody tr:hover > td:first-child{ box-shadow:inset 2px 0 0 var(--ouro-claro); }

/* ---------------------------------------------------------------------
   LINHA DE TOTAL — o número que fecha a conta não é mais uma linha

   Nos relatórios (DRE, balanço, fluxo) o total vinha em <b>, do mesmo
   tamanho e no mesmo cinza dos itens: quem varria a coluna passava reto
   por ele. Aqui ele ganha fundo, um fio grosso em cima (o traço de soma
   do papel quadriculado) e nenhuma borda embaixo — porque não há nada
   depois de um total. */
table.tbl tr.tbl-total > td{
  background:var(--superficie-2); font-weight:700; color:var(--tinta);
  border-bottom:0; border-top:2px solid var(--linha-forte);
  padding-top:.72rem; padding-bottom:.72rem;
}
.dark table.tbl tr.tbl-total > td{ background:rgba(255,255,255,.045); }
table.tbl tr.tbl-total:hover > td{ background:var(--superficie-2); }
.dark table.tbl tr.tbl-total:hover > td{ background:rgba(255,255,255,.045); }
/* Subtotal de grupo: o mesmo papel, meio degrau abaixo. */
table.tbl tr.tbl-grupo > td{
  background:color-mix(in srgb, var(--superficie-2) 65%, var(--superficie));
  font-weight:650;
}
.dark table.tbl tr.tbl-grupo > td{ background:rgba(255,255,255,.025); }
/* `table.tbl th` (0,1,2) vence o `.text-right` do Tailwind (0,1,0) — sem
   estas linhas o rótulo de uma coluna numérica fica à esquerda enquanto os
   valores vão à direita. Reabilita as utilidades de alinhamento na tabela. */
/* Valor não quebra linha: "R$" numa linha e "1.240,90" na outra é o jeito mais
   rápido de uma coluna de dinheiro deixar de ser lida como coluna. */
table.tbl th.text-right,  table.tbl td.text-right { text-align:right; white-space:nowrap; }
table.tbl th.text-center, table.tbl td.text-center{ text-align:center; }
table.tbl th.text-left,   table.tbl td.text-left  { text-align:left; }
table.tbl tbody tr:hover{ background:var(--superficie-2); }
.dark table.tbl tbody tr:hover{ background:rgba(255,255,255,.03); }

/* ---------------------------------------------------------------------
   A LINHA DO RAZÃO — densidade é função, não estética

   Um razão em que não cabe o mês inteiro obriga a rolar para responder
   qualquer pergunta ("quanto gastei com mercado?"), e rolar apaga a
   comparação que a pessoa estava fazendo de cabeça. As regras abaixo
   servem a uma medida só: quantos lançamentos cabem sem rolar.

   Código monoespaçado e nome na MESMA linha; o caminho do grupo virou
   `title`. O código fica em versalete-tenue de propósito: ele é a chave,
   e quem varre a coluna está lendo o NOME. Quem procura pelo código o
   encontra pela forma (é o único monoespaçado da linha).
   --------------------------------------------------------------------- */
/* `fixed` é o que dá a última palavra sobre a largura: com `auto` o
   navegador mede o conteúdo e devolve a coluna mais larga para quem tem o
   texto mais comprido — que aqui era o código da conta, não o histórico. */
/* O PISO DE LARGURA não é detalhe: com `table-layout:fixed`, se as colunas
   de medida absoluta somarem mais que a tabela, o que sobra para as
   flexíveis é ZERO — e a coluna de Histórico literalmente desaparece.
   Foi o que aconteceu num painel de 560px. Sete colunas de razão pedem
   ~52rem; abaixo disso a tabela ROLA (o contêiner já tem overflow-x),
   que é o mesmo trato que ela já faz no celular. */
table.tbl-razao{ table-layout:fixed; min-width:56rem; }
/* As fixas somam ~30rem; o que sobra é repartido entre Histórico e Conta,
   com o Histórico levando a maior parte — é a coluna que se lê. */
table.tbl-razao .c-data{ width:5.75rem; }
table.tbl-razao .c-hist{ width:auto; }
table.tbl-razao .c-conta{ width:19%; }
table.tbl-razao .c-cart{ width:7.5rem; }
table.tbl-razao .c-val{ width:6.75rem; }
table.tbl-razao .c-acoes{ width:3.75rem; }
/* A coluna de valor único do celular não existe aqui — e some de verdade
   (`display:none`), não só de largura: com `table-layout:fixed` uma coluna
   sem largura declarada ainda reparte o que sobra. */
table.tbl-razao .c-mob{ display:none; }
/* O status vive DENTRO do histórico agora — pequeno, e depois do texto. */
.pill-inline{ margin-left:.4rem; font-size:.62rem; vertical-align:.06em; }
/* Texto que não cabe vira reticências, não uma segunda linha: a altura da
   linha é o recurso escasso aqui, e o valor inteiro está no `title`. */
table.tbl-razao td.cel-hist, table.tbl-razao td.cel-fraca{
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}

.cel-conta{ display:flex; align-items:baseline; gap:.4rem; min-width:0; }
.cel-cod{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:.72rem; color:var(--tinta-tenue); flex:0 0 auto;
}
.cel-nome{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.cel-data{ color:var(--tinta-fraca); font-variant-numeric:tabular-nums; }
.cel-hist{ font-weight:550; }
.cel-fraca{ color:var(--tinta-fraca); }

/* Os ícones de ação só aparecem na linha sob o cursor. Duas colunas de
   ✎ e 🗑 repetidas em vinte linhas viram um padrão visual que compete com
   o dado — e ninguém procura o lápis antes de escolher a linha.
   Em toque não há cursor: lá eles ficam sempre visíveis (ver bloco CELULAR). */
.cel-acoes{ white-space:nowrap; }
.btn-icone{
  color:var(--tinta-tenue); background:transparent; border:0; cursor:pointer;
  padding:.15rem .3rem; border-radius:.35rem; line-height:1;
  opacity:0; transition:opacity .12s, color .12s, background-color .12s;
}
tr:hover .btn-icone, .btn-icone:focus-visible{ opacity:1; }
.btn-icone:hover{ color:var(--ouro-escuro); background:var(--ouro-fraco); }
.btn-icone-perigo:hover{ color:var(--g-critico); background:transparent; }
.btn-icone:focus-visible{ outline:2px solid var(--ouro); outline-offset:1px; }
.dark .btn-icone:hover{ color:var(--ouro-claro); }

/* ---------------------------------------------------------------------
   PÍLULAS DE STATUS — a última cor solta do app

   Os cinco fundos vinham do paletão do Tailwind (#dcfce7, #fef3c7…) e
   eram, depois do trabalho nos gráficos, a última cor do app escolhida
   fora do sistema. Na prática isso significava um verde na pílula
   "liquidado" e OUTRO verde na barra "Receitas" a 200px de distância, na
   mesma tela — ninguém aponta o dedo, todo mundo sente.

   Agora as cinco saem dos tokens medidos, por color-mix: fundo é a
   própria cor a 14%, o texto é a cor cheia, e o contorno de 1px é o que
   segura a forma quando o fundo é fraco assim. Como os tokens já mudam no
   tema escuro, as pílulas acertam o escuro sozinhas — as dez linhas de
   `.dark .pill-*` que existiam aqui deixaram de ser necessárias.

   A ANATOMIA também mudou: `inline-flex` com um ponto na frente. Status é
   informação categórica, e categoria transmitida só por matiz é
   invisível para uma parte dos leitores; o ponto não resolve sozinho (o
   texto é que resolve), mas dá a forma que a cor sozinha não dá. */
.pill{
  display:inline-flex; align-items:center; gap:.32rem;
  padding:.1rem .5rem .1rem .42rem; border-radius:999px;
  font-size:.7rem; font-weight:650; letter-spacing:.01em; line-height:1.5;
  border:1px solid transparent;
}
.pill::before{
  content:''; width:.36rem; height:.36rem; border-radius:999px;
  background:currentColor; flex:0 0 auto; opacity:.9;
}
.pill-green{ color:var(--g-bom);     background:color-mix(in srgb, var(--g-bom) 14%, transparent);     border-color:color-mix(in srgb, var(--g-bom) 30%, transparent); }
.pill-amber{ color:var(--g-atencao); background:color-mix(in srgb, var(--g-atencao) 14%, transparent); border-color:color-mix(in srgb, var(--g-atencao) 30%, transparent); }
.pill-red  { color:var(--g-critico); background:color-mix(in srgb, var(--g-critico) 14%, transparent); border-color:color-mix(in srgb, var(--g-critico) 30%, transparent); }
.pill-blue { color:var(--g-cat-3);   background:color-mix(in srgb, var(--g-cat-3) 14%, transparent);   border-color:color-mix(in srgb, var(--g-cat-3) 30%, transparent); }
.pill-gray { color:var(--tinta-fraca); background:color-mix(in srgb, var(--tinta-fraca) 12%, transparent); border-color:var(--linha-forte); }
/* No grafite o mesmo 14% quase não se vê: o fundo sobe para 22% e o
   contorno para 45%. As MATIZES não mudam aqui — quem já as trocou foi o
   bloco html.dark lá em cima, uma vez, para o app inteiro. */
.dark .pill-green{ background:color-mix(in srgb, var(--g-bom) 22%, transparent);     border-color:color-mix(in srgb, var(--g-bom) 45%, transparent); }
.dark .pill-amber{ background:color-mix(in srgb, var(--g-atencao) 22%, transparent); border-color:color-mix(in srgb, var(--g-atencao) 45%, transparent); }
.dark .pill-red  { background:color-mix(in srgb, var(--g-critico) 22%, transparent); border-color:color-mix(in srgb, var(--g-critico) 45%, transparent); }
.dark .pill-blue { background:color-mix(in srgb, var(--g-cat-3) 22%, transparent);   border-color:color-mix(in srgb, var(--g-cat-3) 45%, transparent); }
.dark .pill-gray { background:rgba(255,255,255,.09); color:#cbd5e1; border-color:rgba(255,255,255,.14); }

/* ---------------------------------------------------------------------
   TOAST — a confirmação que não interrompe

   Era um retângulo escuro com o texto dentro, aparecendo e sumindo sem
   transição. Agora: entra deslizando de baixo, traz um fio dourado na
   borda esquerda (a marca assina o que ela confirma) e sai sozinho. Os
   estados de erro e de acerto trocam esse fio — a única cor da peça.
   --------------------------------------------------------------------- */
.toast{
  position:fixed; right:1.25rem; bottom:1.25rem; z-index:70;
  display:flex; align-items:center; gap:.6rem;
  max-width:min(26rem, calc(100vw - 2.5rem));
  padding:.7rem .95rem .7rem .85rem;
  background:#1c1c22; color:#f1efea;
  border:1px solid rgba(255,255,255,.1); border-left:3px solid var(--ouro);
  border-radius:var(--r-sm); box-shadow:var(--e3);
  font-size:.82rem; line-height:1.4;
  animation:toast-entra .26s var(--mola) both;
}
@keyframes toast-entra{
  from{ opacity:0; transform:translateY(.75rem) scale(.97); }
  to  { opacity:1; transform:none; }
}
.toast.erro { border-left-color:var(--g-critico); }
.toast.certo{ border-left-color:var(--g-bom); }

/* Inputs padrão dos formulários — o mesmo campo da tela de acesso: borda de
   1px, foco em anel dourado (box-shadow, que acompanha o raio) e rótulo em
   versalete. Dois formulários com aparências diferentes no mesmo app é o tipo
   de detalhe que faz o conjunto parecer remendado. */
.field{
  width:100%; padding:.55rem .75rem; font-size:.875rem;
  border:1px solid var(--linha-forte); border-radius:var(--r-sm);
  background:var(--superficie); color:var(--tinta); outline:none;
  transition:border-color .15s var(--sai), box-shadow .15s var(--sai), background-color .15s var(--sai);
}
.dark .field{ background:#1f2026; }
.field:hover:not(:focus):not(:disabled){ border-color:var(--ouro-escuro); }
.field:focus{ border-color:var(--ouro); box-shadow:0 0 0 3px rgba(191,155,78,.18); }
/* Campo desabilitado tem de PARECER desabilitado antes do clique: fundo
   recuado e cursor de barrado, não só o texto pálido. */
.field:disabled{ background:var(--superficie-2); color:var(--tinta-tenue); cursor:not-allowed; }
.dark .field:disabled{ background:rgba(255,255,255,.03); }
/* Campo que o app recusou. O anel vermelho precisa existir junto com a
   mensagem — cor sozinha não conta para quem não a distingue. */
.field.invalido{ border-color:var(--g-critico); }
.field.invalido:focus{ box-shadow:0 0 0 3px color-mix(in srgb, var(--g-critico) 22%, transparent); }
.lbl{
  font-size:.68rem; font-weight:600; letter-spacing:.08em; text-transform:uppercase;
  color:var(--tinta-fraca); margin-bottom:.35rem; display:block;
}

/* Combobox com busca (contas e carteiras do lançamento) */
.combo{ position:relative; }
.combo-input{ padding-right:2rem; }
.combo-clear{
  position:absolute; right:.5rem; top:50%; transform:translateY(-50%);
  color:#94a3b8; font-size:.8rem; line-height:1; padding:.15rem;
}
.combo-clear:hover{ color:#475569; }
.dark .combo-clear:hover{ color:#e2e8f0; }
.combo-pop{
  position:absolute; z-index:60; left:0; right:0; top:calc(100% + .3rem);
  max-height:16rem; overflow-y:auto;
  background:var(--superficie); border:1px solid var(--linha-forte); border-radius:.6rem;
  box-shadow:0 12px 32px rgba(17,16,12,.14);
}
.dark .combo-pop{ background:#1f2026; box-shadow:0 12px 32px rgba(0,0,0,.55); }
.combo-head{
  padding:.35rem .7rem; font-size:.62rem; font-weight:700; text-transform:uppercase;
  letter-spacing:.12em; color:var(--tinta-tenue); background:var(--superficie-2);
  position:sticky; top:0;
}
.dark .combo-head{ background:#17171b; }
.combo-opt{
  display:flex; align-items:center; justify-content:space-between; gap:.6rem;
  padding:.42rem .7rem; font-size:.875rem; cursor:pointer;
}
.combo-opt.is-active{ background:var(--ouro-fraco); }
.dark .combo-opt.is-active{ background:rgba(191,155,78,.20); }
.combo-code{ font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:.78rem; color:var(--tinta-fraca); }
.combo-sub{ font-size:.72rem; color:var(--tinta-tenue); }
.combo-empty{ padding:.6rem .7rem; font-size:.8rem; color:var(--tinta-tenue); }

/* ---------------------------------------------------------------------
   CHIPS DOS FILTROS ATIVOS — o alvo é o ✕, não a pílula inteira

   O chip inteiro era clicável e o ✕ era só um desenho de 0,65rem com 60%
   de opacidade. Duas consequências: ninguém sabia que dava para remover
   (nada parecia botão), e quem passava o mouse para LER o filtro
   removia-o sem querer. Agora o ✕ é um alvo redondo de verdade, que
   acende ao ser mirado — e o resto do chip continua clicável, porque
   quem já aprendeu o gesto antigo não pode perdê-lo.

   O corpo também subiu de 0,15rem para 0,3rem de respiro vertical: a
   pílula era mais fina que a linha de texto ao lado dela e lia como
   etiqueta impressa, não como controle. */
.chip{
  display:inline-flex; align-items:center; gap:.4rem;
  padding:.28rem .3rem .28rem .65rem; border-radius:999px;
  font-size:.72rem; font-weight:550; cursor:pointer; line-height:1.3;
  background:linear-gradient(180deg,#fdfaf1,#f7f1e0); color:#7c611f;
  border:1px solid #e6d296; box-shadow:0 1px 1px rgba(140,108,32,.06);
  transition:border-color .15s var(--sai), box-shadow .15s var(--sai), background .15s var(--sai);
}
.chip:hover{ border-color:var(--ouro); box-shadow:0 1px 3px rgba(140,108,32,.16); }
.dark .chip{
  background:rgba(191,155,78,.16); color:#e6cf8f;
  border-color:rgba(191,155,78,.42); box-shadow:none;
}
.dark .chip:hover{ background:rgba(191,155,78,.26); border-color:var(--ouro-claro); }
.chip-x{
  flex:0 0 auto; display:grid; place-items:center;
  width:1.15rem; height:1.15rem; border-radius:999px;
  font-size:.66rem; line-height:1; opacity:.55;
  transition:opacity .12s, background-color .12s, color .12s;
}
.chip:hover .chip-x{ opacity:.85; background:rgba(140,108,32,.12); }
.chip .chip-x:hover{ opacity:1; background:var(--g-critico); color:#fff; }
.dark .chip:hover .chip-x{ background:rgba(255,255,255,.12); }

/* ----------------------------------------------------------------------
   Barra de filtros padronizada. Todo bloco de filtros do app usa `.card
   .filterbar`: um fundo levemente destacado do conteúdo, para o olho saber
   na hora "aqui eu filtro". A busca ganha `.field-search` (lupa à esquerda) e
   os filtros ativos aparecem como `.chip` com um "Limpar" ao lado — mesmo
   modelo em Lançamentos, A pagar/receber, Plano de contas, Conciliação e
   Operações, para não ter cada tela com um jeito diferente. */
/* A FAIXA DE FILTRO É CÔNCAVA, o card é convexo.

   Antes ela era um card levemente mais escuro — e um card mais escuro
   continua parecendo que está POR CIMA da página. Só que filtro não é
   conteúdo: é a bancada onde o conteúdo é preparado. Invertendo a luz
   (sombra para DENTRO, sem realce de topo) ela afunda, e a tabela logo
   abaixo passa a ser a única coisa levantada da tela.

   É um recurso de meio pixel que ninguém nota conscientemente e que
   resolve sozinho a pergunta "onde eu filtro / onde eu leio". */
.filterbar{
  background:var(--superficie-2);
  border-color:var(--linha);
  box-shadow:inset 0 1px 2px rgba(28,22,10,.045);
}
.dark .filterbar{
  background:rgba(0,0,0,.22);
  box-shadow:inset 0 1px 3px rgba(0,0,0,.4);
}
/* A faixa de filtro é MEIO: ela existe para chegar na tabela. Aperta o
   respiro dela e a tabela ganha três lançamentos a mais sem rolagem. */
.filterbar{ padding:.85rem 1rem; }
.filterbar .lbl{ margin-bottom:.25rem; font-size:.64rem; }
/* Dentro da bancada o campo é o que está por cima: ele volta ao branco
   do card e ganha a sombrinha de contato que a faixa perdeu. */
.filterbar .field{ background:var(--superficie); box-shadow:var(--e1); }
.dark .filterbar .field{ background:#1f2026; box-shadow:none; }

/* ---------------------------------------------------------------------
   CARTÃO DE PRIMEIROS PASSOS — a primeira tela que alguém vê

   O anterior eram três caixas lado a lado de altura desigual, com o passo
   já cumprido RISCADO. Riscar diz "cancelado"; o que houve foi o oposto.
   Aqui o passo pronto apenas recua (opacidade + tique), a lista é vertical
   (rótulo nenhum quebra no meio) e existe uma barra de progresso — que é o
   que responde a pergunta que o cartão levanta: falta muito?
   --------------------------------------------------------------------- */
.cartao-inicio{ border-color:var(--ouro-fraco); }
.inicio-topo{ display:flex; align-items:flex-start; justify-content:space-between; gap:1rem; }
.inicio-titulo{ font-size:.95rem; font-weight:650; letter-spacing:-.005em; }
.inicio-sub{ font-size:.78rem; color:var(--tinta-fraca); margin-top:.1rem; }
.inicio-dispensar{
  flex:0 0 auto; font-size:.72rem; color:var(--tinta-tenue);
  background:none; border:0; cursor:pointer; padding:.15rem .25rem; border-radius:.35rem;
}
.inicio-dispensar:hover{ color:var(--tinta); text-decoration:underline; }
.inicio-barra{
  height:4px; border-radius:2px; background:var(--linha);
  margin:.75rem 0 .1rem; overflow:hidden;
}
.inicio-barra > span{
  display:block; height:100%; border-radius:2px; background:var(--ouro);
  transition:width .35s ease;
}
.inicio-passos{ list-style:none; margin:0; padding:0; }
.inicio-passo{
  display:flex; align-items:center; gap:.7rem;
  padding:.6rem .1rem; border-bottom:1px solid var(--linha);
}
.inicio-passo:last-child{ border-bottom:0; padding-bottom:0; }
/* A marca é o NÚMERO do passo enquanto está pendente e um tique quando
   fica pronto: a mesma casa conta a ordem e depois o resultado. */
.inicio-marca{
  flex:0 0 auto; width:1.4rem; height:1.4rem; border-radius:50%;
  display:grid; place-items:center; font-size:.7rem; font-weight:700;
  color:var(--tinta-fraca); border:1px solid var(--linha-forte);
}
.inicio-rotulo{ flex:1; font-size:.875rem; min-width:0; }
.inicio-cta{ flex:0 0 auto; padding:.3rem .7rem; font-size:.75rem; }
.inicio-ok{ flex:0 0 auto; font-size:.72rem; color:var(--tinta-tenue); }
.inicio-passo.feito .inicio-marca{
  background:var(--g-bom); border-color:var(--g-bom); color:#fff;
}
/* Recua, não risca. */
.inicio-passo.feito .inicio-rotulo{ color:var(--tinta-tenue); }
.field-search{
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
  background-repeat:no-repeat; background-position:.65rem center; padding-left:2.1rem;
}
/* Cabeçalho/legenda dentro da barra de filtros e o "Limpar filtros" */
.filter-clear{
  font-size:.72rem; font-weight:600; color:#7c611f; cursor:pointer;
  display:inline-flex; align-items:center; gap:.25rem;
}
.filter-clear:hover{ text-decoration:underline; }
.dark .filter-clear{ color:#e6cf8f; }

/* Realce do trecho buscado no plano de contas */
mark.hl{ background:#fef08a; color:inherit; border-radius:.15rem; padding:0 .05rem; }
.dark mark.hl{ background:rgba(250,204,21,.35); color:#fef9c3; }

/* ======================================================================
   CALENDÁRIO DE VENCIMENTOS — trinta e cinco caixas eram trinta e cinco
   caixas demais

   Cada dia era um retângulo com borda de 1px e canto arredondado. Numa
   grade de 5×7 isso são 35 molduras completas — 140 traços — para exibir,
   em geral, sete ou oito compromissos. A moldura tinha mais tinta que o
   conteúdo, e os dias VAZIOS (a maioria) desenhavam com o mesmo peso dos
   dias que tinham conta a pagar.

   O desenho novo troca 35 molduras por UMA GRADE: cada célula desenha só
   o próprio fio à direita e embaixo (`box-shadow:inset`), de modo que
   duas células vizinhas dividem um traço em vez de encostarem dois.

   POR QUE `inset` E NÃO `gap:1px` COM FUNDO NO CONTÊINER. O truque do vão
   é mais elegante, e foi a primeira tentativa — mas o mês não preenche a
   última linha da grade (fevereiro fecha na quarta-feira, e ali não há
   célula nenhuma). Sem célula, o que aparece naquele retângulo é o FUNDO
   DO CONTÊINER, ou seja, um bloco cinza sólido do tamanho de quatro dias.
   Com o fio dentro da célula, o vazio é vazio.

   Com a moldura fora do caminho, o PESO passa a significar alguma coisa:
   dia sem nada é papel liso; dia com compromisso tem superfície; hoje tem
   ouro. O olho encontra o que vence antes de ler qualquer número.
   ====================================================================== */
.cal{
  display:grid; grid-template-columns:repeat(7,minmax(0,1fr));
  background:var(--superficie);
  border:1px solid var(--linha); border-radius:var(--r-sm); overflow:hidden;
}
.cal > *{ box-shadow:inset -1px -1px 0 var(--linha); }
/* A última coluna não desenha o fio da direita: ali já está a borda do
   contêiner, e dois traços de 1px encostados leem como um de 2px. */
.cal > *:nth-child(7n){ box-shadow:inset 0 -1px 0 var(--linha); }
.cal-dow{
  text-align:center; font-size:.6rem; font-weight:700; text-transform:uppercase;
  letter-spacing:.13em; color:var(--tinta-tenue); padding:.45rem 0;
  background:var(--superficie-2);
}
.dark .cal-dow{ background:rgba(255,255,255,.04); }
.cal-cell{
  position:relative; min-height:4.75rem; padding:.35rem .4rem;
  background:var(--superficie); overflow:hidden;
  transition:background-color .15s var(--sai);
}
/* Dia de outro mês: mesmo papel, sem conteúdo. Não é "invisível" — a
   grade precisa da célula para não desalinhar a semana. */
.cal-cell.is-blank{ background:var(--superficie-2); min-height:4.75rem; }
.dark .cal-cell.is-blank{ background:rgba(255,255,255,.02); }
.cal-cell.has-ev{ cursor:pointer; }
.cal-cell.has-ev:hover{ background:var(--ouro-fraco); }
/* HOJE: número em disco de ouro. O anel de borda que havia antes competia
   com as bordas de todas as outras células (que agora nem existem); marcar
   o NÚMERO é mais preciso e sobra para o conteúdo do dia. */
.cal-cell.is-today{ background:color-mix(in srgb, var(--ouro) 8%, var(--superficie)); }
.dark .cal-cell.is-today{ background:color-mix(in srgb, var(--ouro) 14%, var(--superficie)); }
.cal-cell.is-today .cal-day{
  background:var(--ouro); color:#1b1608; border-radius:999px;
  width:1.35rem; height:1.35rem; display:grid; place-items:center;
  margin:-.1rem 0 .1rem -.1rem;
}
.cal-day{ font-size:.72rem; font-weight:650; color:var(--tinta-fraca); }
/* O compromisso é uma FAIXA com fio de cor à esquerda, não uma pastilha
   de fundo cheio. Três pastilhas coloridas empilhadas numa célula de 76px
   viram um bloco de cor; o fio dá a categoria e devolve o fundo ao texto. */
.cal-ev{
  display:block; margin-top:.2rem; padding:.1rem .3rem .1rem .35rem;
  border-radius:.15rem .25rem .25rem .15rem;
  font-size:.66rem; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  border-left:2.5px solid transparent;
}
.cal-ev.pay{
  background:color-mix(in srgb, var(--g-critico) 12%, transparent);
  border-left-color:var(--g-critico); color:var(--g-critico);
}
.cal-ev.rec{
  background:color-mix(in srgb, var(--g-bom) 12%, transparent);
  border-left-color:var(--g-bom); color:var(--g-bom);
}
/* VENCIDA é o único estado que grita, e deve gritar: fundo cheio. */
.cal-ev.late{ background:var(--g-critico); border-left-color:var(--g-critico); color:#fff; }
.dark .cal-ev.pay{ background:color-mix(in srgb, var(--g-critico) 22%, transparent); }
.dark .cal-ev.rec{ background:color-mix(in srgb, var(--g-bom) 22%, transparent); }
/* Marca sem valor: o vencimento da fatura de um cartão que fechou sem compras.
   Tracejado em vez de fundo cheio, para não competir com o que tem dinheiro. */
.cal-ev.nota{
  background:transparent; border-left-style:dashed; border-left-color:var(--linha-forte);
  color:var(--tinta-tenue); font-weight:500;
}
/* Quadradinhos da legenda — os mesmos tokens das faixas acima. */
.cal-key{ width:.6rem; height:.6rem; border-radius:.15rem; display:inline-block; }
.cal-key.pay { background:color-mix(in srgb, var(--g-critico) 45%, transparent); }
.cal-key.rec { background:color-mix(in srgb, var(--g-bom) 45%, transparent); }
.cal-key.late{ background:var(--g-critico); }

/* Botões */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:.4rem;
  padding:.5rem .9rem; border-radius:var(--r-sm); font-size:.85rem; font-weight:600;
  cursor:pointer; line-height:1.25; white-space:nowrap;
  transition:filter .15s var(--sai), background .15s var(--sai),
             border-color .15s var(--sai), box-shadow .15s var(--sai), transform .06s var(--sai);
}
.btn:focus-visible{ outline:2px solid var(--ouro); outline-offset:2px; }
/* Botão primário dourado ESCOVADO com texto grafite — o mesmo da tela de
   acesso. O registro "cartão premium" (tinta escura sobre metal) lê melhor que
   branco sobre dourado e passa AA com folga.

   O QUE ELE GANHOU: um fio de luz no topo (o metal reflete de cima) e o
   halo dourado da escala de elevação. Um botão de ação com a MESMA sombra
   cinza de um card não parece um botão — parece um retângulo colorido. */
.btn-primary{
  position:relative; overflow:hidden;
  background:linear-gradient(180deg,var(--ouro-claro) 0%,var(--ouro) 55%,var(--ouro-escuro) 100%);
  color:#1b1608; border:1px solid rgba(120,92,26,.35);
  box-shadow:var(--e-ouro), inset 0 1px 0 rgba(255,255,255,.4);
}
/* O brilho que atravessa a face ao passar o mouse. Um gesto só, curto, e
   por cima do gradiente — é o que separa "metal" de "amarelo chapado". */
.btn-primary::after{
  content:''; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(105deg, transparent 35%, rgba(255,255,255,.45) 50%, transparent 65%);
  transform:translateX(-110%); transition:transform .55s var(--sai);
}
.btn-primary:hover{ filter:brightness(1.05); box-shadow:var(--e-ouro), inset 0 1px 0 rgba(255,255,255,.55); }
.btn-primary:hover::after{ transform:translateX(110%); }
.btn-primary:active{ transform:translateY(1px); box-shadow:var(--e1), inset 0 1px 3px rgba(90,68,14,.35); }

.btn-ghost{
  background:var(--superficie); border:1px solid var(--linha-forte); color:var(--tinta);
  box-shadow:var(--e1);
}
.btn-ghost:hover{ border-color:var(--ouro); background:var(--ouro-fraco); box-shadow:var(--e2); }
.btn-ghost:active{ transform:translateY(1px); box-shadow:none; }
.dark .btn-ghost{ background:rgba(255,255,255,.045); box-shadow:none; }
.dark .btn-ghost:hover{ background:var(--ouro-fraco); }
/* Ação destrutiva: vinho só na borda e no texto até o cursor chegar. Um
   botão vermelho sólido parado na tela lê como alarme permanente. */
.btn-perigo{
  background:transparent; border:1px solid color-mix(in srgb, var(--g-critico) 45%, transparent);
  color:var(--g-critico);
}
.btn-perigo:hover{ background:var(--g-critico); border-color:var(--g-critico); color:#fff; }
/* Medida menor, para barra de apoio e ações dentro de card. */
.btn-sm{ padding:.32rem .65rem; font-size:.76rem; border-radius:var(--r-xs); }
.btn:disabled{ opacity:.5; cursor:not-allowed; filter:none; box-shadow:none; transform:none; }
.btn:disabled::after{ display:none; }

.pos{ color:#15803d; } .neg{ color:#be123c; }
.dark .pos{ color:#4ade80; } .dark .neg{ color:#f87171; }

/* Botões de resposta (Sim/Não/Neutro) selecionados */
.ansel-green{ background:#16a34a; color:#fff; }
.ansel-red{ background:#dc2626; color:#fff; }
.ansel-gray{ background:#64748b; color:#fff; }

/* Abas laterais das simulações */
.sim-tab{ display:block; width:100%; text-align:left; padding:.45rem .6rem; border-radius:.5rem;
  font-size:.875rem; color:var(--tinta-fraca); }
.sim-tab:hover{ background:var(--superficie-2); color:var(--tinta); }
.dark .sim-tab:hover{ background:rgba(255,255,255,.06); }
.sim-tab.active{ background:var(--ouro); color:#1b1608; font-weight:600; }
.dark .sim-tab.active{ background:var(--ouro); color:#1b1608; }

/* ======================================================================
   RELATÓRIOS — a árvore de um balanço tem de se ver

   Um DRE ou um balanço não é uma lista: é uma ÁRVORE com somas parciais.
   O que o leitor procura é onde um bloco começa, o que é somatório e qual
   é o número que fecha a conta. As seis classes abaixo são exatamente
   esses papéis (ROW_CLASS no app.js), e cada uma tem um desenho — antes
   os três casos eram "negrito e um cinza um pouco mais escuro", com os
   cinzas vindos do paletão do Tailwind em vez dos tokens daqui.
   ====================================================================== */
/* ABRE UM BLOCO ("(+) RECEITAS"). Versalete espaçado + fio de ouro na
   margem: lê-se como TÍTULO, não como uma linha de valor sem número. */
table.tbl tr.rep-grupo > td{
  background:var(--superficie-2);
  font-size:.7rem; font-weight:700; letter-spacing:.1em; text-transform:uppercase;
  color:var(--tinta-fraca);
  padding-top:.7rem; padding-bottom:.55rem;
  border-bottom:1px solid var(--linha);
  box-shadow:inset 3px 0 0 var(--ouro);
}
.dark table.tbl tr.rep-grupo > td{ background:rgba(255,255,255,.05); }
table.tbl tr.rep-grupo:hover > td{ background:var(--superficie-2); }
.dark table.tbl tr.rep-grupo:hover > td{ background:rgba(255,255,255,.05); }

/* Conta SINTÉTICA: tem filhas logo abaixo. Tinta cheia e um fundo de
   meio degrau — ela é o pai da indentação seguinte. */
table.tbl tr.rep-sint > td{
  background:color-mix(in srgb, var(--superficie-2) 55%, var(--superficie));
  font-weight:600; color:var(--tinta);
}
.dark table.tbl tr.rep-sint > td{ background:rgba(255,255,255,.028); }

/* FECHA UM BLOCO. O fio grosso em cima é o traço de soma do papel
   quadriculado — é ele que diz "o que vem agora é a conta do que estava
   acima", e nenhum negrito faz esse trabalho sozinho. */
table.tbl tr.rep-total > td{
  font-weight:700; color:var(--tinta);
  border-top:1.5px solid var(--linha-forte); border-bottom:0;
  padding-top:.6rem;
}

/* O NÚMERO QUE FECHA O RELATÓRIO. É o único lugar da tabela onde a marca
   aparece: fundo de ouro a 7%, fio de ouro em cima e embaixo — a "linha
   dupla" com que se encerra uma coluna no razão de papel. Um resultado
   apenas em negrito some no meio de vinte outras linhas em negrito. */
table.tbl tr.rep-grand > td{
  background:color-mix(in srgb, var(--ouro) 7%, transparent);
  font-weight:800; font-size:.9rem; color:var(--tinta);
  border-top:2px solid color-mix(in srgb, var(--ouro) 55%, transparent);
  border-bottom:1px solid color-mix(in srgb, var(--ouro) 30%, transparent);
  padding-top:.8rem; padding-bottom:.8rem;
}
.dark table.tbl tr.rep-grand > td{ background:color-mix(in srgb, var(--ouro) 12%, transparent); }
table.tbl tr.rep-grand:hover > td{ background:color-mix(in srgb, var(--ouro) 7%, transparent); }
.dark table.tbl tr.rep-grand:hover > td{ background:color-mix(in srgb, var(--ouro) 12%, transparent); }
/* O trilho dourado do hover não cabe aqui: a linha inteira já é dourada. */
table.tbl tr.rep-grand:hover > td:first-child,
table.tbl tr.rep-grupo:hover > td:first-child{ box-shadow:none; }
table.tbl tr.rep-grupo:hover > td:first-child{ box-shadow:inset 3px 0 0 var(--ouro); }

/* Ressalva, nota de pé de tabela: presente, recessiva. */
table.tbl tr.rep-fraca > td{ color:var(--tinta-tenue); font-size:.82rem; }

/* ---------------------------------------------------------------------
   LISTA DE CARTEIRAS — a proporção mora atrás do texto

   Cinco linhas de "nome … R$ valor" respondem quanto tem em cada, mas não
   respondem ONDE ESTÁ O DINHEIRO — que é a pergunta que se faz olhando
   para uma lista de carteiras. Ler cinco números em reais e ordená-los de
   cabeça é trabalho que o desenho pode fazer.

   A barra de proporção é um fundo de 3px atrás da linha, alinhado à base.
   Não gasta linha nenhuma, não empurra o valor e responde antes da
   leitura. Verde quando é saldo, vinho quando é dívida (fatura de cartão),
   pelos mesmos tokens de polaridade do resto do app.
   --------------------------------------------------------------------- */
.cart-linha{
  position:relative; display:flex; align-items:center; gap:.75rem;
  padding:.55rem .1rem .6rem; border-bottom:1px solid var(--linha);
}
.cart-linha:last-child{ border-bottom:0; }
.cart-prop{
  position:absolute; left:0; bottom:0; height:3px; border-radius:999px;
  opacity:.4; transition:opacity .15s var(--sai), width .3s var(--sai);
}
.cart-linha:hover .cart-prop{ opacity:.75; }
.cart-nome{ flex:1 1 auto; min-width:0; font-size:.875rem; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.cart-tipo{
  font-size:.62rem; letter-spacing:.1em; text-transform:uppercase;
  color:var(--tinta-tenue); margin-left:.4rem;
}
.cart-valor{ flex:0 0 auto; font-weight:650; font-variant-numeric:tabular-nums; }

/* Barra de progresso (orçamento) */
/* `display:flex` porque a barra passou a ter DOIS segmentos lado a lado (o
   realizado e o comprometido). Com `block` o segundo caía embaixo do primeiro.
   `flex:none` mantém cada um exatamente na largura em % que o JS calculou. */
.bar{ height:.45rem; border-radius:999px; background:var(--linha); overflow:hidden; display:flex; }
.bar > span{ display:block; height:100%; border-radius:999px; flex:none; }
/* Segmento COMPROMETIDO — o que vence no mês e ainda não saiu (parcelas 2..N de
   um parcelado, recorrências). Listrado de propósito: é dinheiro já falado, mas
   não gasto; pintá-lo sólido diria que já saiu. */
.bar > span.prev{
  background-image:repeating-linear-gradient(45deg,
    rgba(255,255,255,.6) 0 2px, rgba(255,255,255,0) 2px 5px);
  opacity:.75;
}

/* ---------------------------------------------------------------------
   MODAL — a mesma moldura dos formulários da tela de acesso
   --------------------------------------------------------------------- */
/* O véu escurece E DESFOCA. Só escurecer deixa o formulário atrás legível,
   e um formulário legível atrás de outro formulário divide a atenção
   exatamente no momento em que o app está pedindo uma decisão. */
.modal-fundo{
  background:rgba(17,16,12,.5); backdrop-filter:blur(6px) saturate(.9);
  animation:vela-entra .2s var(--sai) both;
}
@keyframes vela-entra{ from{ opacity:0; } to{ opacity:1; } }
/* Fluxo normal + margem automática: centra na horizontal, dá respiro em cima e
   embaixo, e — porque o #modal rola — deixa a caixa alta ser percorrida inteira
   em vez de vazar para fora da tela. `position:relative` + z-index a poem acima
   do fundo. A margem vertical é o que garante que o topo de um modal mais alto
   que a tela continue alcançavel (margin:auto sozinho cortaria o topo). */
.modal-caixa{
  position:relative; z-index:1; margin:2.5rem auto;
  background:var(--superficie); border:1px solid var(--linha); border-radius:var(--r-xl);
  box-shadow:var(--e3), var(--brilho);
  /* Assenta com um leve ultrapasse (--mola) em vez de simplesmente
     aparecer: é o que dá a sensação de um painel que veio de algum lugar. */
  animation:modal-entra .28s var(--mola) both;
}
@keyframes modal-entra{
  from{ opacity:0; transform:translateY(12px) scale(.985); }
  to  { opacity:1; transform:none; }
}
/* Cabeçalho preso: num formulário longo, o título e o ✕ acompanham a rolagem em
   vez de sumir no topo. O fundo opaco impede o conteúdo de aparecer atrás dele.

   O fio dourado no alto é a mesma assinatura do trilho do KPI e da divisa
   da sidebar: onde a marca toca a moldura, ela toca em ouro. */
.modal-cab{
  background:var(--superficie); border-bottom:1px solid var(--linha);
  border-radius:var(--r-xl) var(--r-xl) 0 0;
  background-image:linear-gradient(90deg, var(--ouro) 0%, color-mix(in srgb, var(--ouro) 20%, transparent) 55%, transparent 100%);
  background-repeat:no-repeat; background-size:100% 2px; background-position:top left;
}

/* Enquanto um modal está aberto, o fundo não rola — senão a roda do mouse
   mexeria a página atrás em vez do formulário na frente, e o usuário "perderia"
   a tela onde estava. Removido no closeModal, sempre. */
html.modal-aberto{ overflow:hidden; }

/* ---------------------------------------------------------------------
   Caixa de "abas liberadas" (cadastro de pessoa). Cada opção é um cartão
   clicável: em lista de checkbox nua, o rótulo e a explicação viram um bloco
   de texto que ninguém lê antes de marcar.
   --------------------------------------------------------------------- */
.abas-grid{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:.4rem; }
@media (max-width:520px){ .abas-grid{ grid-template-columns:1fr; } }
.aba-opt{
  display:flex; align-items:flex-start; gap:.5rem; cursor:pointer;
  padding:.45rem .55rem; border:1px solid var(--linha); border-radius:.5rem;
  transition:border-color .15s, background .15s;
}
.aba-opt:hover{ border-color:var(--linha-forte); background:var(--superficie-2); }
.aba-opt input{ margin-top:.15rem; accent-color:var(--ouro); flex:0 0 auto; }
.aba-opt b{ display:block; font-size:.8rem; font-weight:600; }
.aba-opt i{ display:block; font-size:.68rem; font-style:normal; color:var(--tinta-tenue); line-height:1.35; }
.aba-opt:has(input:checked){ border-color:var(--ouro); background:var(--ouro-fraco); }

/* ---------------- Cores do Tailwind no tema escuro ----------------
   Os tons -500/-600 são feitos para fundo branco; sobre o card (#0f172a) eles
   caem para 2,7–3,9:1 e ficam ilegíveis. Aqui eles viram o -400 equivalente,
   que é a convenção do Tailwind para tema escuro.

   Por que a regra mora aqui e não em cada `class=`: são ~66 usos espalhados
   pelo HTML gerado no app.js/sim.js. Um `dark:` em cada um seria a forma
   idiomática, mas espalharia a decisão de cor por 66 lugares — e o arquivo já
   resolve tudo (.card, .field, .cal-ev…) neste padrão `.dark X`.

   Sobre especificidade: o Play CDN injeta o <style> dele DEPOIS deste arquivo.
   `.dark .text-rose-600` (0,2,0) vence `.text-rose-600` (0,1,0) de qualquer
   jeito. Já `hover:text-rose-600` vira `.hover\:text-rose-600:hover`, que
   também é (0,2,0) — empate que a ordem decidiria contra nós. Daí as regras de
   hover levarem o `.dark` na frente, indo a (0,3,0). */
.dark .text-slate-500  { color:#94a3b8; }
.dark .text-brand-600  { color:#d9bd6b; }
.dark .text-rose-600   { color:#fb7185; }
.dark .text-emerald-600{ color:#34d399; }
.dark .text-amber-600  { color:#fbbf24; }

.dark .hover\:text-brand-600:hover  { color:#d9bd6b; }
.dark .hover\:text-rose-600:hover   { color:#fb7185; }
.dark .hover\:text-emerald-600:hover{ color:#34d399; }

/* ======================================================================
   O QUADRO DO GRÁFICO — moldura, legenda e dica

   Antes o gráfico era um <canvas> solto embaixo de um <h3>, com a legenda
   que o Chart.js desenha por conta própria: quadradinhos coloridos em
   corpo 12 no topo, numa fonte que não é a do app, com espaçamento que
   não é o do app, e sem nenhuma relação com o resto da tela.

   Aqui a legenda sai do canvas e vira HTML no CABEÇALHO do card, junto do
   título — que é onde ela responde a pergunta certa ("o que estou vendo?")
   antes de o olho descer para as barras, e não depois. Sobra ao canvas o
   que só ele sabe fazer: desenhar.
   ====================================================================== */
.graf-legenda{ display:flex; align-items:center; flex-wrap:wrap; gap:.3rem .85rem; }
.graf-chave{
  display:inline-flex; align-items:center; gap:.4rem;
  font-size:.72rem; font-weight:550; color:var(--tinta-fraca); white-space:nowrap;
}
/* O naipe é um retângulo de cantos vivos, não um círculo: ele tem de ser
   lido como "esta é a cor daquela BARRA", e barra é retângulo. */
.graf-naipe{
  width:.7rem; height:.7rem; border-radius:.2rem; flex:0 0 auto;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.08);
}
/* Naipe de série de LINHA: um traço, porque a série é um traço. */
.graf-naipe.linha{ height:.2rem; width:.9rem; border-radius:999px; }
/* Naipe do que é REFERÊNCIA (meta, mediana): tracejado, como o desenho. */
.graf-naipe.ref{ background:transparent; box-shadow:inset 0 0 0 1.5px var(--g-referencia); }

/* A caixa do canvas fixa a ALTURA. Sem isto o Chart.js redimensiona o
   canvas a cada render e o card "respira" alguns pixels toda vez que o
   filtro muda — um tremor pequeno e constante que cansa sem ser notado. */
.graf-caixa{ position:relative; }
.graf-caixa > canvas{ display:block; }

/* Número no miolo da rosca. Uma rosca sem centro é um anel decorativo: o
   total é justamente o que as fatias somam, e ele estava fora do desenho,
   noutro card. `pointer-events:none` para o passar do mouse continuar
   chegando ao canvas embaixo. */
.graf-miolo{
  position:absolute; inset:0; display:grid; place-content:center; text-align:center;
  pointer-events:none;
}
.graf-miolo b{
  display:block; font-size:1.15rem; font-weight:700; letter-spacing:-.02em;
  color:var(--tinta); font-variant-numeric:tabular-nums; line-height:1.15;
}
.graf-miolo span{
  display:block; font-size:.6rem; font-weight:700; letter-spacing:.13em;
  text-transform:uppercase; color:var(--tinta-tenue); margin-top:.2rem;
}

/* ---------------------------------------------------------------------
   A DICA DO GRÁFICO — em HTML, com a cara do app

   A dica nativa do Chart.js é uma caixa preta com sombra dura e a fonte do
   sistema. Ela aparece dezenas de vezes por sessão bem no meio da tela e é,
   na prática, o componente mais visto do painel — e o único que não seguia
   nada da identidade. Esta é desenhada pelo app.js (`dicaHtml`) e mora aqui.
   --------------------------------------------------------------------- */
.ct-tip{
  position:absolute; z-index:40; pointer-events:none;
  min-width:9rem; padding:.55rem .7rem;
  background:var(--superficie); border:1px solid var(--linha-forte);
  border-radius:var(--r-sm); box-shadow:var(--e3);
  font-size:.75rem; line-height:1.45; color:var(--tinta);
  opacity:0; transform:translate(-50%,-.35rem) scale(.97);
  transition:opacity .12s var(--sai), transform .12s var(--sai);
}
.ct-tip.ver{ opacity:1; transform:translate(-50%,-.6rem) scale(1); }
.dark .ct-tip{ background:#22232a; }
.ct-tip-tit{
  font-size:.62rem; font-weight:700; letter-spacing:.11em; text-transform:uppercase;
  color:var(--tinta-tenue); padding-bottom:.35rem; margin-bottom:.35rem;
  border-bottom:1px solid var(--linha);
}
.ct-tip-l{ display:flex; align-items:center; gap:.45rem; }
.ct-tip-l + .ct-tip-l{ margin-top:.2rem; }
.ct-tip-l b{ margin-left:auto; font-variant-numeric:tabular-nums; font-weight:650; }

/* ======================================================================
   O VAZIO — a tela que não tem o que mostrar ainda tem o que dizer

   `emptyMsg` devolvia uma frase cinza centrada. Numa conta nova isso é a
   PRIMEIRA coisa que a pessoa vê no app, e uma frase cinza no meio de um
   card branco lê como falha ("não carregou?"), não como "está tudo certo,
   só falta você começar". O bloco abaixo dá um ícone recuado, um título e
   — o que faltava — um caminho de saída.
   ====================================================================== */
.vazio{
  display:flex; flex-direction:column; align-items:center; text-align:center;
  padding:2.5rem 1.25rem; gap:.15rem;
}
.vazio-ico{
  width:2.75rem; height:2.75rem; border-radius:999px; margin-bottom:.65rem;
  display:grid; place-items:center; color:var(--ouro-escuro);
  background:var(--ouro-fraco);
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--ouro) 25%, transparent);
}
.dark .vazio-ico{ color:var(--ouro-claro); }
.vazio-ico svg{ width:1.35rem; height:1.35rem; }
.vazio-tit{ font-size:.9rem; font-weight:650; color:var(--tinta); }
.vazio-txt{ font-size:.8rem; color:var(--tinta-tenue); max-width:24rem; line-height:1.5; }
.vazio .btn{ margin-top:.85rem; }

/* ======================================================================
   O ESQUELETO — o intervalo entre pedir e receber

   Consulta ao Postgres pela ponte custa dezenas de milissegundos, e nesse
   intervalo o card ficava VAZIO: a página montava com buracos e depois
   preenchia, e o texto pulava de lugar. O esqueleto ocupa a forma final
   antes do dado chegar; o layout não se mexe quando ele chega.

   O brilho anda da esquerda para a direita porque é a direção da leitura —
   um brilho que vai ao contrário é lido como erro.
   ====================================================================== */
.skel{
  position:relative; overflow:hidden; border-radius:var(--r-xs);
  background:var(--superficie-2); color:transparent !important;
}
.dark .skel{ background:rgba(255,255,255,.055); }
.skel::after{
  content:''; position:absolute; inset:0;
  background:linear-gradient(90deg, transparent, rgba(255,255,255,.65), transparent);
  transform:translateX(-100%); animation:skel-varre 1.25s infinite;
}
.dark .skel::after{ background:linear-gradient(90deg, transparent, rgba(255,255,255,.07), transparent); }
@keyframes skel-varre{ to{ transform:translateX(100%); } }
.skel-l{ height:.65rem; margin:.35rem 0; }
.skel-l.curta{ width:45%; } .skel-l.media{ width:70%; } .skel-l.longa{ width:92%; }

/* ======================================================================
   MOVIMENTO — só onde ele responde alguma pergunta

   Regra única deste app: animação existe para dizer DE ONDE uma coisa
   veio ou PARA ONDE ela foi. Nada pulsa, nada balança, nada chama
   atenção sozinho.

   A entrada dos cards é escalonada em 40ms. O escalonamento não é enfeite:
   ele constrói a leitura na ordem em que a tela quer ser lida (o cartão
   principal primeiro, o calendário por último) em vez de despejar doze
   blocos de uma vez.

   O DESLOCAMENTO É DE 6px. Foi 16px na primeira tentativa e a tela
   inteira parecia "cair" a cada troca de aba — o que num app de dinheiro
   lê como instabilidade, não como capricho.
   ====================================================================== */
@keyframes entra{
  from{ opacity:0; transform:translateY(6px); }
  to  { opacity:1; transform:none; }
}
/* A classe entra no #app a cada troca de tela (app.js). Os filhos DIRETOS
   é que se animam — animar netos faria o conteúdo de dentro de um card
   deslizar por baixo da borda dele. */
.anim-tela > *{ animation:entra .32s var(--sai) both; }
.anim-tela > *:nth-child(1){ animation-delay:0ms; }
.anim-tela > *:nth-child(2){ animation-delay:40ms; }
.anim-tela > *:nth-child(3){ animation-delay:80ms; }
.anim-tela > *:nth-child(4){ animation-delay:120ms; }
.anim-tela > *:nth-child(5){ animation-delay:160ms; }
.anim-tela > *:nth-child(n+6){ animation-delay:200ms; }

/* QUEM PEDIU PARA NÃO SE MEXER NÃO SE MEXE. Não é acessibilidade de
   fachada: enjoo de movimento é real, e o sistema operacional já sabe a
   resposta — basta perguntar. Tudo continua funcionando; só chega pronto. */
@media (prefers-reduced-motion:reduce){
  *, *::before, *::after{
    animation-duration:.01ms !important; animation-iteration-count:1 !important;
    transition-duration:.01ms !important; scroll-behavior:auto !important;
  }
}

/* ======================================================================
   O BOOT — a primeira imagem do app, toda vez

   Era um anel girando com "Inicializando banco de dados…" embaixo: a tela
   de carregamento de qualquer coisa. Mas esta é a primeira imagem que o
   app mostra a cada abertura — e ela pode ser a marca em vez de um
   spinner de biblioteca.

   Não há spinner aqui. Um anel girando finge medir um progresso que
   ninguém está medindo; o traço que corre de um lado ao outro diz
   "estou trabalhando" sem prometer quanto falta. O grafite é o mesmo do
   painel de acesso que vem logo depois — a troca de uma tela para a outra
   deixa de ser um corte e vira uma continuação.
   ====================================================================== */
.boot{
  background:radial-gradient(125% 100% at 12% 0%, #26262e 0%, #191920 46%, #0d0d10 100%);
  color:#e8e6e1;
}
.boot-in{ text-align:center; display:flex; flex-direction:column; align-items:center; }
.boot-marca{
  width:3.5rem; height:3.5rem; border-radius:1rem; background:#fff;
  display:grid; place-items:center; box-shadow:0 8px 28px rgba(0,0,0,.45);
  animation:boot-pousa .5s var(--mola) both;
}
.boot-marca svg{ width:2.4rem; height:2.4rem; }
@keyframes boot-pousa{
  from{ opacity:0; transform:translateY(8px) scale(.9); }
  to  { opacity:1; transform:none; }
}
.boot-word{
  font-family:Georgia,'Times New Roman',serif; font-size:1.35rem; font-weight:700;
  letter-spacing:.24em; color:#fff; margin-top:1.1rem; padding-left:.24em;
}
.boot-tag{
  font-size:.62rem; letter-spacing:.2em; text-transform:uppercase;
  color:#bf9b4e; margin-top:.35rem;
}
/* O trilho de progresso indeterminado: um segmento de 40% que atravessa,
   some e volta. Fica ESTREITO (10rem) porque uma barra larga sugere
   proporção — e não há proporção nenhuma sendo medida aqui. */
.boot-trilho{
  width:10rem; height:2px; margin-top:1.6rem; border-radius:999px;
  background:rgba(255,255,255,.10); overflow:hidden;
}
.boot-trilho > span{
  display:block; width:40%; height:100%; border-radius:999px;
  background:linear-gradient(90deg, transparent, #bf9b4e, transparent);
  animation:boot-corre 1.15s var(--sai) infinite;
}
@keyframes boot-corre{
  from{ transform:translateX(-110%); } to{ transform:translateX(360%); }
}
.boot-nota{ font-size:.72rem; color:#807c75; margin-top:1rem; }

/* ======================================================================
   TELA DE ACESSO (auth.js) — login, criar acesso, redefinir senha

   Duas colunas: a MARCA à esquerda, em grafite quase-preto com o dourado
   champanhe da identidade, e o FORMULÁRIO à direita, sobre fundo claro. O
   painel escuro não muda com o tema: ele é a marca, e marca não tem tema.

   Por que CSS de verdade e não utilitários do Tailwind: os gradientes, a trama
   gravada do fundo e o estado dos campos (ok/não) precisam de várias camadas e
   de pseudo-elementos. Escrever isso em `class=` viraria uma linha ilegível de
   400 caracteres repetida em cada tela.
   ====================================================================== */
.au-root{
  position:fixed; inset:0; z-index:60; display:flex; overflow:auto;
  /* O mesmo papel iluminado do app: bafo dourado no alto e queda vertical
     para o pé. O fundo chapado fazia o formulário flutuar num vazio. */
  background:
    radial-gradient(110% 70% at 88% -6%, rgba(191,155,78,.10) 0%, rgba(191,155,78,.025) 36%, transparent 64%),
    linear-gradient(180deg, #fbfaf7 0%, #f5f4f0 52%, #eeece6 100%);
  color:#1e293b;
}
.dark .au-root{
  background:
    radial-gradient(110% 70% at 88% -6%, rgba(191,155,78,.12) 0%, rgba(191,155,78,.03) 36%, transparent 64%),
    linear-gradient(180deg, #1a1b21 0%, #15161a 52%, #101116 100%);
  color:#e2e8f0;
}

/* ---- Painel da marca ---- */
.au-brand{
  position:relative; overflow:hidden; flex:0 0 46%; max-width:640px;
  display:none; padding:3rem 3.25rem;
  background:radial-gradient(120% 95% at 12% 8%, #26262e 0%, #191920 48%, #0d0d10 100%);
  color:#e8e6e1;
}
@media (min-width:1024px){ .au-brand{ display:block; } }
/* Brilho dourado difuso: o "metal" da identidade, sem virar amarelo chapado. */
.au-brand-glow{
  position:absolute; inset:auto auto -18% -12%; width:60rem; height:60rem;
  background:radial-gradient(circle, rgba(191,155,78,.20) 0%, rgba(191,155,78,.06) 38%, transparent 68%);
  pointer-events:none;
}
/* Trama gravada, no registro de papel-moeda/certificado: linhas finíssimas em
   dois ângulos, quase invisíveis — dão textura sem competir com o texto. */
.au-brand-grade{
  position:absolute; inset:0; pointer-events:none; opacity:.5;
  background:
    repeating-linear-gradient(115deg, rgba(191,155,78,.07) 0 1px, transparent 1px 13px),
    repeating-linear-gradient(65deg,  rgba(255,255,255,.035) 0 1px, transparent 1px 22px);
  -webkit-mask-image:radial-gradient(80% 70% at 30% 30%, #000 25%, transparent 85%);
          mask-image:radial-gradient(80% 70% at 30% 30%, #000 25%, transparent 85%);
}
/* Fio dourado na divisa das duas colunas. */
.au-brand::after{
  content:''; position:absolute; top:0; right:0; bottom:0; width:1px;
  background:linear-gradient(180deg, transparent, rgba(191,155,78,.55) 30%, rgba(191,155,78,.55) 70%, transparent);
}
.au-brand-in{
  position:relative; z-index:1; height:100%; min-height:26rem;
  display:flex; flex-direction:column; gap:2.25rem;
}
.au-logo{ display:flex; align-items:center; gap:.9rem; }
.au-mark{
  width:3rem; height:3rem; border-radius:.85rem; background:#fff; flex:0 0 auto;
  display:grid; place-items:center; box-shadow:0 6px 20px rgba(0,0,0,.35);
}
.au-mark svg{ width:2.1rem; height:2.1rem; }
.au-word{
  font-family:Georgia,'Times New Roman',serif; font-size:1.45rem; font-weight:700;
  letter-spacing:.22em; line-height:1.1; color:#fff;
}
.au-tag{ font-size:.72rem; letter-spacing:.18em; text-transform:uppercase; color:#bf9b4e; margin-top:.15rem; }
.au-lead{ margin-top:auto; }
.au-rule{ width:3.5rem; height:2px; background:#bf9b4e; margin-bottom:1.1rem; }
.au-lead p{ font-size:1.6rem; line-height:1.35; font-weight:300; color:#f1efea; }
.au-pilares{ display:flex; flex-direction:column; gap:1rem; }
.au-pilares li{ position:relative; padding-left:1.4rem; }
.au-pilares li::before{
  content:''; position:absolute; left:0; top:.42rem; width:.45rem; height:.45rem;
  border-radius:999px; background:#bf9b4e; box-shadow:0 0 0 3px rgba(191,155,78,.18);
}
.au-pilares b{ display:block; font-size:.85rem; font-weight:600; color:#fff; }
.au-pilares span{ display:block; font-size:.78rem; line-height:1.45; color:#9d9a94; margin-top:.1rem; }
.au-brand-pe{ font-size:.7rem; letter-spacing:.06em; color:#75726d; }

/* ---------------------------------------------------------------------
   A VITRINE — o produto aparece na tela de entrada

   O painel dizia três frases sobre o que o app faz e não mostrava nada do
   que ele É. Esta é a miniatura do cartão de abertura do dashboard, no
   mesmo vidro fumê do painel: o número grande, a variação e a série de
   seis meses. Quem está avaliando o app vê o app.

   As barras SOBEM ao entrar (`transform-origin:bottom`), escalonadas em
   70ms. É a única animação decorativa do arquivo inteiro, e ela se paga:
   uma barra que cresce é lida como medida sendo feita — enquanto seis
   retângulos parados são um desenho.
   --------------------------------------------------------------------- */
.au-vitrine{
  position:relative; border-radius:.9rem; padding:1.1rem 1.15rem 1rem;
  background:linear-gradient(155deg, rgba(255,255,255,.075), rgba(255,255,255,.02));
  border:1px solid rgba(191,155,78,.24);
  box-shadow:0 18px 40px -22px rgba(0,0,0,.8), inset 0 1px 0 rgba(255,255,255,.07);
  backdrop-filter:blur(2px);
}
.au-vit-topo{ display:flex; align-items:center; gap:.75rem; }
.au-vit-rot{
  flex:1 1 auto; font-size:.6rem; font-weight:700; letter-spacing:.15em;
  text-transform:uppercase; color:#bf9b4e;
}
.au-vit-var{
  flex:0 0 auto; font-size:.66rem; font-weight:700; padding:.12rem .42rem;
  border-radius:999px; color:#7fc98d; background:rgba(104,178,116,.18);
}
.au-vit-valor{
  font-size:1.75rem; font-weight:700; letter-spacing:-.03em; color:#fff;
  margin-top:.45rem; font-variant-numeric:tabular-nums;
}
/* As barras: seis colunas de altura própria, alinhadas pela base. */
/* Alto o bastante para a diferença entre 38% e 88% ser uma DIFERENÇA. A
   2,75rem as seis colunas saíam quase quadradas e o desenho lia como uma
   fileira de blocos, não como uma medida. */
.au-vit-barras{
  display:flex; align-items:flex-end; gap:.4rem; height:4rem; margin-top:1rem;
}
.au-vit-barras > span{
  flex:1 1 0; min-width:0; border-radius:.25rem .25rem .1rem .1rem;
  background:linear-gradient(180deg, rgba(191,155,78,.85), rgba(191,155,78,.30));
  transform-origin:bottom; animation:vit-sobe .55s var(--sai) both;
}
/* A última barra é o mês corrente: cheia, e a única com brilho. */
.au-vit-barras > span:last-child{
  background:linear-gradient(180deg, #d0ac5c, #a8873c);
  box-shadow:0 0 12px rgba(191,155,78,.45);
}
@keyframes vit-sobe{ from{ transform:scaleY(.05); opacity:0; } to{ transform:none; opacity:1; } }
.au-vit-pe{
  display:flex; gap:.35rem 1.1rem; flex-wrap:wrap;
  margin-top:.95rem; padding-top:.75rem; border-top:1px solid rgba(255,255,255,.08);
}
.au-vit-pe span{ display:block; }
.au-vit-pe b{
  display:block; font-size:.78rem; font-weight:650; color:#efece5;
  font-variant-numeric:tabular-nums;
}
.au-vit-pe span{
  font-size:.55rem; letter-spacing:.13em; text-transform:uppercase; color:#8d8981;
}
/* Painel curto (notebook de 720p deitado): a vitrine é o que sai primeiro
   — ela é o argumento, e argumento não pode empurrar o formulário para
   fora da tela. */
@media (max-height:760px){ .au-vitrine{ display:none; } }

/* ---------------------------------------------------------------------
   Painel do formulário

   O FORMULÁRIO PASSA A TER UMA MOLDURA. Ele era um bloco de campos solto
   sobre o fundo: ao lado de um painel de marca com textura, gradiente e
   profundidade, a metade direita da tela parecia inacabada — e, o que é
   pior num app de dinheiro, parecia improvisada.

   O cartão não pede nenhuma mudança no auth.js: `.au-box` já envolve o
   título, o formulário e o rodapé das três telas de acesso (entrar, criar
   e redefinir), então vestir ELE veste as três de uma vez.
   --------------------------------------------------------------------- */
.au-panel{ flex:1 1 auto; display:grid; place-items:center; padding:2rem 1.25rem; }
.au-box{
  width:100%; max-width:25rem;
  background:#fff; border:1px solid var(--linha);
  border-radius:var(--r-xl); padding:2.25rem 2rem;
  box-shadow:var(--e3), inset 0 1px 0 rgba(255,255,255,.7);
  animation:entra .4s var(--sai) both;
}
.dark .au-box{
  background:#1c1d23; border-color:rgba(255,255,255,.08);
  box-shadow:var(--e3), inset 0 1px 0 rgba(255,255,255,.05);
}
/* O fio de ouro no alto do cartão — a mesma assinatura do trilho do KPI e
   do cabeçalho do modal. É o detalhe que costura login e app. */
.au-box{
  background-image:linear-gradient(90deg, var(--ouro) 0%, color-mix(in srgb, var(--ouro) 22%, transparent) 58%, transparent 100%);
  background-repeat:no-repeat; background-size:100% 3px; background-position:top left;
}
/* Numa tela estreita a moldura atrapalha: ela vira uma caixa de 320px
   dentro de uma tela de 375px, com 12px de fundo aparecendo de cada lado —
   o pior dos dois desenhos. Abaixo de 480px o cartão se dissolve. */
@media (max-width:480px){
  .au-box{
    background:transparent; background-image:none; border:0;
    box-shadow:none; padding:0; max-width:23rem;
  }
}
/* Nas telas estreitas o painel da marca some; a marca reaparece aqui em cima,
   pequena, para a tela não começar com um formulário sem dono. */
.au-mobile-logo{ display:flex; align-items:center; gap:.7rem; margin-bottom:2rem; }
.au-mobile-logo .au-mark{ width:2.4rem; height:2.4rem; border-radius:.65rem; box-shadow:0 2px 10px rgba(0,0,0,.15); }
.au-mobile-logo .au-mark svg{ width:1.7rem; height:1.7rem; }
.au-mobile-logo .au-word{ font-size:1.05rem; color:#1e293b; }
.dark .au-mobile-logo .au-word{ color:#fff; }
@media (min-width:1024px){ .au-mobile-logo{ display:none; } }

.au-titulo{ font-size:1.6rem; font-weight:600; letter-spacing:-.01em; line-height:1.2; }
.au-sub{ font-size:.875rem; color:#64748b; margin-top:.45rem; line-height:1.5; }
.dark .au-sub{ color:#94a3b8; }
.au-form{ margin-top:1.75rem; display:flex; flex-direction:column; gap:1rem; }

.au-campo{ display:block; }
.au-rot{
  display:block; font-size:.7rem; font-weight:600; letter-spacing:.08em;
  text-transform:uppercase; color:#64748b; margin-bottom:.4rem;
}
.dark .au-rot{ color:#94a3b8; }
.au-inp-wrap{ position:relative; display:block; }
.au-inp{
  width:100%; border:1px solid #d5d3cd; border-radius:.6rem; background:#fff;
  padding:.7rem .85rem; font-size:.9rem; color:inherit; outline:none;
  transition:border-color .15s, box-shadow .15s;
}
.au-inp.tem-olho{ padding-right:2.6rem; }
.au-inp:focus{ border-color:#bf9b4e; box-shadow:0 0 0 3px rgba(191,155,78,.18); }
.au-inp.ok{ border-color:#10b981; }
.au-inp.ok:focus{ box-shadow:0 0 0 3px rgba(16,185,129,.18); }
.au-inp.nao{ border-color:#f43f5e; }
.au-inp.nao:focus{ box-shadow:0 0 0 3px rgba(244,63,94,.18); }
.dark .au-inp{ background:#1f2026; border-color:rgba(255,255,255,.12); }

.au-olho{
  position:absolute; right:.35rem; top:50%; transform:translateY(-50%);
  width:2rem; height:2rem; display:grid; place-items:center; border-radius:.45rem;
  color:#94a3b8; cursor:pointer;
}
.au-olho svg{ width:1.05rem; height:1.05rem; }
.au-olho:hover{ color:#475569; background:rgba(0,0,0,.04); }
.au-olho.ligado{ color:#8a6a12; }
.dark .au-olho:hover{ color:#e2e8f0; background:rgba(255,255,255,.08); }
.dark .au-olho.ligado{ color:#d9bd6b; }

/* Botão principal: dourado escovado com tinta grafite — o mesmo contraste do
   .btn-primary do app, que passa AA com folga (branco sobre dourado não passa). */
.au-btn{
  width:100%; border-radius:.6rem; padding:.75rem 1rem; font-size:.9rem; font-weight:700;
  letter-spacing:.01em; color:#1b1608; cursor:pointer;
  background:linear-gradient(180deg,#d0ac5c 0%,#bf9b4e 55%,#a8873c 100%);
  box-shadow:0 1px 2px rgba(0,0,0,.12); transition:filter .15s, transform .05s, box-shadow .15s;
}
.au-btn:hover{ filter:brightness(1.06); box-shadow:0 3px 12px rgba(191,155,78,.35); }
.au-btn:active{ transform:translateY(1px); }
.au-btn:disabled{ opacity:.55; cursor:not-allowed; filter:none; box-shadow:none; }

.au-link{
  width:100%; text-align:center; font-size:.78rem; color:#64748b; cursor:pointer; padding-top:.1rem;
}
.au-link:hover{ color:#8a6a12; text-decoration:underline; }

/* Seletor de família no login (quem é membro de mais de uma). */
.au-nucleos{ display:grid; gap:.55rem; }
.au-nucleo{
  display:flex; align-items:center; justify-content:space-between; gap:.75rem;
  width:100%; text-align:left; cursor:pointer;
  border:1px solid #e2e8f0; border-radius:.6rem; padding:.8rem 1rem;
  background:#fff; transition:border-color .15s, box-shadow .15s, transform .05s;
}
.au-nucleo:hover{ border-color:#bf9b4e; box-shadow:0 2px 10px rgba(191,155,78,.18); }
.au-nucleo:active{ transform:translateY(1px); }
.au-nuc-nome{ font-weight:700; font-size:.95rem; color:#1b1608; }
.au-nuc-papel{ font-size:.78rem; color:#64748b; }
.dark .au-nucleo{ background:rgba(255,255,255,.03); border-color:rgba(255,255,255,.12); }
.dark .au-nuc-nome{ color:#f1e9d4; }
.dark .au-link{ color:#94a3b8; }
.dark .au-link:hover{ color:#d9bd6b; }

.au-erro{ font-size:.8rem; line-height:1.45; color:#e11d48; }
.au-erro.ok{ color:#059669; }
.dark .au-erro{ color:#fb7185; }
.dark .au-erro.ok{ color:#34d399; }
.au-aviso{ font-size:.85rem; line-height:1.55; color:#64748b; }
.dark .au-aviso{ color:#94a3b8; }

/* Lista de conferência da senha: cada linha fica verde no caractere em que
   passa a valer (as regras vêm do servidor — ver auth.js). */
.au-regras{ display:flex; flex-direction:column; gap:.35rem; margin-top:-.35rem; }
.au-regras li{
  display:flex; align-items:center; gap:.5rem; font-size:.75rem; color:#94a3b8;
  transition:color .15s;
}
.au-regras li .marca{
  width:1rem; height:1rem; flex:0 0 auto; display:grid; place-items:center;
  border-radius:999px; font-size:.6rem; line-height:1;
  box-shadow:inset 0 0 0 1px #cbd5e1; transition:background .15s, color .15s, box-shadow .15s;
}
.dark .au-regras li .marca{ box-shadow:inset 0 0 0 1px rgba(255,255,255,.2); }
.au-regras li.ok{ color:#059669; }
.au-regras li.ok .marca{ background:#10b981; color:#fff; box-shadow:inset 0 0 0 1px #10b981; }
.dark .au-regras li.ok{ color:#34d399; }

.au-pe{
  margin-top:1.5rem; padding-top:1.15rem; border-top:1px solid #e6e4de;
  font-size:.72rem; line-height:1.6; color:#94a3b8;
}
.dark .au-pe{ border-top-color:rgba(255,255,255,.08); }
/* `break-all` partiria o comando no meio de uma palavra ("pyth on") e o
   usuário copiaria errado. Quebra só onde já há espaço; se não couber, rola. */
.au-pe code{
  display:inline-block; max-width:100%; overflow-x:auto; vertical-align:bottom;
  font-size:.68rem; padding:.05rem .3rem; border-radius:.25rem;
  background:rgba(0,0,0,.05); color:#64748b; white-space:nowrap;
}
.dark .au-pe code{ background:rgba(255,255,255,.07); color:#cbd5e1; }

/* ----------------------------------------------------------------------
   Leitura de comprovante (§7.4)

   O OCR leva de meio a três segundos. Sem nada girando na tela, esse
   intervalo — logo depois de a câmera fechar — é lido como travamento, e a
   pessoa toca de novo. O giro não é enfeite: é a diferença entre "está
   pensando" e "morreu".
   ---------------------------------------------------------------------- */
/* O botão precisa ser flex AQUI, e não pelas classes do Tailwind: o `.btn` não
   declara display, e o preflight do Tailwind põe `display:block` em todo `svg`.
   Num botão inline-block isso joga o ícone para uma linha só dele, encostado na
   esquerda, com o texto centralizado embaixo — foi o que apareceu na primeira
   medição. Sendo regra do próprio arquivo, não depende de o JIT do Tailwind ter
   gerado `.flex` para uma classe que só existe em HTML criado por JavaScript. */
#txCamBtn{ display:flex; align-items:center; justify-content:center; gap:.5rem; }

.cam-girando{
  width:.9rem; height:.9rem; flex:0 0 auto; display:inline-block;
  border:2px solid currentColor; border-right-color:transparent;
  border-radius:50%; opacity:.75;
  animation:cam-gira .7s linear infinite;
}
@keyframes cam-gira{ to{ transform:rotate(360deg); } }
/* Quem pediu menos movimento no sistema recebe pulso em vez de rotação. */
@media (prefers-reduced-motion:reduce){
  .cam-girando{ animation:cam-pulsa 1.4s ease-in-out infinite; }
  @keyframes cam-pulsa{ 0%,100%{ opacity:.25 } 50%{ opacity:.9 } }
}

/* ======================================================================
   CELULAR — o app visto de 375px

   Este bloco existe porque o app nasceu de uma planilha e cresceu numa tela
   larga: até aqui o arquivo inteiro tinha três @media, duas delas da tela de
   acesso. O que foi medido no aparelho, com o layout que estava:

     · abrir o ☰ deixava o conteúdo com 135px de 375 — a barra voltava como
       COLUNA da linha flex, empurrando a tela em vez de cobri-la;
     · nenhum dos 24 alvos de toque chegava aos 44px recomendados;
     · 11 campos abaixo de 16px, e abaixo disso o WebView dá zoom sozinho ao
       focar — a tela pula e sai do lugar a cada campo;
     · "R$ 1.284.930,55" precisava de 161px num cartão de 120px, e vazava:
       num app de dinheiro, número cortado é o pior defeito possível;
     · a célula do calendário ficava com 39px de largura, larga o bastante
       para a tarja do evento e estreita demais para uma letra dela.

   Fica tudo no fim do arquivo de propósito: assim estas regras ganham os
   empates de especificidade com o que veio antes, sem precisar de !important.
   O corte é 767.98px para casar exatamente com o `md:` do Tailwind, que é
   quem decide o resto da casca.
   ====================================================================== */

/* O véu e a barra de baixo não existem no desktop. */
.nav-fundo{ display:none; }
.tabbar{ display:none; }
/* E ela também não existe ENQUANTO ESTÁ VAZIA. O #tabbar nasce no HTML e só é
   preenchido depois do portão (§4.1) — sem esta linha, a tela de acesso teria
   uma faixa vazia com fio e sombra encostada no rodapé. */
.tabbar:empty{ display:none !important; }

/* ----------------------------------------------------------------------
   O DETALHE DA LINHA — o que fazer com as colunas que não cabem no celular

   Uma tabela de 13 colunas mede 966px; a tela do celular dá 314. Rolar de
   lado três telas para ver o "Total" de uma operação é o mesmo que não ter
   a informação. E virar cada tabela numa lista de cartões custaria reescrever
   as ~40 tabelas do app, além de matar a leitura EM COLUNA — que é justamente
   o que faz uma tabela de dinheiro servir.

   O trato aqui: cada tabela declara, num atributo só, quais colunas valem a
   viagem (`data-mob="2 7 8"`, índices de 1). O resto some no celular e volta
   num toque, embaixo da própria linha, com o rótulo que está no <thead>.
   Nenhuma tabela sem o atributo muda de comportamento.

   O detalhe NUNCA carrega controle (botão, campo, seleção). Não é preferência:
   os botões de ✎/🗑 são ligados um a um no app.js, e um clone deles seria um
   botão MORTO — que é pior do que botão nenhum. Por isso a coluna de ações,
   quando existe, fica entre as visíveis.
   --------------------------------------------------------------------- */
tr.tbl-det{ display:none; }        /* só existe no celular (ver bloco CELULAR) */
.tbl-dica{ display:none; }         /* idem: o aviso de "toque na linha" */

@media (max-width:767.98px){

  /* ---- A barra vira gaveta -----------------------------------------
     `fixed` é o ponto todo: fora do fluxo, ela não tem como espremer o
     conteúdo. Fechada, fica encostada do lado de fora; `visibility` entra
     junto para ela não ser alcançável pelo Tab enquanto está escondida —
     `transform` sozinho deixaria o foco cair num menu invisível. */
  #sidebar{
    position:fixed; top:0; left:0; bottom:0; z-index:45;
    width:17rem; max-width:82vw;
    transform:translateX(-100%); visibility:hidden;
    transition:transform .24s cubic-bezier(.4,0,.2,1), visibility 0s linear .24s;
    box-shadow:none;
  }
  html.nav-aberta #sidebar{
    transform:none; visibility:visible;
    transition:transform .24s cubic-bezier(.4,0,.2,1), visibility 0s;
    box-shadow:0 0 45px rgba(0,0,0,.55);
  }
  html.nav-aberta{ overflow:hidden; }          /* o fundo não rola por baixo */
  html.nav-aberta .nav-fundo{
    display:block; position:fixed; inset:0; z-index:44;
    background:rgba(12,11,8,.55); backdrop-filter:blur(1.5px);
  }

  /* O modo rail é uma escolha de desktop (barra estendida × só ícones). Dentro
     de uma gaveta ele não faz sentido: a gaveta já é o "recolhido", e abrir uma
     gaveta de 76px só com ícones é pior que não abrir. Desfaz o que a .rail
     tinha escondido e tira o botão do ar. */
  #sidebar.rail{ width:17rem; }
  #sidebar.rail .side-head{ flex-direction:row; padding-left:1.25rem; padding-right:1.25rem; }
  #sidebar.rail .side-words{ display:block; }
  /* `flex`, não `block`: o rótulo do grupo tem texto + contador + chevron
     numa linha só (ver a seção dos grupos recolhíveis). */
  #sidebar.rail .nav-group{ display:flex; }
  /* E os grupos voltam a obedecer o recolhimento — dentro da gaveta o
     `.rail` não vale, então quem manda é a classe `.aberta`. */
  #sidebar.rail .nav-list{ max-height:0; }
  #sidebar.rail .nav-sec.aberta > .nav-list{ max-height:var(--alt, 32rem); }
  #sidebar.rail .nav-list-in::before{ display:block; }
  #sidebar.rail .nav-sec + .nav-sec{ margin-top:.5rem; padding-top:0; border-top:0; }
  #sidebar.rail .nav-item{ justify-content:flex-start; padding-left:1.9rem; padding-right:1.25rem; }
  #sidebar.rail .nav-item.active::before{ left:1.1rem; }
  #sidebar.rail .nav-item > span:not(.nav-badge){ display:inline; }
  #sidebar.rail .nav-badge{ position:static; width:auto; height:auto; min-width:1.5rem;
    padding:0 .4rem; font-size:.68rem; line-height:1.5rem; margin-left:auto; }
  #sidebar.rail #sidebarProfile{ padding-left:1rem; padding-right:1rem; }
  #sidebar.rail .sb-meta, #sidebar.rail #sessaoInfo{ display:block; }
  #sidebar.rail .sessao-bar{ justify-content:flex-start; }
  .rail-toggle{ display:none; }

  /* ---- Alvos de toque ----------------------------------------------
     44px é a medida que a Apple e o Google publicam, e não é preciosismo: é a
     largura média da polpa do dedo. Abaixo disso o erro de toque deixa de ser
     exceção — e num app onde o botão vizinho é 🗑, errar tem preço. */
  .nav-item{ min-height:2.75rem; font-size:.92rem; }
  .nav-ico{ width:1.15rem; height:1.15rem; }
  .top-btn{ min-width:2.75rem; min-height:2.75rem; display:inline-grid; place-items:center; padding:.5rem; }
  /* A busca encolhida (abaixo de 900px ela vira só a lupa) tinha 2.15rem = 34px
     e ficou de fora do arredondamento geral: ela não é `.top-btn`, é o campo
     falso disfarçado de ícone. Aqui ela recebe o mesmo alvo dos vizinhos. */
  .top-busca{ width:2.75rem; height:2.75rem; }
  #menuBtn{ margin-left:-.35rem; }
  .btn{ padding:.65rem 1rem; min-height:2.75rem; }
  /* Os ✎/🗑 no fim da linha da tabela são só um caractere: sem isto o alvo tem
     o tamanho da letra, e o vizinho é o botão de apagar. */
  table.tbl td button{ min-width:2.75rem; min-height:2.75rem; }
  .chip{ min-height:2.25rem; padding:.3rem .6rem .3rem .7rem; font-size:.75rem; }
  /* O ✕ do chip tinha 18px — e o que ele faz (remover o filtro) é irreversível
     do ponto de vista de quem estava lendo a lista filtrada. A área cresce por
     PADDING, com margem negativa para o chip não engordar junto. */
  .chip-x{ width:1.9rem; height:1.9rem; margin:-.35rem -.25rem -.35rem 0; opacity:.85; }
  .filter-clear{ min-height:2.25rem; font-size:.78rem; }
  .combo-opt{ min-height:2.75rem; padding:.6rem .7rem; }
  /* O ✕ que limpa o combo tinha ~14px de lado — o alvo mais difícil do app,
     e vizinho do texto que a pessoa acabou de escolher. Vira um quadrado de
     44px encostado na direita do campo (que já tem 44px de altura). */
  .combo-clear{
    top:0; bottom:0; right:0; transform:none;
    width:2.75rem; display:grid; place-items:center; padding:0;
  }
  .combo-input{ padding-right:2.75rem; }
  .aba-opt{ min-height:2.75rem; padding:.65rem .7rem; }
  /* Botões de texto solto ("limpar tudo", "marcar todas") tinham 16px de
     altura. Não dá para engordá-los sem afastar o texto vizinho, então o
     alvo cresce só para BAIXO e para cima, por padding, sem mexer na linha. */
  #app button.underline, #app button.hover\:underline{ padding:.5rem 0; }

  /* ---- A tira de sub-abas --------------------------------------------
     Ela já rolava; o que faltava era alcance e aviso. Alvo de 44px (era 38),
     e o desbote da beirada vem das classes .tem-esq/.tem-dir (ver a seção das
     abas, mais acima) — que o app.js põe medindo a rolagem de verdade. */
  .abas{ gap:.1rem; margin-bottom:.85rem; }
  .aba{ min-height:2.75rem; padding:.7rem .8rem; font-size:.9rem; display:flex; align-items:center; }
  .sim-tab{ min-height:2.75rem; padding:.65rem .7rem; display:flex; align-items:center; }
  /* "Sair" no pé da barra tinha 17px de altura — o menor alvo do app inteiro,
     e o de consequência mais chata: sair sem querer. */
  .sessao-bar #btnSair{ min-height:2.5rem; padding:0 .6rem; margin-right:-.6rem; }

  /* ---- Campos: 16px é regra, não gosto ------------------------------
     Com fonte menor que 16px o navegador do celular entende que o campo é
     pequeno demais para digitar e dá zoom ao focar. A tela salta, o resto do
     formulário sai de vista, e ao sair do campo nem sempre volta. */
  .field, input, select, textarea{ font-size:16px; }
  .field{ padding:.7rem .8rem; }
  /* Precisa vir DEPOIS do `.field` acima: o `padding` abreviado apaga o
     `padding-left:2.1rem` que abria espaço para a lupa, e ela passa a ser
     desenhada por cima do texto do campo. */
  .field-search{ padding-left:2.35rem; background-position:.8rem center; }
  /* Exceção: o seletor de competência abre a roda nativa, não teclado — não há
     zoom a evitar. O `max-width:8rem` que morava aqui era a tentativa antiga de
     salvar o título espremendo o mês, e ele custava o outro lado: "agosto de
     2026" virava "agosto de 20". Agora a competência tem uma faixa inteira e
     não disputa nada — o teto sai, e o campo cresce até o fim da faixa. O que
     fica é só o que é dele: a altura do alvo de toque.

     A FONTE de 16px entrou na v14.85. A nota antiga dizia que aqui não havia
     zoom a evitar porque a competência abre a roda nativa — mas o Safari do
     iOS aplica o zoom no FOCO de qualquer campo abaixo de 16px, tenha ele
     teclado ou não, e a medição pegou este campo em 14,4px. Custa nada: desde
     que a competência ganhou faixa própria ela não disputa largura com
     ninguém, que era o motivo de tê-la deixado menor. */
  #globalMonth{ min-height:2.75rem; font-size:16px; }

  /* ---- Cartões e KPI ------------------------------------------------
     O valor encolhe de 1.75rem para 1.3rem: é o tamanho em que a maior cifra
     plausível ("R$ 1.284.930,55") volta a caber numa linha dentro do cartão de
     meia largura. Continua sendo o maior texto da tela — segue sendo o assunto. */
  .card{ padding:.9rem .85rem; }
  /* 1.1rem não é chute: em meia largura sobram 134px para o valor, e
     "R$ 1.284.930,55" — sete dígitos, que é a ordem de grandeza do patrimônio
     aqui, não um caso extremo — pede 150px no tamanho anterior. Sem isto ele
     quebra em duas linhas, com o "R$" órfão em cima do número. Continua sendo
     o maior texto do cartão, que é o que importa. */
  .kpi-value{ font-size:1.1rem; }
  .kpi-label{ font-size:.63rem; letter-spacing:.08em; }
  .kpi-label::before{ margin-bottom:.4rem; }

  /* ---- Tabelas ------------------------------------------------------
     Uma tabela de 11 colunas não vira lista de cartões sem reescrever as ~48
     tabelas do app, e transformar coluna em rótulo repetido custa a leitura em
     coluna — que é justamente o que faz uma tabela de dinheiro servir. Então
     ela continua tabela e rola de lado; o que faltava era DIZER isso.

     A sombra nas bordas é o aviso: aparece só do lado em que ainda há tabela
     escondida e some quando chega ao fim. É CSS puro — os dois gradientes
     lineares (cor do cartão) andam com o conteúdo por `background-attachment:
     local` e cobrem a sombra quando não há mais o que rolar; os radiais ficam
     presos por `scroll`. Sem uma linha de JavaScript e sem evento de rolagem. */
  .overflow-x-auto{
    background:
      linear-gradient(to right, var(--superficie) 30%, rgba(255,255,255,0)) left center,
      linear-gradient(to left,  var(--superficie) 30%, rgba(255,255,255,0)) right center,
      radial-gradient(farthest-side at 0 50%,   rgba(23,20,12,.16), rgba(23,20,12,0)) left center,
      radial-gradient(farthest-side at 100% 50%,rgba(23,20,12,.16), rgba(23,20,12,0)) right center;
    background-repeat:no-repeat;
    background-size:2.2rem 100%, 2.2rem 100%, .85rem 100%, .85rem 100%;
    background-attachment:local, local, scroll, scroll;
    -webkit-overflow-scrolling:touch;
    overscroll-behavior-x:contain;   /* rolar a tabela não navega para trás */
  }
  .dark .overflow-x-auto{
    background-image:
      linear-gradient(to right, var(--superficie) 30%, rgba(0,0,0,0)),
      linear-gradient(to left,  var(--superficie) 30%, rgba(0,0,0,0)),
      radial-gradient(farthest-side at 0 50%,   rgba(0,0,0,.5), rgba(0,0,0,0)),
      radial-gradient(farthest-side at 100% 50%,rgba(0,0,0,.5), rgba(0,0,0,0));
  }
  table.tbl{ font-size:.8rem; }
  table.tbl th{ padding:.45rem .55rem; font-size:.62rem; }
  table.tbl td{ padding:.6rem .55rem; }
  /* AS RETICÊNCIAS DENTRO DE CÉLULA CAEM NO CELULAR.
     O `truncate` existe nas tabelas para proteger a ALTURA DA LINHA numa tela
     onde cabem vinte linhas — o recurso escasso lá é o vertical. No celular
     cabem seis, e a conta se inverte: medido nas Metas por classe, "1.2.1.001
     · Renda Variável Nacional" pedia 167px numa coluna `w-32` de 128 e chegava
     ao usuário como "1.2.1.001 · Renda Va…". Numa tela de dinheiro, o nome da
     conta cortado é exatamente o defeito que não se pode ter. Aqui ele quebra
     em duas linhas e fica inteiro. */
  #app table.tbl td .truncate{
    overflow:visible; text-overflow:clip; white-space:normal;
  }

  /* ---- As colunas que valem a viagem ---------------------------------
     Medido a 375px (314px úteis dentro do card): o razão pedia 896px, as
     operações de investimento 966, o orçamento 733. Duas a três telas de
     rolagem lateral por linha — e a rolagem lateral tem um custo que a
     vertical não tem: perde-se a referência de QUAL linha se está lendo.

     `data-mob` lista as colunas que ficam (índices de 1, separados por
     espaço). O seletor abaixo é o contrário disso: esconde a coluna N em
     toda tabela que TEM o atributo e NÃO nomeia o N — que é o que o `~=`
     (casa uma palavra da lista) permite escrever sem JavaScript.

     `tr:not(.tbl-det)` é obrigatório: a linha de detalhe tem uma célula só,
     e sem a exceção ela sumiria junto com a "coluna 1" da tabela. */
  table.tbl[data-mob]:not([data-mob~="1"])  > * > tr:not(.tbl-det) > *:nth-child(1),
  table.tbl[data-mob]:not([data-mob~="2"])  > * > tr:not(.tbl-det) > *:nth-child(2),
  table.tbl[data-mob]:not([data-mob~="3"])  > * > tr:not(.tbl-det) > *:nth-child(3),
  table.tbl[data-mob]:not([data-mob~="4"])  > * > tr:not(.tbl-det) > *:nth-child(4),
  table.tbl[data-mob]:not([data-mob~="5"])  > * > tr:not(.tbl-det) > *:nth-child(5),
  table.tbl[data-mob]:not([data-mob~="6"])  > * > tr:not(.tbl-det) > *:nth-child(6),
  table.tbl[data-mob]:not([data-mob~="7"])  > * > tr:not(.tbl-det) > *:nth-child(7),
  table.tbl[data-mob]:not([data-mob~="8"])  > * > tr:not(.tbl-det) > *:nth-child(8),
  table.tbl[data-mob]:not([data-mob~="9"])  > * > tr:not(.tbl-det) > *:nth-child(9),
  table.tbl[data-mob]:not([data-mob~="10"]) > * > tr:not(.tbl-det) > *:nth-child(10),
  table.tbl[data-mob]:not([data-mob~="11"]) > * > tr:not(.tbl-det) > *:nth-child(11),
  table.tbl[data-mob]:not([data-mob~="12"]) > * > tr:not(.tbl-det) > *:nth-child(12),
  table.tbl[data-mob]:not([data-mob~="13"]) > * > tr:not(.tbl-det) > *:nth-child(13),
  table.tbl[data-mob]:not([data-mob~="14"]) > * > tr:not(.tbl-det) > *:nth-child(14){ display:none; }

  /* Com três colunas a tabela cabe: some o piso de largura e a repartição
     fixa, que foram medidos para a tela larga e aqui só empurrariam. */
  table.tbl[data-mob]{ width:100%; }
  /* Menos ar entre as colunas do que numa tabela larga: com três colunas, os
     .55rem de cada lado somam 26px de vão numa tela de 314. Foi a diferença
     entre o orçamento caber (314) e não caber (337) — e ele é uma tabela em
     que a primeira coluna já gasta recuo com a árvore de contas. */
  table.tbl[data-mob] th, table.tbl[data-mob] td{ padding-left:.4rem; padding-right:.4rem; }
  table.tbl-razao[data-mob]{ table-layout:auto; min-width:0; }
  /* A coluna "Valor" do razão é o inverso das outras: só existe AQUI. */
  table.tbl-razao[data-mob] .c-mob{ display:table-cell; }
  /* Campo DENTRO de célula (o orçado do OBZ é um `w-28` = 112px fixos): com
     três colunas numa tela de 314px, 112 deles presos num só campo estouram a
     tabela sozinhos. A largura passa a ser a da coluna. */
  table.tbl[data-mob] td .field{ width:100%; min-width:0; }
  table.tbl[data-mob] td .field.w-28,
  table.tbl[data-mob] td .field.w-24,
  table.tbl[data-mob] td .field.w-32{ width:100%; }
  /* O `!py-1` do orçado (utilitário do Tailwind, com !important) deixava o
     campo com 31px de altura — abaixo do alvo de toque, e é um campo em que
     se DIGITA. `min-height` passa por cima do padding sem brigar com ele. */
  table.tbl[data-mob] td .field{ min-height:2.75rem; }
  /* No razão, o histórico volta a poder QUEBRAR. As reticências existem
     para proteger a altura da linha numa tela onde cabem 20 lançamentos;
     num celular cabem 6, e cortar "Supermercado Pão de Aç…" para ganhar
     meia linha é trocar a informação pelo espaço em branco. */
  table.tbl-razao[data-mob] td.cel-hist{ white-space:normal; overflow:visible; }

  /* A COLUNA DE AÇÕES PODE QUEBRAR. Ela é a única que ficou obrigatoriamente
     visível (o detalhe não carrega controle), e por isso é ela que sobra
     quando a conta não fecha: no Plano de Contas são ＋/✎/🗑, três alvos de
     44px = 168px de uma tela de 299, mais que a coluna do nome da conta. Com
     `white-space:nowrap` a única saída era rolar de lado.

     Aqui os botões descem para uma segunda linha em vez de empurrar a tabela.
     É a troca certa: altura de linha, num celular, é o recurso barato — e os
     44px de cada alvo ficam de pé, que é o que não podia ceder. */
  table.tbl[data-mob] tbody td:last-child,
  table.tbl[data-mob] tbody td.cel-acoes{ white-space:normal; }

  /* A linha que abre. O ouro à esquerda é o mesmo da linha sob o cursor no
     desktop — aqui ele diz "esta é a linha que você abriu". */
  table.tbl[data-mob] tbody tr:not(.tbl-det){ cursor:pointer; }
  table.tbl[data-mob] tbody tr.tbl-aberta > td{ background:var(--superficie-2); }
  table.tbl[data-mob] tbody tr.tbl-aberta > td:first-child{ box-shadow:inset 2px 0 0 var(--ouro); }
  tr.tbl-det{ display:table-row; }
  tr.tbl-det > td{
    padding:0 !important; border-bottom:1px solid var(--linha) !important;
    background:var(--superficie-2);
    box-shadow:inset 2px 0 0 var(--ouro);
  }
  .dark tr.tbl-det > td{ background:rgba(255,255,255,.045); }
  /* Rótulo à esquerda, valor à direita: a mesma leitura da tabela de onde
     ele saiu, só que empilhada. `max-content` na primeira coluna para o
     rótulo nunca quebrar — quem quebra é o valor, se precisar. */
  .tbl-det-lista{
    display:grid; grid-template-columns:max-content minmax(0,1fr);
    gap:.4rem .9rem; padding:.7rem .85rem .8rem; margin:0;
    font-size:.78rem;
  }
  .tbl-det-lista dt{ color:var(--tinta-tenue); font-weight:500; }
  .tbl-det-lista dd{ margin:0; text-align:right; color:var(--tinta); font-weight:550; }
  .tbl-det-lista dd .pill{ vertical-align:.05em; }
  /* As células vêm da tabela e trazem a formatação delas. Duas precisam ser
     desfeitas aqui: a conta é um flex que alinharia à esquerda dentro de um
     bloco que alinha à direita, e as reticências (que existem para proteger a
     ALTURA DA LINHA da tabela) não têm sentido num detalhe que já é uma linha
     por informação — aqui o texto pode quebrar e ficar inteiro. */
  .tbl-det-lista dd .cel-conta{ justify-content:flex-end; flex-wrap:wrap; }
  .tbl-det-lista dd .cel-nome,
  .tbl-det-lista dd .cel-hist{ overflow:visible; text-overflow:clip; white-space:normal; }
  /* Um aviso por tabela, no pé: sem ele a linha que abre é um segredo. */
  .tbl-dica{
    margin-top:.5rem; font-size:.7rem; color:var(--tinta-tenue);
    display:flex; align-items:center; gap:.35rem;
  }
  .tbl-dica::before{ content:'⌄'; font-size:.9rem; line-height:1; opacity:.8; }
  /* As larguras fixas do markup (w-28, w-32, w-40) foram escolhidas para uma
     tela larga; aqui elas só empurram a tabela para longe. `table.tbl th`
     (0,1,2) vence `.w-28` (0,1,0) sem precisar de !important. */
  table.tbl th{ width:auto; }
  /* A primeira coluna é a âncora da leitura (data, ticker, competência): fica
     presa enquanto o resto desliza, senão o usuário rola até a última coluna e
     não sabe mais de que linha ela é.

     Não vale para quem tem `data-mob`: essas tabelas passaram a caber, então
     não há nada deslizando para ancorar — e a linha de detalhe, que é uma
     célula só, viraria uma tarja presa no canto esquerdo. */
  table.tbl:not([data-mob]) th:first-child,
  table.tbl:not([data-mob]) td:first-child{
    position:sticky; left:0; z-index:1; background:var(--superficie);
  }
  table.tbl:not([data-mob]) tbody tr:hover td:first-child{ background:var(--superficie-2); }
  .dark table.tbl:not([data-mob]) tbody tr:hover td:first-child{ background:#1f2026; }

  /* ---- Grade de filtros e formulários -------------------------------
     Os `grid-cols-2` sem prefixo responsivo do app.js viram uma coluna abaixo
     de 430px, onde 2 colunas dão ~144px por campo — largura em que um select
     de conta contábil mostra "3.1.02 Alim…" e mais nada. */
  .filterbar .grid{ gap:.6rem; }

  /* ---- Modal vira folha ---------------------------------------------
     Encostada embaixo, cantos arredondados só em cima: é onde o polegar chega.
     `#modal .modal-caixa` (1,1,0) precisa vencer o `w-[95%] max-w-lg` do
     Tailwind (0,1,0), que o Play CDN injeta DEPOIS deste arquivo. */
  #modal .modal-caixa{
    width:100%; max-width:none; margin:2.5rem 0 0;
    min-height:calc(100% - 2.5rem);
    border-radius:1.1rem 1.1rem 0 0;
  }
  #modal .modal-cab{ border-radius:1.1rem 1.1rem 0 0; padding-top:1.1rem; padding-bottom:1.1rem; }
  #modal .modal-cab [data-close]{ padding:.35rem .5rem; margin:-.35rem -.5rem; }
  #modalBody{ padding-bottom:calc(1.25rem + env(safe-area-inset-bottom)); }

  /* ---- Calendário ---------------------------------------------------
     Em 39px de largura o nome do evento não cabe — nem abreviado. Vira uma
     tarja de cor: diz "tem coisa nesse dia" e de que tipo, que é o que a
     grade do mês precisa responder. O nome está a um toque de distância, no
     detalhe do dia. */
  .cal-cell, .cal-cell.is-blank{ min-height:3.2rem; padding:.25rem .2rem; }
  .cal-day{ font-size:.7rem; }
  .cal-cell.is-today .cal-day{ width:1.2rem; height:1.2rem; font-size:.65rem; }
  /* A tarja perde o fio da esquerda: num retângulo de 5px de altura, 2,5px de
     borda são metade da peça — e ela deixaria de ler como "cor do tipo" para
     ler como "duas cores". Aqui a cor volta a ser o fundo inteiro. */
  .cal-ev{
    font-size:0; line-height:0; height:.34rem; padding:0;
    margin-top:.2rem; border-radius:999px; border-left:0;
  }
  /* Sem texto por cima, a tarja precisa da cor CHEIA. Os tons de 12–22% de
     alfa foram calibrados para servir de FUNDO a uma legenda escrita;
     virando barra de 5px eles somem — e deixam de bater com o quadradinho
     da legenda logo abaixo. Aqui a barra e a legenda usam a mesma cor. */
  .cal-ev.pay { background:var(--g-critico); }
  .cal-ev.rec { background:var(--g-bom); }
  .cal-ev.nota{ background:var(--linha-forte); border:0; }

  /* ---- Barra de cima: duas linhas, não uma ----------------------------
     A tentativa anterior foi espremer tudo numa linha só — o título ganhou
     `flex:1 1 auto` e a competência, um teto de 8rem. Medido no aparelho
     depois disso: o título ficou com VINTE E QUATRO pixels de 375. A conta
     não fecha e não tinha como fechar: menu 44 + busca 34 + tema 44 + a
     competência (128 do campo + 2×24 das setas + bordas = 178) já passam de
     324px, e as folgas comem o resto. Um teto menor ainda comeria o mês
     ("agosto de 20…"), que é o outro defeito que se queria evitar.

     Então a barra quebra. A competência desce para uma faixa inteira dela —
     onde cabe o mês por extenso E setas de 44px — e a primeira linha volta a
     ser o que uma barra de app é: onde estou, buscar, tema.

     `flex-wrap` só resolve porque a competência é FILHA DIRETA desta linha
     (ver index.html); enquanto ela morava dentro do agrupamento da direita,
     não havia como fazê-la quebrar sozinha. */
  header.app-top .top-linha{
    min-height:3.25rem; gap:.4rem;
    flex-wrap:wrap; align-items:center;
    padding-top:.25rem; padding-bottom:.35rem;
  }
  header.app-top .top-onde{ flex:1 1 auto; }
  .top-title{ font-size:1rem; }
  /* A faixa da competência: linha inteira, ordem 9 (depois de tudo). O
     `order` não é enfeite — sem ele a quebra levaria junto o botão de tema,
     que vem depois dela no HTML. */
  .mes-nav{ order:9; flex:1 0 100%; }
  /* O campo ocupa o meio inteiro: o mês aparece por extenso E o alvo que abre
     a roda do sistema passa a ser a faixa toda, não um retângulo de 128px no
     centro. `width:100%` junto do `flex:1` porque um <input type=month> não
     estica só com `flex-grow` — ele tem largura intrínseca de conteúdo. */
  .mes-nav .field{
    min-width:0; flex:1 1 auto; width:100%;
    font-size:.9rem; padding:.5rem .3rem !important;
  }
  /* 2.75rem = 44px. As setas eram 24px de largura — o menor alvo de toque da
     barra, e o de uso mais repetido do app inteiro. */
  .mes-seta{ width:2.75rem; min-height:2.75rem; }
  .mes-seta svg{ width:1.15rem; height:1.15rem; }
  /* O selo de "competência fechada" NÃO ganha `order`: sem ele fica na ordem
     natural (0) e continua na primeira linha, entre a busca e o tema — que é
     onde um selo de estado deve estar. É só o cadeado; o "fechada" ao lado
     dele já é `hidden sm:inline` no app.js. */
  /* A trama e o bafo do cartão de abertura foram desenhados para 500px de
     largura; num cartão de 340px eles viram manchas. O grafite e o ouro
     ficam — é a marca —, o resto sai. */
  .kpi-hero{ padding:1.1rem 1rem 1rem; min-height:0; }
  .kpi-hero-valor{ font-size:1.65rem; }
  .kpi-hero-linhas{ gap:.3rem 1rem; padding-top:.85rem; }
  .kpi-hero-onda{ height:3.25rem; opacity:.7; }
  /* O cabeçalho de card empilha: título em cima, legenda/ações embaixo e à
     esquerda. `margin-left:auto` numa linha que quebrou joga o bloco para o
     canto direito, longe do título a que ele pertence. */
  .card-cab{ gap:.5rem; padding-bottom:.65rem; margin-bottom:.8rem; }
  .card-cab-acoes{ margin-left:0; }
  /* A faísca sai: no cartão estreito ela fica embaixo do valor, não ao lado. */
  .kpi-spark{ display:none; }

  /* ---- A BARRA DE BAIXO ----------------------------------------------
     Quatro telas a um toque, mais o "Mais" que abre a gaveta. Ela é a razão
     de o conteúdo ganhar um rodapé de ar: sem o `padding-bottom` no #app, a
     última linha de toda tabela nasce debaixo da barra.

     `env(safe-area-inset-bottom)` é a barra de gestos do Android / o traço do
     iPhone: o aparelho informa a medida, e sem ela os rótulos ficam por baixo.
     `backdrop-filter` para o conteúdo que passa por baixo continuar sendo
     percebido como conteúdo, e não como fundo da barra. */
  .tabbar{
    display:flex; position:fixed; z-index:40;
    left:0; right:0; bottom:0;
    padding:.3rem .25rem calc(.3rem + env(safe-area-inset-bottom));
    background:color-mix(in srgb, var(--superficie) 92%, transparent);
    backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
    border-top:1px solid var(--linha);
    box-shadow:0 -6px 20px -14px rgba(28,22,10,.55);
  }
  .dark .tabbar{ box-shadow:0 -8px 24px -14px rgba(0,0,0,.9); }
  /* O mesmo fio dourado que costura a barra de cima à sidebar, do outro lado
     da tela — é a assinatura, e ela fecha o quadro. */
  .tabbar::before{
    content:''; position:absolute; left:0; right:0; top:-1px; height:1px;
    pointer-events:none;
    background:linear-gradient(90deg, rgba(191,155,78,.55), transparent 60%);
  }
  .tabbar-item{
    flex:1 1 0; min-width:0;
    display:flex; flex-direction:column; align-items:center; justify-content:center; gap:.15rem;
    min-height:3rem; padding:.35rem .15rem .3rem;
    position:relative; border:0; background:transparent; cursor:pointer;
    color:var(--tinta-tenue);
    transition:color .15s var(--sai);
    -webkit-tap-highlight-color:transparent;
  }
  .tabbar-item svg{ width:1.35rem; height:1.35rem; flex:0 0 auto; }
  /* O rótulo não some nem vira reticências: um ícone sem nome obriga a
     decorar, e "Lançamentos" não tem abreviação óbvia. Ele encolhe até 9px,
     que ainda é legível, e o nome curto vem do próprio app.js. */
  .tabbar-txt{
    font-size:.58rem; font-weight:600; letter-spacing:.01em; line-height:1.1;
    max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .tabbar-item.ativa{ color:var(--ouro-escuro); }
  .dark .tabbar-item.ativa{ color:var(--ouro-claro); }
  /* O traço em cima, e não um fundo dourado atrás: é o mesmo vocabulário da
     sub-aba ativa (`.aba.ativa::after`), do outro lado da tela. */
  .tabbar-item.ativa::before{
    content:''; position:absolute; top:0; left:22%; right:22%; height:2px;
    background:var(--ouro); border-radius:0 0 2px 2px;
  }
  .tabbar-item:focus-visible{ outline:2px solid var(--ouro); outline-offset:-3px; border-radius:.5rem; }
  /* O contador de alertas encostado no ícone, como no menu. */
  .tabbar-badge{
    position:absolute; top:.15rem; left:50%; margin-left:.35rem;
    min-width:1.05rem; height:1.05rem; padding:0 .2rem; border-radius:999px;
    background:var(--g-critico); color:#fff;
    font-size:.58rem; font-weight:700; line-height:1.05rem; text-align:center;
  }
  /* O ar embaixo do conteúdo. 3.75rem é a barra; o inset é o aparelho. */
  #app{ padding-bottom:calc(4.25rem + env(safe-area-inset-bottom)); }

  /* ---- Rodapé flutuante ----------------------------------------------
     `bottom-5` são 20px, e a barra de gestos do Android ocupa ~24px: o aviso
     nascia debaixo dela. `env(safe-area-inset-bottom)` é o número que o próprio
     aparelho informa. Largura cheia porque num celular um aviso encolhido no
     canto simplesmente não é visto.

     Agora ele também tem de subir ACIMA da barra de baixo: um aviso que nasce
     atrás da navegação é um aviso que não foi dado. */
  #toast{
    left:1rem; right:1rem; text-align:center;
    bottom:calc(4.6rem + env(safe-area-inset-bottom));
  }
  /* A gaveta cobre a barra de baixo enquanto está aberta — ela É a lista
     completa, e ver a versão curta por cima dela confunde as duas. */
  html.nav-aberta .tabbar{ display:none; }
}

/* Duas colunas viram uma abaixo de 430px — mas SÓ onde a coluna estreita
   destrói a informação. Corte separado do de cima de propósito: 767px é onde a
   casca muda, 430px é onde um controle deixa de caber ao lado do outro.

   A tentação era colapsar todo `grid-cols-2` (são 29 no app.js, nenhum com
   prefixo responsivo). Medido, ficou ruim: quatro KPIs empilhados em largura
   cheia empurram o conteúdo do painel para baixo da dobra, e cartão, barra de
   orçamento e par de datas leem bem em meia largura.

   Quem sofre de verdade é o campo de ESCOLHA: um <select> de conta contábil em
   144px mostra "3.1.02 Alim…" e mais nada — o texto que distingue uma conta da
   outra é justamente o que é cortado. Então a regra pergunta pelo conteúdo, com
   `:has()` (que o arquivo já usa no .aba-opt), em vez de colapsar no atacado. */
@media (max-width:429.98px){
  #app  .grid.grid-cols-2:has(select, .combo-input),
  #modal .grid.grid-cols-2:has(select, .combo-input){ grid-template-columns:minmax(0,1fr); }
  /* Sem esta linha o colapso sai pior do que o problema. Os campos largos do
     formulário são marcados `col-span-2` (71 deles no app); com uma coluna só
     declarada, "ocupe 2" faz o navegador INVENTAR uma segunda coluna implícita,
     dimensionada pelo conteúdo — a grade voltava a ter duas colunas, agora
     tortas (112px e 208px, medido). Numa coluna, "ocupe duas" não quer dizer
     nada: vira `auto`. */
  #app  .grid.grid-cols-2:has(select, .combo-input) > .col-span-2,
  #modal .grid.grid-cols-2:has(select, .combo-input) > .col-span-2{ grid-column:auto; }
  #app  .grid.grid-cols-3{ grid-template-columns:repeat(2,minmax(0,1fr)); }
}

/* `100vh` no celular é a altura da tela COM a barra do navegador recolhida —
   ou seja, mais alta que a área visível, e o rodapé fica sempre um dedo abaixo
   do fim. `dvh` é a altura que existe agora. No app Android o WebView é tela
   cheia e dá no mesmo, mas o mesmo endereço abre no Chrome do celular, e lá a
   diferença é visível. `div.h-screen` (0,1,1) vence o `.h-screen` (0,1,0) que o
   Play CDN injeta depois. */
@supports (height:100dvh){
  div.h-screen{ height:100dvh; }
  main.app-main.h-screen{ height:100dvh; }
}
