﻿/* ============================================================
   COMPONENTES — vocabulario visual compartilhado entre modulos.
   ============================================================ */

/* ===== PAGE SCAFFOLD ===== */
.page { padding: 28px 32px 48px; max-width: 1440px; margin: 0 auto; }
.page-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 24px;
  margin-bottom: 24px;
  flex-wrap: wrap;
}
/* O eyebrow E' o <h1> das telas do Financeiro: os titulos de 42px sairam de la'
   (eram slogan, e o que identificava desceu para ca'), e uma pagina sem
   cabecalho nenhum e' pior que uma sem slogan. `margin: 0` e' obrigatorio — h1
   traz margem propria do navegador, e base.css nao a zera. */
.page-eyebrow {
  font-family: var(--sans); font-weight: 600;
  font-size: 10px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--fg-faint);
  margin: 0 0 10px;
}
/* Sem titulo no meio, os 10px de baixo do eyebrow e os 10px de cima do sub
   viravam 20px entre duas linhas de 10px. O seletor de irmao adjacente so'
   dispara quando NAO ha' titulo — onde ainda existe (Home, ModuleUnavailable,
   Alterar senha), nada muda. */
.page-eyebrow + .page-sub { margin-top: 0; }
.page-title {
  font-family: var(--display); font-variant-numeric: tabular-nums;
  font-size: 42px;
  line-height: 0.95;
  font-weight: 700;
  letter-spacing: -0.025em;
  margin: 0;
}
.page-sub {
  font-family: var(--sans); font-weight: 600;
  font-size: 10px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--fg-faint);
  margin-top: 10px;
}

.stats-strip {
  display: flex;
  gap: 28px;
  font-family: var(--sans); font-weight: 600;
  font-size: 10px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--fg-dim);
}
.stats-strip > div { display: flex; flex-direction: column; gap: 4px; text-align: right; }
.stats-strip b {
  font-family: var(--display); font-variant-numeric: tabular-nums;
  font-size: 28px;
  font-weight: 700;
  color: var(--fg);
  letter-spacing: -0.025em;
  line-height: 1;
}
.stats-strip b.pos { color: var(--pos); }
.stats-strip b.neg { color: var(--neg); }

/* ===== GRID / CARDS ===== */
.grid { display: grid; gap: 16px; }
.g2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.g3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.g4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.span2 { grid-column: span 2; }

.card {
  background: var(--bg-elev);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 20px;
  min-width: 0;
}
.card-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 14px;
}
.card-title {
  font-family: var(--display); font-variant-numeric: tabular-nums;
  font-size: 22px;
  font-weight: 700;
  margin: 0;
  letter-spacing: -0.025em;
}
.card-kicker {
  font-family: var(--sans); font-weight: 600;
  font-size: 9px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--fg-faint);
  margin-bottom: 6px;
}
.card-link {
  font-family: var(--sans); font-weight: 600;
  font-size: 10px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--fg-dim);
  text-decoration: none;
  border-bottom: 1px dashed var(--line-strong);
  padding-bottom: 1px;
}
.card-link:hover { color: var(--accent); border-color: var(--accent); }

/* ===== TABELAS ===== */

/* Uma <table> não encolhe abaixo da largura mínima do seu conteúdo, e
   `width: 100%` não muda isso — é teto, não piso. Num cartão estreito ela
   simplesmente vaza para fora e empurra a página inteira para o lado.
   O container é a única defesa que funciona em qualquer largura, com qualquer
   dado: o que não couber rola aqui dentro, e não na página.
   Toda .tbl deve estar dentro de um. */
.tbl-scroll { overflow-x: auto; }

.tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
.tbl th {
  font-family: var(--sans);
  font-size: 9px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--fg-faint);
  font-weight: 600;
  text-align: left;
  padding: 8px 10px;
  border-bottom: 1px dashed var(--line);
}
.tbl td {
  padding: 10px;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}
.tbl tr:last-child td { border-bottom: none; }
.tbl tbody tr { transition: background 0.15s; }
.tbl tbody tr:hover { background: var(--bg); }
.tbl .num { text-align: right; font-family: var(--mono); font-size: 12px; font-variant-numeric: tabular-nums; }
.tbl .num.pos { color: var(--pos); }
.tbl .num.neg { color: var(--neg); }
.tbl .mono { font-family: var(--mono); font-size: 11px; color: var(--fg-dim); }
/* Coluna de largura curta e previsivel — data, categoria, quem — centralizada
   com o proprio cabecalho. Valor continua a direita e descricao a esquerda: o
   que se compara verticalmente alinha pela virgula, o que se le alinha pela
   margem. */
.tbl th.col-center, .tbl td.col-center { text-align: center; }

/* O RODAPE fecha a coluna. Sem regra propria ele sai igual a uma linha comum, e
   um total que parece mais uma linha nao prova nada — a borda de cima e' o que
   diz "aqui a coluna acabou". */
.tbl tfoot td {
  border-top: 1px solid var(--line-strong);
  border-bottom: 0;
  color: var(--fg);
}

/* Rodape de VARIAS linhas — soma dos itens, "Outros", total. So a primeira
   fecha a coluna; nas outras a borda separaria numeros que sao uma conta so.

   Classe propria, e nao `.tbl tfoot tr + tr td`: a matriz do orcamento tambem e
   .tbl, e uma regra generica venceria `.bud-matrix tfoot td` por especificidade
   e apagaria as bordas de la. */
.tbl tfoot.foot-total tr + tr td { border-top: 0; }

/* Chips / badges */
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--sans); font-weight: 600; font-size: 9px;
  letter-spacing: 0.05em; text-transform: uppercase;
  border: 1px solid var(--line); border-radius: 4px;
  padding: 3px 7px; color: var(--fg-dim);
  background: var(--bg-elev);
}
.chip .dot { width: 7px; height: 7px; border-radius: 2px; background: var(--fg-faint); }
.chip.pos { color: var(--pos); border-color: color-mix(in oklab, var(--pos) 40%, transparent); }
.chip.neg { color: var(--neg); border-color: color-mix(in oklab, var(--neg) 40%, transparent); }
.chip.accent { color: var(--accent); border-color: color-mix(in oklab, var(--accent) 40%, transparent); }

/* Avatares de pessoas (compartilhamento) */
.av-stack { display: inline-flex; }
.av {
  width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--display); letter-spacing: -0.01em; font-size: 11px; font-weight: 600;
  color: var(--bg);
  border: 2px solid var(--bg-elev);
}
.av + .av { margin-left: -7px; }
.av.a1 { background: var(--chart-1); }
.av.a2 { background: var(--chart-2); }
.av.a3 { background: var(--chart-5); }

/* ===== BARRAS DE PROGRESSO ===== */
.bar-row { display: flex; align-items: center; gap: 10px; }
.bar-track {
  flex: 1; height: 8px; background: var(--bg); border-radius: 4px;
  position: relative; overflow: hidden;
  border: 1px solid var(--line);
}
.bar-fill {
  position: absolute; left: 0; top: 0; height: 100%;
  background: var(--accent); border-radius: 4px;
  transition: width .3s;
}
.bar-fill.cyan { background: var(--cyan); }
.bar-fill.pos { background: var(--pos); }
.bar-fill.neg { background: var(--neg); }
.bar-pct { font-family: var(--mono); font-size: 11px; color: var(--fg-dim); min-width: 40px; text-align: right; }

/* ===== FORMULÁRIOS ===== */

/* Formulário em linha, com as colunas declaradas pela própria view em --cols:

     <form class="form-row" style="--cols:2fr 1fr 1fr auto">

   O template fica junto do formulário, que é onde faz sentido lê-lo, mas mora
   numa custom property e não em `style="grid-template-columns:…"`. A diferença
   importa: estilo inline vence media query, e as duas versões inline que
   existiam antes — seis e cinco colunas fixas — não tinham como colapsar no
   celular. Ficavam com seis campos lado a lado em 375px de tela. */
.form-row {
  display: grid;
  grid-template-columns: var(--cols, 1fr);
  gap: 10px;
  align-items: end;
}
/* O botao de um formulario cujos campos ja preenchem todas as colunas. Sem
   isto ele cai na primeira coluna da linha seguinte, encostado a esquerda e
   longe do ultimo campo preenchido. */
.form-row-action { grid-column: 1 / -1; justify-self: end; }

.inp, .sel {
  background: var(--bg); border: 1px solid var(--line); color: var(--fg);
  padding: 8px 10px; border-radius: 6px;
  font-family: var(--sans); font-size: 13px;
  outline: none; min-width: 0;
  transition: border-color .15s;
}
.inp:focus, .sel:focus { border-color: var(--accent); }
.inp.mono { font-family: var(--mono); font-size: 12px; }
.lbl {
  font-family: var(--sans); font-weight: 600; font-size: 9px; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--fg-faint);
  display: block; margin-bottom: 6px;
}
.btn {
  background: var(--accent); color: var(--bg);
  border: 1px solid var(--accent);
  padding: 8px 18px; border-radius: 6px;
  font-family: var(--sans); font-size: 13px; font-weight: 600;
  cursor: pointer; transition: opacity .15s;
}
.btn:hover { opacity: 0.88; }
/* O mesmo botao como <a>: os dialogos abrem por href, entao metade das acoes
   primarias do sistema sao ancora e nao <button>. Sem isto herdavam sublinhado
   e alinhamento de texto, e as duas versoes nao pareciam o mesmo controle. */
a.btn, a.btn-ghost { display: inline-flex; align-items: center; gap: 6px; text-decoration: none; }
.btn-ghost {
  background: var(--bg-elev); color: var(--fg);
  border: 1px solid var(--line);
  padding: 8px 14px; border-radius: 6px;
  font-family: var(--sans); font-size: 13px;
  cursor: pointer; transition: all .15s;
}
.btn-ghost:hover { border-color: var(--accent); color: var(--accent); }
.btn-dashed {
  background: transparent; border: 1px dashed var(--line-strong);
  color: var(--fg-dim); padding: 8px; border-radius: 6px;
  font-family: var(--sans); font-size: 12px; cursor: pointer; transition: .15s;
  width: 100%;
}
.btn-dashed:hover { color: var(--accent); border-color: var(--accent); }

/* Botao de acao dentro de linha de tabela ou de cartao. Vivia em travel.css, e
   por isso o "Vender" da carteira, o "Cotacoes" dos ativos e o "Remover" da
   fatura saiam como texto cru: a folha do modulo Financeiro nunca carregou a
   regra. Vocabulario compartilhado mora aqui. */
.place-btn {
  background: transparent; border: 1px solid var(--line); color: var(--fg-dim);
  font-family: var(--sans); font-weight: 600; font-size: 10px; letter-spacing: 0.05em;
  padding: 5px 9px; border-radius: 5px; cursor: pointer; white-space: nowrap;
  text-decoration: none; display: inline-flex; align-items: center; gap: 5px;
  transition: .15s;
}
.place-btn:hover { color: var(--accent); border-color: var(--accent); }
/* Acao que fecha ou apaga alguma coisa. So no hover: vermelho permanente numa
   coluna inteira transforma a tabela num alarme. */
.place-btn.is-danger:hover {
  color: var(--neg); border-color: var(--neg);
  background: color-mix(in oklab, var(--neg) 10%, transparent);
}

/* Linha de volta de uma tela de detalhe: voltar, o periodo, e a acao. Tambem
   vinha de travel.css, e em /Finance/Budget/Movement os tres sairam empilhados
   e sem moldura ate esta regra existir aqui. */
.plan-back-row { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin-bottom: 20px; }
.plan-back {
  background: transparent; border: 1px solid var(--line);
  color: var(--fg-dim); font-family: var(--sans); font-weight: 600; font-size: 11px;
  letter-spacing: 0.05em; padding: 6px 12px; border-radius: 6px; cursor: pointer;
  text-decoration: none; display: inline-flex; align-items: center; gap: 6px;
  transition: .15s;
}
.plan-back:hover { color: var(--accent); border-color: var(--accent); }
.plan-back-crumb {
  font-family: var(--sans); font-weight: 600; font-size: 10px; letter-spacing: 0.05em;
  color: var(--fg-faint); text-transform: uppercase;
}
/* Empurra a acao para a ponta direita da linha. */
.plan-back-end { margin-left: auto; }
.plan-inline-link {
  background: transparent; border: none; padding: 0;
  color: var(--accent); font: inherit; cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
}

/* Barra de acoes no topo da pagina, ao lado do que ja estiver ali (o seletor de
   mes, por exemplo). O botao de criar ficava no FIM da lista: em um mes com
   doze categorias era preciso rolar a pagina inteira para lancar. */
.page-toolbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-bottom: 16px;
}
.page-toolbar > .page-toolbar-actions { display: flex; align-items: center; gap: 10px; margin-left: auto; }

/* Pills de filtro */
.filter-pills { display: flex; gap: 4px; font-family: var(--sans); font-weight: 600; font-size: 10px; letter-spacing: 0.05em; flex-wrap: wrap; }
.filter-pill {
  padding: 5px 10px; border-radius: 999px;
  border: 1px solid var(--line); background: transparent;
  color: var(--fg-dim); cursor: pointer; transition: all 0.15s;
  font: inherit; text-transform: uppercase;
  font-family: var(--sans); letter-spacing: 0.05em; font-weight: 600; font-size: 10px;
}
.filter-pill:hover { color: var(--fg); border-color: var(--line-strong); }
.filter-pill.on { background: var(--accent); color: var(--bg); border-color: var(--accent); }

/* ===== SELECT — legibilidade no tema escuro =====
   Sem isto o Chrome desenha as <option> com as cores do SO, ilegiveis
   sobre o fundo escuro do app. */
select, .currency-picker select { color-scheme: light dark; }
select option,
.currency-picker select option,
.jrn-entry-author select option {
  background-color: var(--bg-card);
  color: var(--fg);
}
html[data-theme="dark"] select option,
html[data-theme="dark"] .currency-picker select option,
html[data-theme="dark"] .jrn-entry-author select option {
  background-color: oklch(0.22 0.014 260);
  color: oklch(0.96 0.01 85);
}


/* ===== PRIMITIVAS DE FORMULARIO =====
   Os nomes vem do Bootstrap porque as telas de acesso ja' os usavam. Em vez de
   reescrever aquelas views, o sistema passa a definir as classes: sao genericas
   o bastante para serem nossas, e o Extrato vai precisar delas de qualquer forma.
   O Bootstrap inteiro sai da CDN. */
.form-label {
  display: block;
  color: var(--fg);
  font-size: 0.85rem;
  font-weight: 500;
  margin-bottom: 0.5rem;
}
.form-control {
  display: block;
  width: 100%;
  background: var(--bg);
  border: 1px solid var(--line);
  color: var(--fg);
  border-radius: 8px;
  padding: 0.65rem 1rem;
  font-family: var(--sans);
  font-size: 0.9rem;
  outline: none;
  transition: border-color .15s, box-shadow .15s;
}
.form-control::placeholder { color: var(--fg-faint); }
.form-control:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px oklch(from var(--accent) l c h / 0.15);
}
.btn-primary {
  display: block;
  width: 100%;
  background: linear-gradient(135deg, var(--accent), var(--cyan));
  border: none;
  color: oklch(0.16 0 0);
  padding: 0.75rem;
  font-family: var(--sans);
  font-size: 0.95rem;
  font-weight: 600;
  border-radius: 8px;
  margin-top: 1rem;
  cursor: pointer;
  transition: filter .15s, transform .15s, box-shadow .15s;
}
.btn-primary:hover {
  filter: brightness(1.06);
  transform: translateY(-1px);
  box-shadow: 0 6px 18px -6px oklch(from var(--accent) l c h / 0.5);
}
.form-check { display: flex; align-items: center; gap: 8px; }
.form-check-input {
  width: 15px; height: 15px; margin: 0;
  accent-color: var(--accent);
  background: var(--bg);
  border: 1px solid var(--line);
}
.form-check-label { color: var(--fg-dim); }
.auth-link {
  color: var(--accent);
  text-decoration: none;
  font-size: 0.85rem;
}
.auth-link:hover { text-decoration: underline; }

/* Erro de validacao, do servidor ou do modelo. Vazio nao ocupa espaco:
   asp-validation-for sempre renderiza o <span>, com ou sem mensagem.

   Estava em modules/auth.css, que so' o _AuthLayout carrega. A troca de senha
   acontece dentro do app, com o _Layout normal — la' a regra nao existia e a
   mensagem de erro saia com a cor do texto comum. E' primitiva de formulario,
   nao estilo de tela de acesso. */
.auth-error {
  color: var(--neg);
  font-size: 0.82rem;
  display: block;
}
.auth-error:empty { display: none; }
.auth-error ul {
  list-style: none;
  padding: 0;
  margin: 0 0 1rem;
}

/* Utilitarios que as telas de acesso usam */
.text-center { text-align: center; }
.mt-3 { margin-top: 1rem; }
.mb-3 { margin-bottom: 1rem; }
.small { font-size: 0.85rem; }


/* ===== MODULO INDISPONIVEL =====
   Renderiza dentro da moldura normal, com HTTP 503. So' o corpo do modulo e'
   substituido: topbar, seletor de modulos e tema seguem funcionando, para o
   usuario conseguir ir a um modulo que esteja no ar. */
.unavailable-hint { color: var(--fg-dim); font-size: 14px; margin: 0 0 18px; }
.unavailable-trace {
  margin-top: 18px; padding-top: 14px; border-top: 1px dashed var(--line);
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.1em;
  color: var(--fg-faint);
}

/* Só aparece em desenvolvimento — ver a nota em ModuleUnavailable.cshtml. */
.unavailable-detail {
  margin-top: 18px; padding: 12px 14px;
  border: 1px dashed var(--line-strong); border-radius: 8px;
  background: var(--bg);
  display: flex; flex-direction: column; gap: 6px;
}
.unavailable-detail-label {
  font-family: var(--sans); font-weight: 600; font-size: 9px; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--fg-faint);
}
.unavailable-detail code {
  font-family: var(--mono); font-size: 12px; color: var(--fg);
  white-space: pre-wrap; word-break: break-word;
}
.unavailable-detail-code {
  align-self: flex-start;
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.08em;
  color: var(--accent); border: 1px solid var(--accent);
  border-radius: 4px; padding: 1px 6px;
}

/* ===== SALVAMENTO EM LINHA =====
   O botao "Salvar" existe no HTML para quem esta' sem JavaScript. A classe .js
   e' posta no <html> pelo _Head, entao com JS ele some e o autosave assume. */
.row-save, .jrn-save {
  background: transparent; border: 1px solid var(--line);
  color: var(--fg-dim); font-family: var(--sans); font-size: 11px;
  padding: 4px 10px; border-radius: 6px; cursor: pointer;
}
.row-save:hover, .jrn-save:hover { color: var(--accent); border-color: var(--accent); }
html.js .row-save { display: none; }

form.is-saving { opacity: 0.65; }
form.is-error { box-shadow: inset 2px 0 0 var(--neg); }

/* ===== AVISOS FLUTUANTES =====
   Um campo que falhou ao salvar nao merece uma pagina de erro inteira. */
.planner-toast {
  position: fixed; bottom: 56px; left: 50%; transform: translateX(-50%);
  z-index: 3000; max-width: 460px;
  background: var(--bg-card); border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: 10px; padding: 12px 18px;
  box-shadow: var(--shadow-lg);
  font-size: 13px; color: var(--fg);
  animation: toastIn .18s ease-out;
}
.planner-toast.is-error { border-left-color: var(--neg); }
.planner-toast.leaving { opacity: 0; transition: opacity .35s; }
@keyframes toastIn { from { opacity: 0; transform: translate(-50%, 8px); } to { opacity: 1; transform: translate(-50%, 0); } }

/* ===== MODAL E FORMULARIO =====
   Promovido de modules/travel.css quando o Financeiro ganhou escrita: dois
   modulos usando o mesmo vocabulario, e a folha de um modulo nao e' carregada
   no outro. Sem esta mudanca, todo <dialog> do Financeiro sairia sem estilo.

   Mesma razao pela qual .auth-error subiu de modules/auth.css: e' primitiva de
   formulario, nao estilo de uma tela.

   O <dialog> abre por showModal() com JavaScript e por :target sem ele — em
   ambos os casos o formulario e' um <form> normal, com POST + redirect. */
.pp-empty {
  border: 1px dashed var(--line-strong);
  border-radius: 12px;
  background: var(--bg-elev);
  padding: 18px 22px;
  margin-bottom: 28px;
  font-family: var(--sans); font-size: 13px; line-height: 1.55;
  color: var(--fg-dim);
}
.pp-empty b { display: block; color: var(--fg); margin-bottom: 4px; }


.plan-modal {
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  background: var(--bg-elev);
  color: var(--fg);
  padding: 0;
  width: min(460px, calc(100vw - 32px));
  box-shadow: var(--shadow-lg);
}
.plan-modal::backdrop { background: rgba(0, 0, 0, 0.55); }
.plan-modal:target { display: block; margin: 16px auto; }

.plan-modal-form { display: flex; flex-direction: column; gap: 14px; padding: 20px; }
.pm-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.pm-head h2 {
  margin: 0;
  font-family: var(--sans); font-weight: 600; font-size: 13px; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--fg-dim);
}
.pm-x {
  text-decoration: none; color: var(--fg-faint);
  width: 28px; height: 28px; border-radius: 5px;
  display: grid; place-items: center; font-size: 12px;
}
.pm-x:hover { color: var(--fg); background: var(--bg); }

.pm-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; border: none; padding: 0; margin: 0; }
.pm-field > span, .pm-field > legend {
  font-family: var(--sans); font-weight: 600; font-size: 10px; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--fg-faint);
  padding: 0;
}
.pm-field input, .pm-field select {
  width: 100%; min-width: 0;
  background: var(--bg); border: 1px solid var(--line); color: var(--fg);
  padding: 9px 10px; border-radius: 6px;
  font-family: var(--sans); font-size: 14px;
  outline: none;
}
.pm-field input[type="number"] { font-family: var(--mono); text-align: right; -moz-appearance: textfield; }
.pm-field input[type="number"]::-webkit-outer-spin-button,
.pm-field input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.pm-field input:focus, .pm-field select:focus { border-color: var(--accent); }
.pm-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

.pm-note {
  margin: 0; font-size: 12px; line-height: 1.5; color: var(--fg-dim);
  border-left: 2px solid var(--line-strong); padding-left: 10px;
}


.pm-foot { display: flex; align-items: center; gap: 10px; margin-top: 4px; }
.pm-del {
  margin-right: auto;
  background: transparent; border: 1px solid var(--line); color: var(--fg-faint);
  font-family: var(--sans); font-weight: 600; font-size: 11px;
  padding: 9px 12px; border-radius: 6px; cursor: pointer;
}
.pm-del:hover { color: oklch(0.72 0.18 25); border-color: oklch(0.72 0.18 25); }
/* .pm-del serve botão E link. No diálogo da viagem ele é um <a> que abre a
   confirmação em vez de submeter: apagar leva roteiro, gastos e carimbos. */
a.pm-del { text-decoration: none; }
.pm-cancel {
  text-decoration: none;
  color: var(--fg-dim);
  font-family: var(--sans); font-weight: 600; font-size: 11px;
  padding: 9px 12px; border-radius: 6px;
}
.pm-cancel:hover { color: var(--fg); background: var(--bg); }
.pm-save {
  background: var(--accent); border: 1px solid var(--accent); color: var(--bg);
  font-family: var(--sans); font-weight: 600; font-size: 11px;
  padding: 9px 18px; border-radius: 6px; cursor: pointer;
}
.pm-save:hover { filter: brightness(1.08); }

.pci-split-chip {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--bg); border: 1px solid var(--line);
  color: var(--fg-dim);
  padding: 2px 7px 2px 3px; border-radius: 999px;
  font-family: var(--sans); font-size: 11px; letter-spacing: 0;
  text-transform: none; cursor: pointer; transition: .12s;
}
.pci-split-chip .person-chip {
  width: 18px; height: 18px; font-size: 10px;
  margin: 0; border: none;
  opacity: 0.4;
}
.pci-split-chip.on {
  background: oklch(from var(--accent) l c h / 0.18);
  border-color: oklch(from var(--accent) l c h / 0.5);
  color: var(--fg);
}

/* ===== CARREGANDO =====
   Toda tela e' renderizada no servidor, entao "carregando" aqui e' quase sempre
   a espera ENTRE telas: o navegador ja' saiu da pagina antiga e a nova ainda nao
   chegou. Sem retorno visual, clicar duas vezes num link parece a unica reacao
   possivel — e o segundo clique costuma ser um segundo POST.

   O overlay e' um <dialog> aberto com showModal(), e nao uma <div> com z-index.
   A razao e' concreta: quase todo formulario deste app e' enviado de DENTRO de
   um <dialog> (novo lugar, novo item, nova viagem). Um <dialog> modal vive na
   top layer, acima de qualquer z-index, entao uma <div> ficaria escondida atras
   dele justamente nos casos em que o spinner mais importa.

   De quebra, o ::backdrop e' o esmaecido sem elemento extra, e o showModal deixa
   o resto da pagina inerte — o clique duplo que isto existe para evitar passa a
   ser impossivel, e nao so' desencorajado. */
.load-overlay {
  border: none; background: transparent; padding: 0;
  max-width: none; max-height: none;
  color: var(--fg);
}
.load-overlay::backdrop {
  background: color-mix(in oklab, var(--bg) 72%, transparent);
  backdrop-filter: blur(2px);
}
.load-overlay-box {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
}
/* Bem maior que o .spinner de 14px usado em linha: aqui ele e' o assunto da
   tela, nao um enfeite ao lado de um botao. */
.load-overlay .spinner { width: 34px; height: 34px; border-width: 3px; }

/* Sem showModal (navegador antigo), o <dialog> cai para o atributo open — e a'
   nao existe ::backdrop, entao o proprio elemento pinta o fundo e se posiciona.
   A classe e' posta pelo JS, e nao um :not(:modal): quem nao tem showModal
   tambem nao tem a pseudo-classe :modal, e a regra inteira seria descartada
   justamente no navegador que precisa dela. */
.load-overlay.is-plain[open] {
  position: fixed; inset: 0; z-index: 4000;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in oklab, var(--bg) 72%, transparent);
}

.spinner {
  display: inline-block; width: 14px; height: 14px;
  border: 2px solid color-mix(in oklab, var(--fg-faint) 45%, transparent);
  border-top-color: var(--accent);
  border-radius: 999px;
  animation: spin .7s linear infinite;
}

/* O esqueleto e' o gradiente andando, nao a cor piscando: piscar compete com o
   conteudo que chega, e a faixa diz "vem vindo" sem chamar atencao. */
.skeleton {
  border-radius: 6px;
  background: linear-gradient(90deg,
      var(--bg-elev) 0%,
      color-mix(in oklab, var(--fg-faint) 12%, var(--bg-elev)) 50%,
      var(--bg-elev) 100%);
  background-size: 200% 100%;
  animation: shimmer 1.3s linear infinite;
}

.loading-label {
  font-family: var(--sans); font-weight: 600; font-size: 10px;
  letter-spacing: 0.05em; text-transform: uppercase; color: var(--fg-faint);
}

/* Ocupado: o botao continua legivel e para de aceitar clique. disabled sozinho
   o apagaria; a opacidade explica por que ele nao responde. */
.is-busy { opacity: 0.6; cursor: progress; }
button.is-busy, .btn.is-busy { pointer-events: none; }
form.is-busy { opacity: 0.65; }

@keyframes spin { to { transform: rotate(360deg); } }
@keyframes shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }

/* Movimento e' enfeite; o estado precisa continuar visivel sem ele. */
@media (prefers-reduced-motion: reduce) {
  .spinner, .skeleton { animation: none; }
}

/* ===== APEXCHARTS — integração de tema ===== */
.apexcharts-tooltip {
  background: var(--bg-card) !important;
  border: 1px solid var(--line-strong) !important;
  color: var(--fg) !important;
  box-shadow: var(--shadow-lg) !important;
  font-family: var(--sans) !important;
}
.apexcharts-tooltip-title {
  background: var(--bg-elev) !important;
  border-bottom: 1px solid var(--line) !important;
  font-family: var(--mono) !important;
}
.apexcharts-legend-text { color: var(--fg-dim) !important; font-family: var(--sans) !important; }
.apexcharts-text { fill: var(--fg-dim); font-family: var(--mono) !important; }
.apexcharts-gridline { stroke: var(--chart-grid); }

/* ===== CAMPO DE DINHEIRO =====
   O `.money-input` é criado pelo money.js em cima do <input type="number"> que o
   servidor renderiza — sem JavaScript ele não existe e o campo numérico comum
   aparece no lugar. Ver o cabeçalho de money.js.

   Alinhado à DIREITA porque é assim que se confere dinheiro: a vírgula das
   linhas vizinhas fica na mesma coluna, e a máscara monta o número da direita
   para a esquerda de qualquer modo. `tabular-nums` é o que impede a largura de
   dançar a cada dígito digitado — sem isso o campo "pula" enquanto se digita. */
.money-input {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}

/* Campo em erro pela validação de mínimo. :user-invalid e não :invalid: este
   último pinta de vermelho um campo obrigatório que a pessoa ainda nem tocou. */
.money-input:user-invalid { border-color: var(--neg); }

/* ===== RESPONSIVO ===== */
@media (max-width: 1100px) {
  .g3, .g4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 860px) {
  /* O TOPBAR EM DUAS LINHAS, e as duas com piso zero.
   *
   * `1fr` é `minmax(auto, 1fr)`: o piso é min-content, então a faixa se recusa a
   * encolher abaixo do conteúdo e a barra inteira transborda — a mesma armadilha
   * de `.tbl` sem `.tbl-scroll`. Medido em 375px: a linha 1 pedia 500px (marca
   * 195 + direita 295) num viewport de 375, e o documento saía com 538 de
   * scrollWidth. `minmax(0, 1fr)` é o que dá permissão de encolher.
   *
   * E o seletor de visão DESCE PARA A LINHA 2, encostado à direita das abas.
   * No desktop ele vive ao lado do chip de usuário porque responde "de quem são
   * estes números"; aqui a linha 2 já é a linha do módulo, que é sobre o que ele
   * filtra. Sem descer não fecha: só ele são 126px dos 343 disponíveis.
   *
   * `display: contents` em `.topbar-right` é o que permite isso sem mexer no
   * HTML: os três filhos viram itens da grade do topbar e se colocam sozinhos.
   * O wrapper é um <div> sem papel semântico, então some da árvore sem custo. */
  .topbar {
    grid-template-columns: minmax(0, 1fr) auto auto;
    grid-template-rows: auto auto;
    gap: 10px;
    padding: 12px 16px;
  }
  .topbar > .brand { grid-row: 1; grid-column: 1; min-width: 0; }
  .topbar .topbar-right { display: contents; }
  .topbar .icon-btn { grid-row: 1; grid-column: 2; }
  .topbar .user-chip-wrap { grid-row: 1; grid-column: 3; }
  .topbar .scope-switch { grid-row: 2; grid-column: 2 / -1; justify-self: end; }

  /* As abas rolam; o seletor ao lado não. Sem `min-width: 0` a faixa volta a ter
     piso de min-content e as seis abas empurram a barra de novo. */
  .nav-tabs {
    grid-row: 2; grid-column: 1;
    justify-self: start;
    min-width: 0; max-width: 100%;
    overflow-x: auto;
  }

  /* O nome do módulo é o que diz ONDE se está, então ele trunca em vez de
     empurrar — e só depois de a marca já ter cedido o que tinha para ceder. */
  .brand-home { min-width: 0; }
  .module-chip {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .page { padding: 20px 16px 40px; }
  .g2, .g3, .g4 { grid-template-columns: 1fr; }
  .span2 { grid-column: span 1; }
  .page-head { flex-direction: column; align-items: flex-start; }
  .stats-strip { flex-wrap: wrap; }
  .stats-strip > div { text-align: left; }
  .ticker { display: none; }

  /* Tablet: as proporções de --cols param de servir. Um formulário de seis
     campos aqui dá 80px por campo, e o <select> de conta trunca "Nubank —
     Conta Conjunta" no meio. auto-fit com piso de 150px acha sozinho quantas
     colunas cabem, sem precisar de um --cols por faixa de largura. */
  .form-row { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
}

/* Celular. Breakpoint próprio, mais estreito que o de 860: lá o cartão passa a
   ocupar a linha inteira e ganha ~830px, onde uma tabela de sete colunas cabe
   folgada. Esconder coluna ali seria perder dado à toa. */
@media (max-width: 720px) {
  /* Aperta a célula antes de esconder qualquer coisa: 8px de padding em vez de
     10 e um ponto a menos de fonte já devolvem perto de 60px numa tabela de
     seis colunas, sem custo nenhum de informação. */
  .tbl { font-size: 12px; }
  .tbl th { padding: 7px 6px; }
  .tbl td { padding: 8px 6px; }

  /* Coluna secundária: a view marca th e td com .col-sec, e some no celular.
     Não é "menos importante" no geral — é o que se pode deduzir do contexto ou
     consultar abrindo o item. A conta do lançamento, a classe do ativo. O que
     identifica a linha (data, descrição) e o que se foi olhar (valor) nunca
     leva esta classe. */
  .col-sec { display: none; }

  /* Uma coluna, sempre. Vence o --cols da view porque é regra mais específica
     em media query — e não venceria se o template estivesse no style inline. */
  .form-row { grid-template-columns: 1fr; }

  /* O QUE SAI DO TOPBAR NO CELULAR, e por quê — mesma regra do `.col-sec`: sai o
     que se deduz do contexto, nunca o que identifica.
     *
     * "Planner" é constante: uma vez dentro do app não informa nada, e a marca
     * redonda continua sendo o link para o hub. O NOME do usuário sai pelo mesmo
     * motivo — as iniciais no avatar já identificam quem está logado, e o nome
     * inteiro com o e-mail está no menu, a um toque.
     *
     * Os dois juntos devolvem 118px. Medido depois: a linha 1 passa a precisar
     * de 292px de mínimo, então fecha até em 320. */
  .brand-name { display: none; }
  .user-name { display: none; }
}
