/* =============================================================================
   design-system.css — Camada autoral sobre o Tabler
   -----------------------------------------------------------------------------
   O design system real é o Tabler (vendor). Este arquivo é a FINA camada
   autoral do projeto: tokens, shell de layout (ver DESIGN.md) e utilitárias
   que substituem o CSS inline espalhado.

   Substitui o antigo `main.css`. Carregar SEMPRE depois do tabler.min.css.

   Princípios desta versão (v2, com as decisões aplicadas):
   - Trocado o que é invisível ou idêntico:
       • larguras de tabela inline → classes utilitárias (mesmos px).
   - Decisões de consolidação aplicadas (mudanças visíveis acordadas):
       1. cor primária: token morto #0081f1 DESCARTADO; mantido o primário do Tabler;
       2. divisor: unificado em #e6e8ec (sidebar + footer);
       3. footer padding: 12px 18px → 12px 16px (na régua de espaçamento).
============================================================================= */

/* =============================================================================
   1. TOKENS  (:root)
============================================================================= */
:root {
  /* --- 1.1 Raio de borda: escala autoral premium (DESIGN §2.2) --------------
     Sai o reset global `0`; entra um raio SUTIL que só quebra o canto reto
     (premium sem exagero, nunca "bolha"). Default do sistema = xs (1px); `none`
     fica só para encostes edge-to-edge (thead sticky). */
  --ds-radius-none: 0;
  --ds-radius-xs: 1px; /* botões, inputs, chips, badges, células */
  --ds-radius-sm: 2px; /* controles maiores, tabs-pílula */
  --ds-radius-md: 4px; /* cartões, drawer, overlays, container de tabela */
  --ds-radius-lg: 8px; /* cartões grandes / card de login */
  --ds-radius-xl: 16px; /* superfícies de destaque */
  --ds-radius-pill: 999px; /* estádio (badges, chips, FAB com rótulo) */
  --ds-radius-round: 50%; /* círculo (avatar, dot, ícone redondo) */
  /* Componentes do Tabler leem --tblr-border-radius*: apontam para a escala
     autoral (antes tudo 0). O raio cresce com o tamanho do componente:
     controles em xs, cartões em md, superfícies grandes em lg. */
  --tblr-border-radius: var(--ds-radius-xs);
  --tblr-border-radius-sm: var(--ds-radius-xs);
  --tblr-border-radius-lg: var(--ds-radius-md);
  --tblr-border-radius-xl: var(--ds-radius-md);
  --tblr-border-radius-xxl: var(--ds-radius-lg);
  --tblr-border-radius-2xl: var(--ds-radius-lg);

  /* --- 1.2 Superfícies e texto (paleta neutra global — v3) ------------------
     Paleta neutra estilo Vercel/Supabase, adotada globalmente (decisão de UI).
     Os valores antigos (#f6f8fb / #1f2937 / #667085) foram repontados para a
     nova paleta clara; o tema escuro vem na §1.7. Tabela de bridge --tblr-* na
     §1.8 garante que os componentes do Tabler acompanhem. */
  --ds-body-bg: #f7f8fa; /* fundo da página (neutro frio v4) */
  --ds-surface: #ffffff; /* cartões / footer */
  --ds-surface-2: #eef0f4; /* superfície secundária */
  --ds-text: #0f1117; /* texto principal */
  --ds-text-muted: #54607a; /* texto secundário */
  --ds-text-faint: #717c90; /* texto terciário / placeholders */

  /* Divisor */
  --ds-border: #e6e8ed;
  --ds-border-strong: #d2d7df; /* borda de controle (input/seletor) — hover/realce */

  /* --- 1.2.1 Acento (índigo v4) e DINHEIRO (família própria, ≠ Ut) ----------
     §2.4 do DESIGN: dinheiro ≠ UI ≠ titular. O índigo é SÓ ação/links/seleção/
     foco; receita/despesa usam a família money. Migrado da v3 (azul) em v1.22.0. */
  --ds-accent: #3b5bdb; /* ação primária (índigo) */
  --ds-accent-strong: #2f49b8; /* ação primária (hover) */
  --ds-accent-tint: #eef1fd; /* fundo sutil de seleção/realce */
  --ds-money-in: #0e9f6e; /* entrada/receita (verde) */
  --ds-money-out: #e5484d; /* saída/despesa (vermelho) */
  --ds-money-neutral: #54607a; /* transferência/neutro */
  /* aliases legados → dinheiro (receita NÃO é mais o azul de UI) */
  --ds-expense: var(--ds-money-out);
  --ds-revenue: var(--ds-money-in);
  --ds-income: var(--ds-money-in);
  --ds-warn: #c2841d; /* alerta */

  /* --- 1.2.2 Cores de TITULAR (PF/PJ/Fazenda): famílias próprias — nunca money
     nem accent (§2.4 do DESIGN). Portadas do preview v4. -------------------- */
  --ds-holder-pf: #0d8f96; /* PF — turquesa */
  --ds-holder-pj: #5b6b8c; /* PJ — ardósia */
  --ds-holder-fazenda: #8a6d3b; /* Fazenda — terroso/ocre */

  /* --- 1.2.3 Projetos: prioridade/tipo/gráfico/estado (spec §19.7). Categórica
     --ds-chart-* é família PRÓPRIA: NÃO alia money/holder/warn/ai; só chart-1 =
     índigo da marca. Status "concluído" usa chart-3 (teal), nunca money-in. ----- */
  --ds-prio-low: #6b7280;
  --ds-prio-medium: #2f6fed;
  --ds-prio-high: #c2841d;
  --ds-prio-urgent: #d6402c;
  --ds-type-epic: #8257e6;
  --ds-type-story: #3b7fd4;
  --ds-type-task: #5a6b86;
  --ds-type-bug: #d6402c;
  --ds-type-spike: #b0791f;
  --ds-wip-over: #d6402c;
  --ds-critical: #e5484d;
  --ds-chart-1: #3b5bdb;
  --ds-chart-2: #e08a2a;
  --ds-chart-3: #12a39a;
  --ds-chart-4: #9b59e6;
  --ds-chart-5: #d6488f;
  --ds-chart-6: #4a9e4f;
  --ds-chart-7: #2b9bd6;
  --ds-chart-8: #6b7488;

  /* --- 1.2.2 Famílias tipográficas (Inter, carregada em base.html) --------- */
  --ds-font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --ds-font-num: "Inter", ui-monospace, monospace;
  --tblr-font-sans-serif: var(--ds-font-sans);

  /* --- 1.2.3 Régua tipográfica UNIFICADA (mesma do mobile .mtx-) ------------
     base 13.5px, linha 1.45, leve aproximação (-0.01em). Os componentes do
     Tabler leem --tblr-body-font-size / --tblr-body-line-height; o tracking vai
     no body (§2). Unifica desktop/tablet/tv com o mobile, que já usa estes valores. */
  --ds-font-size-base: 13.5px;
  --ds-line-height-base: 1.45;
  --ds-letter-spacing: -0.01em;
  --tblr-body-font-size: var(--ds-font-size-base);
  --tblr-body-line-height: var(--ds-line-height-base);

  /* --- 1.3 Escala de espaçamento (ritmo 4 já existente: 8/12/16) ------------ */
  --ds-space-1: 4px;
  --ds-space-1-5: 6px; /* meio-passo (antes hardcoded em caixa/mobile-tx) */
  --ds-space-2: 8px;
  --ds-space-3: 12px;
  --ds-space-4: 16px;
  --ds-space-5: 20px;
  --ds-space-6: 24px;
  --ds-space-7: 32px;

  /* --- 1.4 Dimensões do layout (ver DESIGN.md §5) --------------------------- */
  /* A topbar e o footer fixos saíram do shell na v4 (§5): a navbar é dona do
     chrome e ocupa a viewport inteira. Sobram só as larguras da aside. */
  --ds-aside-w: 256px; /* sidebar expandida */
  --ds-rail-w: 64px; /* sidebar colapsada (rail) */

  /* --- 1.5 Camadas (z-index) ------------------------------------------------ */
  --ds-z-aside: 1020;
  /* Camadas de overlay (DESIGN §13) — antes inexistentes (dropdown/FAB/drawer). */
  --ds-z-dropdown: 1040;
  --ds-z-fab: 1045;
  --ds-z-drawer: 1050;
  --ds-z-topright: 1055; /* olho + tema: sempre visíveis, acima de qualquer overlay */
  --ds-z-modal: 1060;
  --ds-z-toast: 1080;

  /* --- 1.6 Larguras de coluna de tabela (substituem os style="width:" inline) */
  --ds-col-narrow: 50px;
  --ds-col-sm: 110px;
  --ds-col-md: 120px;
  --ds-col-lg: 130px;
  --ds-col-xl: 140px;
  --ds-col-search: 220px; /* min-width do input de busca */

  /* --- 1.6.1 Larguras do drawer (DESIGN.md §Drawer; grid de 12 col, ref. xl) -
     Tokens FIXOS em px (não escalam com vw, de propósito — um drawer não vira
     painel gigante). O `md` (default) é a largura base + 25%. O drawer da IA tem
     largura própria (440px) na §7, independente destes tokens. */
  --ds-drawer-w-sm: 360px; /* 3 colunas */
  --ds-drawer-w-md: 550px; /* 4 colunas + 25% (default) */
  --ds-drawer-w-lg: 600px; /* 6 colunas */
  --ds-drawer-w-xl: 800px; /* 8 colunas */

  /* --- 1.8 Bridge --tblr-* (tema CLARO) ------------------------------------
     Repontamos as variáveis que os componentes do Tabler leem para a paleta
     neutra, de modo que cards/tabelas/botões acompanhem sem reescrever o
     vendor. Mantém o reset de raio (§1.1). */
  --tblr-body-bg: var(--ds-body-bg);
  --tblr-body-color: var(--ds-text);
  --tblr-secondary-bg: var(--ds-surface-2);
  --tblr-secondary-color: var(--ds-text-muted);
  --tblr-border-color: var(--ds-border);
  --tblr-border-color-translucent: var(--ds-border);
  --tblr-primary: var(--ds-accent);
  --tblr-primary-rgb: 59, 91, 219; /* #3b5bdb (índigo v4) */
  --tblr-success: var(--ds-income);
  --tblr-success-rgb: 14, 159, 110; /* #0e9f6e (money-in) */
  --tblr-danger: var(--ds-expense);
  --tblr-danger-rgb: 229, 72, 77; /* #e5484d (money-out) */

  /* --- 1.9 Elevação (DESIGN §4) — borda 1px + sombra sutil ------------------
     Escala curta e0–e3. e0 não tem sombra (fundo da página). Repontada no
     escuro (§1.7) — lá a sombra rende pouco e a separação migra p/ a borda. */
  --ds-shadow-1:
    0 1px 2px rgba(13, 16, 28, 0.06), 0 1px 1px rgba(13, 16, 28, 0.03); /* cartões/tabelas */
  --ds-shadow-2:
    0 4px 12px rgba(13, 16, 28, 0.09), 0 2px 4px rgba(13, 16, 28, 0.05); /* dropdown/popover/FAB */
  --ds-shadow-3:
    0 16px 40px rgba(13, 16, 28, 0.18), 0 4px 12px rgba(13, 16, 28, 0.08); /* drawers/modais */

  /* --- 1.10 Motion e foco (DESIGN §7) --------------------------------------
     Rápido, preciso e contido. Substitui as durações soltas (0.15/0.2/0.25/0.3s)
     espalhadas pelo arquivo e nos CSS de componente. */
  --ds-motion-fast: 120ms; /* hover/press/tinta */
  --ds-motion: 200ms; /* menu/drawer/abas */
  --ds-motion-slow: 320ms; /* overlays maiores, FAB→drawer */
  --ds-ease: cubic-bezier(0.2, 0, 0, 1); /* padrão (desacelera no fim) */
  --ds-ease-emphasis: cubic-bezier(0.16, 1, 0.3, 1); /* entradas com ênfase */
  --ds-focus: 2px solid var(--ds-accent); /* anel de foco (outline) */
  --ds-focus-offset: 2px;

  /* --- 1.11 Escala tipográfica (DESIGN §13) — antes havia um único tamanho -- */
  --ds-fs-xs: 11px;
  --ds-fs-sm: 12px;
  --ds-fs-md: 13.5px; /* == --ds-font-size-base */
  --ds-fs-lg: 15px;
  --ds-fs-xl: 18px;
  --ds-fs-display: 22px;
  --ds-lh-tight: 1.25;
  --ds-fw-medium: 500;
  --ds-fw-semibold: 600;
  --ds-fw-bold: 700; /* Inter 700 (carregado no <head>) — totais/ênfase forte */

  /* --- 1.12 Régua de botão (DESIGN §12) — menores que o Tabler ------------- */
  --ds-btn-h-sm: 26px; /* linhas/filtros densos */
  --ds-btn-h: 30px; /* padrão */
  --ds-btn-h-lg: 38px; /* CTA público */

  /* --- 1.13 Cores utilitárias (DESIGN §13) --------------------------------- */
  --ds-on-accent: #ffffff; /* texto/ícone sobre acento/gradiente (mata #fff hardcoded) */
  --ds-backdrop: rgba(13, 16, 28, 0.45); /* véu de overlay (consolida .4/.5) */

  /* --- 1.14 Identidade de IA (DESIGN §2.5/§8) — a única superfície de marca - */
  --ds-ai-gradient: linear-gradient(135deg, #3b5bdb, #7c5cfb); /* índigo→violeta */
  --ds-ai-accent: #7c5cfb; /* acento/glow da IA (violeta, distinto do acento de UI) */
  --ds-ai-glow: 0 0 0 4px color-mix(in srgb, #7c5cfb 22%, transparent);
  --ds-fab-size: 52px;
}

/* --- 1.7 Tema ESCURO (DESIGN.md §2 — Fase 6) --------------------------------
   Os tokens autorais ACOMPANHAM o tema do Tabler no modo escuro (em vez de uma
   paleta dark inventada): assim sidebar/footer/drawer/painel de IA combinam com
   os cards do Tabler. O modo claro permanece com a paleta autoral original
   acima — nada muda nele. O `data-bs-theme` vai no <html> (JS em base.html).

   ESCOPADO em :root de propósito — a <aside> carrega `data-bs-theme="dark"` fixo
   no markup; um seletor `[data-bs-theme="dark"]` solto casaria com ela e forçaria
   --ds-text claro NO TEMA CLARO (texto claro sobre fundo claro). Só o tema do
   <html> deve trocar os tokens. */
:root[data-bs-theme="dark"] {
  /* Paleta escura neutra (v3). Repontamos --ds-* para valores literais e
     também os --tblr-* lidos pelo vendor, espelhando a §1.8 do tema claro. */
  --ds-body-bg: #0c0e13; /* carvão azulado v4 (não preto puro) */
  --ds-surface: #15181f;
  --ds-surface-2: #1d212a;
  --ds-text: #e7e9ee;
  --ds-text-muted: #aab2c0;
  --ds-text-faint: #838b99;
  --ds-border: #262b34;
  --ds-border-strong: #353c47;

  /* Acento (índigo claro no escuro) + DINHEIRO */
  --ds-accent: #6182f5;
  --ds-accent-strong: #84a0f8;
  --ds-accent-tint: #18213a;
  --ds-money-in: #2dd498;
  --ds-money-out: #ff6166;
  --ds-money-neutral: #aab2c0;
  --ds-expense: var(--ds-money-out);
  --ds-revenue: var(--ds-money-in);
  --ds-income: var(--ds-money-in);
  --ds-warn: #e0a85f;

  /* Cores de titular (escuro) */
  --ds-holder-pf: #3cc7cd;
  --ds-holder-pj: #93a3c4;
  --ds-holder-fazenda: #c9a86a;

  /* Projetos (escuro) — spec §19.7; tons mais claros p/ fundo carvão */
  --ds-prio-low: #8b93a3;
  --ds-prio-medium: #6a93f7;
  --ds-prio-high: #e0a85f;
  --ds-prio-urgent: #ff6b5e;
  --ds-type-epic: #a98bff;
  --ds-type-story: #6aa5f2;
  --ds-type-task: #8291ab;
  --ds-type-bug: #ff6b5e;
  --ds-type-spike: #d6a24f;
  --ds-wip-over: #ff6b5e;
  --ds-critical: #ff6166;
  --ds-chart-1: #6182f5;
  --ds-chart-2: #e79a3c;
  --ds-chart-3: #24b3a6;
  --ds-chart-4: #b48cff;
  --ds-chart-5: #ec74a9;
  --ds-chart-6: #5cc07d;
  --ds-chart-7: #55b6e6;
  --ds-chart-8: #8b93a8;

  /* Bridge --tblr-* (escuro) */
  --tblr-body-bg: var(--ds-body-bg);
  --tblr-body-color: var(--ds-text);
  --tblr-secondary-bg: var(--ds-surface-2);
  --tblr-secondary-color: var(--ds-text-muted);
  --tblr-border-color: var(--ds-border);
  --tblr-border-color-translucent: var(--ds-border);
  --tblr-primary: var(--ds-accent);
  --tblr-primary-rgb: 97, 130, 245; /* #6182f5 */
  --tblr-success: var(--ds-income);
  --tblr-success-rgb: 45, 212, 152; /* #2dd498 (money-in) */
  --tblr-danger: var(--ds-expense);
  --tblr-danger-rgb: 255, 97, 102; /* #ff6166 (money-out) */

  /* Elevação no escuro (DESIGN §4): a sombra rende pouco, então enfraquece e a
     separação migra para a borda/superfície. */
  --ds-shadow-1: 0 1px 2px rgba(0, 0, 0, 0.45);
  --ds-shadow-2: 0 6px 16px rgba(0, 0, 0, 0.55);
  --ds-shadow-3: 0 20px 48px rgba(0, 0, 0, 0.66);
  --ds-backdrop: rgba(0, 0, 0, 0.62);
}

/* =============================================================================
   2. BASE
============================================================================= */
/* iOS/WebView: não reescalar fontes ao girar; sem flash de tap; sem elástico que
   "vaza" o scroll para o WebView; remove o delay de 300ms / double-tap-zoom. */
html {
  -webkit-text-size-adjust: 100%;
}
body {
  background: var(--ds-body-bg);
  font-family: var(--ds-font-sans);
  letter-spacing: var(--ds-letter-spacing); /* mesmo tracking do mobile */
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior-y: none;
}
button,
a {
  touch-action: manipulation;
}

/* Números tabulares (dinheiro/KPIs alinhados) — DESIGN §1/§9. */
.ds-num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}

/* Foco consistente e visível (DESIGN §7) — substitui os `2px solid accent`
   repetidos à mão. Só no foco por teclado (:focus-visible). */
:focus-visible {
  outline: var(--ds-focus);
  outline-offset: var(--ds-focus-offset);
}

/* Régua de botão premium (DESIGN §2.3/§12): menores que o default do Tabler.
   Aplicada pelas CSS vars que o próprio .btn do Tabler consome — sem reescrever
   o vendor. Ícone-só permanece quadrado na mesma altura. */
.btn {
  --tblr-btn-padding-y: 0.25rem; /* 4px */
  --tblr-btn-padding-x: 0.75rem; /* 12px */
  --tblr-btn-font-size: var(--ds-fs-md);
  min-height: var(--ds-btn-h);
}
.btn-sm,
.btn-group-sm > .btn {
  --tblr-btn-padding-y: 0.125rem; /* 2px */
  --tblr-btn-padding-x: 0.5rem; /* 8px */
  --tblr-btn-font-size: var(--ds-fs-sm);
  min-height: var(--ds-btn-h-sm);
}
.btn-lg,
.btn-group-lg > .btn {
  --tblr-btn-padding-y: 0.5rem; /* 8px */
  --tblr-btn-padding-x: 1rem; /* 16px */
  --tblr-btn-font-size: var(--ds-fs-lg);
  min-height: var(--ds-btn-h-lg);
}
/* Ícone-só: quadrado na mesma altura do tamanho correspondente. */
.btn-icon {
  width: var(--ds-btn-h);
  padding-inline: 0;
}
.btn-sm.btn-icon {
  width: var(--ds-btn-h-sm);
}
.btn-lg.btn-icon {
  width: var(--ds-btn-h-lg);
}

/* Fallback global de movimento reduzido (DESIGN §7) — obrigatório. Anula
   transições/animações para quem pede menos movimento; cada componente pode
   trazer um fallback estático específico (ex.: FAB vira pulso de cor). */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* =============================================================================
   3. REGIÕES DO SHELL  (camada autoral — o LAYOUT é do Tabler)
   -----------------------------------------------------------------------------
   O layout do shell (page / page-wrapper / page-body / navbar-vertical fixa) é
   100% Tabler e permanece intacto. Esta seção só aplica a CAMADA AUTORAL sobre
   as regiões REAIS do Tabler: cor/divisor da sidebar e cosmética do footer.

   A geometria do shell do DESIGN.md §5 (navbar dona do chrome, ocupando a
   viewport inteira; main como única região com scroll; sem topbar/footer) está
   na §6. Esta seção §3 cobre só a CAMADA AUTORAL (cor/divisor da sidebar); a §6
   cobre o POSICIONAMENTO.
============================================================================= */

/* -----------------------------------------------------------------------------
   Navbar v4 (.ds-nav) — sistema próprio do shell Premium (design-system-v4.html).
   Substitui o chrome do Tabler (.navbar-vertical/.nav-link/dropup): a <nav> NÃO
   carrega data-bs-theme; cor/superfície vêm direto dos tokens --ds-*, que já
   acompanham o tema do <html>. O POSICIONAMENTO (fixa/drawer/rail) fica na §6.
----------------------------------------------------------------------------- */
.ds-nav {
  display: flex;
  flex-direction: column;
  background: var(--ds-surface);
  border-right: 1px solid var(--ds-border);
  width: var(--ds-aside-w);
}

/* Topo: marca + chevron do rail, e o seletor de titular. */
.ds-nav-top {
  flex: 0 0 auto;
  padding: var(--ds-space-3);
  /* abaixo do notch/status bar (iOS standalone/WKWebView) */
  padding-top: calc(var(--ds-space-3) + env(safe-area-inset-top, 0px));
  border-bottom: 1px solid var(--ds-border);
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-2);
}
.ds-nav-brandrow {
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
}
.ds-brand {
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
  font-weight: var(--ds-fw-semibold);
  font-size: var(--ds-fs-lg);
  color: var(--ds-text);
  text-decoration: none;
  min-width: 0;
}
.ds-brand .mark {
  width: 26px;
  height: 26px;
  flex: 0 0 26px;
  display: grid;
  place-items: center;
}
.ds-brand .mark svg,
.ds-brand .mark img {
  width: 26px;
  height: 26px;
}
.ds-brand .app-brand-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-rail-chevron {
  margin-left: auto;
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  border: none;
  background: transparent;
  color: var(--ds-text-faint);
  border-radius: var(--ds-radius-xs);
  cursor: pointer;
  transition:
    background var(--ds-motion-fast) var(--ds-ease),
    transform var(--ds-motion) var(--ds-ease);
}
.ds-rail-chevron:hover {
  background: var(--ds-surface-2);
  color: var(--ds-text);
}

/* Seletor de entidade/negócio (PF/PJ/Fazenda/Consolidado) — DESIGN §3. */
.ds-ctx-wrap {
  position: relative;
}
.ds-ctx {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 8px;
  border: 1px solid var(--ds-border);
  background: var(--ds-surface-2);
  border-radius: var(--ds-radius-xs);
  color: var(--ds-text);
  font: inherit;
  font-size: var(--ds-fs-sm);
  cursor: pointer;
}
.ds-ctx:hover {
  border-color: var(--ds-border-strong);
}
.ds-ctx .dot2 {
  width: 8px;
  height: 8px;
  border-radius: var(--ds-radius-round);
  background: var(--ds-accent);
  flex: 0 0 8px;
}
.ds-ctx .dot2.pf {
  background: var(--ds-holder-pf);
}
.ds-ctx .dot2.pj {
  background: var(--ds-holder-pj);
}
.ds-ctx .dot2.fazenda {
  background: var(--ds-holder-fazenda);
}
.ds-ctx .label {
  flex: 1;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-ctx svg {
  width: 14px;
  height: 14px;
  color: var(--ds-text-faint);
  flex: 0 0 14px;
}
.ds-ctx-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-sm);
  box-shadow: var(--ds-shadow-2);
  padding: var(--ds-space-1);
  z-index: var(--ds-z-dropdown);
  max-height: 60vh;
  overflow-y: auto;
}
.ds-ctx-menu .grp {
  font-size: var(--ds-fs-xs);
  color: var(--ds-text-faint);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 6px 10px 2px;
}
.ds-ctx-menu button {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 7px 10px;
  border: none;
  background: transparent;
  border-radius: var(--ds-radius-xs);
  color: var(--ds-text);
  font: inherit;
  font-size: var(--ds-fs-sm);
  cursor: pointer;
  text-align: left;
}
.ds-ctx-menu button:hover {
  background: var(--ds-surface-2);
}
.ds-ctx-menu button.is-active {
  color: var(--ds-accent);
  font-weight: var(--ds-fw-medium);
}
.ds-ctx-menu .tag {
  margin-left: auto;
}

/* Meio (rolável): navegação agrupada em seções. */
.ds-nav-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: var(--ds-space-2);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.ds-nav-sec {
  font-size: var(--ds-fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ds-text-faint);
  font-weight: var(--ds-fw-medium);
  padding: 14px 10px 4px;
}
.ds-nav-sec:first-child {
  padding-top: 4px;
}
.ds-nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 10px;
  border-radius: var(--ds-radius-xs);
  color: var(--ds-text-muted);
  text-decoration: none;
  font-size: 13px;
  font-weight: 450;
  line-height: 1.2;
  cursor: pointer;
  position: relative;
  transition:
    background var(--ds-motion-fast) var(--ds-ease),
    color var(--ds-motion-fast) var(--ds-ease),
    box-shadow var(--ds-motion-fast) var(--ds-ease);
  white-space: nowrap;
}
.ds-nav-item svg {
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
  color: var(--ds-text-faint);
  transition: color var(--ds-motion-fast) var(--ds-ease);
}
.ds-nav-item:hover {
  background: var(--ds-surface-2);
  color: var(--ds-text);
}
.ds-nav-item:hover svg {
  color: var(--ds-text-muted);
}
.ds-nav-item.active {
  background: color-mix(in srgb, var(--ds-accent) 12%, transparent);
  color: var(--ds-accent);
  font-weight: var(--ds-fw-semibold);
  box-shadow: inset 2px 0 0 var(--ds-accent);
}
.ds-nav-item.active svg {
  color: var(--ds-accent);
}

/* Rodapé: avatar (área de login) + menu + sair. */
.ds-nav-foot {
  flex: 0 0 auto;
  border-top: 1px solid var(--ds-border);
  padding: var(--ds-space-2);
  padding-bottom: calc(var(--ds-space-2) + env(safe-area-inset-bottom, 0px));
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--ds-space-1);
}
.ds-avatar-btn {
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
  flex: 1;
  min-width: 0;
  padding: var(--ds-space-2);
  border: none;
  background: transparent;
  border-radius: var(--ds-radius-xs);
  cursor: pointer;
  color: var(--ds-text);
}
.ds-avatar-btn:hover {
  background: var(--ds-surface-2);
}
.ds-avatar {
  width: 28px;
  height: 28px;
  border-radius: var(--ds-radius-round);
  background: var(--ds-income);
  color: #fff;
  display: grid;
  place-items: center;
  font-weight: 600;
  font-size: 12px;
  flex: 0 0 28px;
}
.ds-avatar-btn .meta {
  flex: 1;
  text-align: left;
  overflow: hidden;
  min-width: 0;
}
.ds-avatar-btn .meta .name {
  font-size: var(--ds-fs-sm);
  font-weight: var(--ds-fw-medium);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-avatar-btn .meta .sub {
  font-size: var(--ds-fs-xs);
  color: var(--ds-text-faint);
}
.ds-menu {
  position: absolute;
  bottom: calc(100% + 4px);
  left: var(--ds-space-2);
  right: var(--ds-space-2);
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-xs);
  box-shadow: var(--ds-shadow-2);
  padding: var(--ds-space-1);
  z-index: var(--ds-z-dropdown);
}
.ds-menu button,
.ds-menu a {
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
  width: 100%;
  padding: var(--ds-space-2);
  border: none;
  background: transparent;
  border-radius: var(--ds-radius-xs);
  cursor: pointer;
  color: var(--ds-text);
  font: inherit;
  font-size: var(--ds-fs-md);
  text-decoration: none;
  text-align: left;
}
.ds-menu button:hover,
.ds-menu a:hover {
  background: var(--ds-surface-2);
}
.ds-menu hr {
  border: none;
  border-top: 1px solid var(--ds-border);
  margin: var(--ds-space-1) 0;
}
.ds-menu svg {
  width: 16px;
  height: 16px;
  flex: 0 0 16px;
}
.ds-menu .ds-menu-form {
  margin: 0;
}
.ds-menu select.form-select {
  height: var(--ds-btn-h);
  font-size: var(--ds-fs-sm);
}
.ds-menu .ds-menu-label {
  font-size: var(--ds-fs-xs);
  color: var(--ds-text-faint);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 6px var(--ds-space-2) 2px;
}
.ds-menu .ds-menu-credit {
  text-transform: none;
  letter-spacing: 0;
}
/* Cabeçalho do menu avatar (start-menu): avatar + nome + papel. */
.ds-menu-user-header {
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
  padding: var(--ds-space-2) var(--ds-space-2) var(--ds-space-1);
  border-bottom: 1px solid var(--ds-border);
  margin-bottom: var(--ds-space-1);
}
.ds-menu-user-meta {
  flex: 1;
  min-width: 0;
}
.ds-menu-user-meta .name {
  font-size: var(--ds-fs-sm);
  font-weight: var(--ds-fw-medium);
  color: var(--ds-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ds-menu-user-meta .sub {
  font-size: var(--ds-fs-xs);
  color: var(--ds-text-faint);
}
/* Caret discreto no botão do rodapé sinalizando que abre o menu (troca de
   workspace/usuário). Some no rail (junto com .meta). */
.ds-avatar-caret {
  width: 14px;
  height: 14px;
  flex: 0 0 14px;
  color: var(--ds-text-faint);
}
/* Troca de workspace no menu iniciar: lista clicável (1 clique alterna), no
   mesmo padrão do seletor de titular (.ds-ctx-menu). */
.ds-menu-ws {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 40vh;
  overflow-y: auto;
}
.ds-menu-ws-item {
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
  width: 100%;
  padding: 7px var(--ds-space-2);
  border: none;
  background: transparent;
  border-radius: var(--ds-radius-xs);
  color: var(--ds-text);
  font: inherit;
  font-size: var(--ds-fs-sm);
  text-align: left;
  cursor: pointer;
}
.ds-menu-ws-item:hover {
  background: var(--ds-surface-2);
}
.ds-menu-ws-mark {
  flex: 0 0 22px;
  width: 22px;
  height: 22px;
  border-radius: var(--ds-radius-xs);
  background: var(--ds-surface-2);
  color: var(--ds-text-muted);
  display: grid;
  place-items: center;
  font-size: 11px;
  font-weight: var(--ds-fw-semibold);
}
.ds-menu-ws-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-menu-ws-check {
  flex: 0 0 16px;
  width: 16px;
  height: 16px;
  color: var(--ds-accent);
}
.ds-menu-ws-item.is-active {
  color: var(--ds-accent);
  font-weight: var(--ds-fw-medium);
}
.ds-menu-ws-item.is-active .ds-menu-ws-mark {
  background: color-mix(in srgb, var(--ds-accent) 16%, transparent);
  color: var(--ds-accent);
}
.ds-logout {
  flex: 0 0 auto;
  margin-left: auto;
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border: none;
  background: transparent;
  color: var(--ds-text-faint);
  border-radius: var(--ds-radius-xs);
  cursor: pointer;
  transition:
    background var(--ds-motion-fast) var(--ds-ease),
    color var(--ds-motion-fast) var(--ds-ease);
}
.ds-logout:hover {
  background: var(--ds-surface-2);
  color: var(--ds-expense);
}
.ds-logout svg {
  width: 18px;
  height: 18px;
}

/* Controles fixos no canto superior direito: [olho] [tema (luas)]. */
.ds-topright {
  position: fixed;
  top: calc(12px + env(safe-area-inset-top, 0px));
  right: calc(16px + env(safe-area-inset-right, 0px));
  display: flex;
  gap: 6px;
  z-index: var(--ds-z-topright);
  transition:
    opacity var(--ds-motion) var(--ds-ease),
    visibility var(--ds-motion) var(--ds-ease);
}
/* Quando o drawer AI está aberto, ocultar topright e FAB que ficam por cima */
body.is-ai-open .ds-topright,
body.is-ai-open .ds-fab,
body.is-ai-open .mtx-fab {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
.ds-iconbtn {
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border: none;
  background: transparent;
  padding: 0;
  color: var(--ds-text-muted);
  cursor: pointer;
  transition: color var(--ds-motion-fast) var(--ds-ease);
}
.ds-iconbtn:hover {
  color: var(--ds-text);
}
.ds-iconbtn svg {
  width: 20px;
  height: 20px;
}

/* =============================================================================
   4. COMPONENTES AUTORAIS
============================================================================= */

/* 4.1 Tabelas ---------------------------------------------------------------- */
.table-responsive {
  width: 100%;
}

.table {
  width: 100%;
  /* dígitos tabulares: colunas de valor alinhadas, igual aos valores do mobile */
  font-variant-numeric: tabular-nums;
}

/* Células não quebram em telas estreitas (rolagem horizontal via
   .table-responsive); a partir de 992px voltam a quebrar. Regra preservada do
   main.css para não mudar a aparência das tabelas. */
.table th,
.table td {
  white-space: nowrap;
}

@media (min-width: 992px) {
  .table th,
  .table td {
    white-space: normal;
  }
}

/* Mobile (<768px) — a tela de transações deixou de transformar a tabela em
   cartões via CSS. Agora um componente dedicado (mobile-tx.css + mobile-tx.js,
   prefixo .mtx-) renderiza a lista agrupada por dia a partir das mesmas linhas
   .tx-row. A tabela SSR continua sendo a fonte de verdade, apenas oculta no
   mobile. tablet/desktop/tv (>=768px) seguem com a tabela original. */

/* 4.2 ds-table — tabela premium de dados (DESIGN.md §16) ----------------------
   Sticky header, tabular-nums, status pills com color-mix (mesmo padrão do
   .ds-due-badge). Todas as cores via --ds-* tokens — funciona em claro e escuro
   sem overrides adicionais. */
.ds-table-surface {
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-md);
  overflow: hidden;
  background: var(--ds-surface);
}
.ds-table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.ds-table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}
.ds-table thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--ds-surface);
  padding: 9px 12px;
  font-size: 11px;
  font-weight: 500;
  color: var(--ds-text-faint);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  border-bottom: 1px solid var(--ds-border);
  white-space: nowrap;
}
.ds-table tbody td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--ds-border);
  color: var(--ds-text);
  vertical-align: middle;
}
.ds-table tbody tr:last-child td {
  border-bottom: none;
}
.ds-table tbody tr[role="button"] {
  cursor: pointer;
  transition: background 0.1s;
}
.ds-table tbody tr[role="button"]:hover td {
  background: var(--ds-surface-2);
}
.ds-table tbody tr[role="button"]:focus-visible {
  outline: 2px solid var(--ds-accent);
  outline-offset: -2px;
}
.ds-table-amount {
  text-align: right;
  font-weight: 500;
  white-space: nowrap;
}
.ds-tx-expense {
  color: var(--ds-expense);
}
.ds-tx-revenue {
  color: var(--ds-income);
}
.ds-tx-name {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 500;
}
.ds-tx-icon--expense {
  color: var(--ds-expense);
  font-size: 14px;
  flex-shrink: 0;
}
.ds-tx-icon--revenue {
  color: var(--ds-income);
  font-size: 14px;
  flex-shrink: 0;
}
.ds-tx-icon--transfer {
  color: var(--ds-text-muted);
  font-size: 14px;
  flex-shrink: 0;
}
.ds-tx-sub {
  font-size: 11px;
  color: var(--ds-text-faint);
  margin-top: 2px;
}
.ds-tx-recur {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 11px;
  font-weight: 400;
  color: var(--ds-text-muted);
  padding: 1px 5px;
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-xs);
  margin-left: 2px;
  vertical-align: middle;
}
.ds-tx-recur .ti {
  font-size: 11px;
}
.ds-cell-muted {
  color: var(--ds-text-muted);
}
.ds-cell-truncate {
  max-width: 140px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ds-tx-due--overdue {
  color: var(--ds-expense);
}
.ds-tx-status {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 8px;
  border-radius: var(--ds-radius-xs);
  font-size: 11px;
  font-weight: 500;
  white-space: nowrap;
  border: 1px solid transparent;
}
.ds-tx-status .ti {
  font-size: 13px;
}
.ds-tx-status--paid {
  --_c: var(--tblr-success, var(--ds-income));
  color: var(--_c);
  background: color-mix(in srgb, var(--_c) 12%, var(--ds-surface));
  border-color: color-mix(in srgb, var(--_c) 25%, transparent);
}
.ds-tx-status--overdue {
  --_c: var(--tblr-danger, var(--ds-expense));
  color: var(--_c);
  background: color-mix(in srgb, var(--_c) 12%, var(--ds-surface));
  border-color: color-mix(in srgb, var(--_c) 25%, transparent);
}
.ds-tx-status--pending {
  color: var(--ds-text-muted);
  background: var(--ds-surface-2);
  border-color: var(--ds-border);
}
.ds-btn-quitar {
  font: inherit;
  font-size: 11px;
  font-weight: 500;
  padding: 3px 8px;
  background: transparent;
  border: 1px solid var(--ds-income);
  border-radius: var(--ds-radius-xs);
  color: var(--ds-income);
  cursor: pointer;
  white-space: nowrap;
  transition:
    background 0.1s,
    color 0.1s;
}
.ds-btn-quitar:hover {
  background: var(--ds-income);
  color: var(--ds-surface);
}
.ds-table-empty-row td {
  border-bottom: none !important;
}
.ds-table-empty {
  padding: 3rem 1.5rem;
  text-align: center;
  color: var(--ds-text-faint);
  font-size: 13px;
}
.ds-table-empty .ti {
  font-size: 32px;
  display: block;
  margin-bottom: 8px;
}
/* Sort — coluna clicável com indicador ↑↓ */
.ds-table thead th[aria-sort] {
  cursor: pointer;
  user-select: none;
}
.ds-table thead th[aria-sort]:hover {
  color: var(--ds-text-muted);
}
.ds-table thead th[aria-sort]::after {
  content: " \2195";
  font-size: 10px;
  opacity: 0.4;
  font-style: normal;
}
.ds-table thead th[aria-sort="ascending"]::after {
  content: " \2191";
  opacity: 1;
}
.ds-table thead th[aria-sort="descending"]::after {
  content: " \2193";
  opacity: 1;
}

/* 4.2c Paginação (DESIGN.md §16.5) — rodapé da .ds-table-surface OU standalone
   sob qualquer coleção (grade de cartões, lista). Radius-0, tokens, tabular-nums. */
.ds-pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ds-space-4);
  flex-wrap: wrap;
  padding: var(--ds-space-2) var(--ds-space-4);
  border-top: 1px solid var(--ds-border);
  font-size: 13px;
  color: var(--ds-text-muted);
}
.ds-pagination__count strong {
  font-weight: 500;
  color: var(--ds-text);
}
.ds-pagination__nav {
  display: flex;
  align-items: center;
  gap: var(--ds-space-3);
}
.ds-pagination__perpage {
  display: flex;
  align-items: center;
  gap: var(--ds-space-1-5);
  white-space: nowrap;
}
.ds-pagination__perpage .form-select {
  width: auto;
  height: 32px;
  padding: 0 26px 0 8px;
}
.ds-pagination__pages {
  display: flex;
  align-items: center;
  gap: 2px;
}
.ds-pagination__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  padding: 0 8px;
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-xs);
  color: var(--ds-text);
  text-decoration: none;
  font-variant-numeric: tabular-nums;
  transition:
    background var(--ds-motion-fast, 120ms),
    border-color var(--ds-motion-fast, 120ms);
}
.ds-pagination__btn:hover {
  background: var(--ds-surface-2);
  border-color: var(--ds-border-strong);
}
.ds-pagination__btn.is-current {
  background: var(--ds-accent-tint);
  border-color: var(--ds-accent);
  color: var(--ds-accent);
  font-weight: 500;
}
.ds-pagination__btn[aria-disabled="true"] {
  opacity: 0.4;
  pointer-events: none;
}
.ds-pagination__gap {
  padding: 0 4px;
  color: var(--ds-text-faint);
}
@media (max-width: 767.98px) {
  .ds-pagination {
    flex-direction: column;
    align-items: stretch;
    gap: var(--ds-space-2);
  }
  .ds-pagination__count {
    text-align: center;
  }
  .ds-pagination__nav {
    justify-content: center;
  }
  .ds-pagination__perpage {
    display: none;
  }
  /* no celular fica ‹ anterior · [atual] · próxima › — enxuto */
  .ds-pagination__btn--edge,
  .ds-pagination__gap,
  .ds-pagination__btn.ds-num:not(.is-current) {
    display: none;
  }
}
/* 4.2b ds-table responsiva — card-stack no mobile (DESIGN.md §16) ------------
   A MESMA tabela vira cartões empilhados no celular, dirigida só por atributos
   no markup — sem JS, sem segundo layout. Convenção única para TODAS as telas:
     • data-label="…"     rótulo exibido antes do valor no modo cartão
     • data-col="title"   vira o título do cartão (sem rótulo, peso maior)
     • data-col="amount"  número-chave, fixado no topo-direito do cartão
     • data-col="actions" vira a barra de ações no rodapé do cartão
     • .ds-col--lg         oculta <768px (baixa prioridade)
     • .ds-col--md         oculta <1100px (média prioridade)
     • .ds-num             alinha número à direita + tabular-nums (desktop) */
.ds-num,
.ds-table th.ds-num,
.ds-table td.ds-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* média prioridade — some entre tablet estreito e desktop */
@media (max-width: 1099.98px) {
  .ds-table th.ds-col--md,
  .ds-table td.ds-col--md {
    display: none;
  }
}

/* MOBILE — cada linha da tabela vira um cartão */
@media (max-width: 767.98px) {
  .ds-table th.ds-col--lg,
  .ds-table td.ds-col--lg {
    display: none;
  }

  /* o surface deixa de ter moldura/scroll próprios — a moldura é o cartão */
  .ds-table-surface {
    border: none;
    background: transparent;
    border-radius: 0;
    overflow: visible;
  }
  .ds-table-scroll {
    overflow-x: visible;
  }

  .ds-table {
    display: block;
  }
  .ds-table thead {
    display: none;
  }
  .ds-table tbody {
    display: block;
  }

  .ds-table tbody tr {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: baseline;
    gap: 2px 12px;
    padding: 12px 14px;
    margin-bottom: 8px;
    background: var(--ds-surface);
    border: 1px solid var(--ds-border);
    border-radius: var(--ds-radius-md);
  }
  .ds-table tbody tr[role="button"]:active {
    background: var(--ds-surface-2);
  }
  .ds-table tbody tr[role="button"]:hover td {
    background: transparent;
  }

  .ds-table tbody td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 3px 0;
    border-bottom: none;
    grid-column: 1 / -1;
    font-size: 13px;
    max-width: none;
  }
  /* rótulo vindo do data-label */
  .ds-table tbody td[data-label]::before {
    content: attr(data-label);
    color: var(--ds-text-faint);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.02em;
    flex-shrink: 0;
  }

  /* título do cartão: 1ª coluna da 1ª linha, sem rótulo */
  .ds-table tbody td[data-col="title"] {
    grid-column: 1;
    grid-row: 1;
    display: block;
    font-size: 14px;
    font-weight: 600;
    color: var(--ds-text);
  }
  .ds-table tbody td[data-col="title"]::before {
    content: none;
  }

  /* número-chave: topo-direito, alinhado ao título */
  .ds-table tbody td[data-col="amount"] {
    grid-column: 2;
    grid-row: 1;
    display: block;
    text-align: right;
    font-size: 14px;
    font-weight: 600;
    white-space: nowrap;
  }
  .ds-table tbody td[data-col="amount"]::before {
    content: none;
  }

  /* barra de ações: rodapé do cartão, largura total, alinhada à direita */
  .ds-table tbody td[data-col="actions"] {
    justify-content: flex-end;
    gap: 8px;
    padding-top: 10px;
    margin-top: 4px;
    border-top: 1px solid var(--ds-border);
  }
  .ds-table tbody td[data-col="actions"]::before {
    content: none;
  }

  /* célula truncada volta a fluir dentro do cartão */
  .ds-cell-truncate {
    max-width: none;
    white-space: normal;
    overflow: visible;
  }
  /* o subtítulo (titular • categoria) acompanha o título no cartão */
  .ds-table tbody td[data-col="title"] .ds-tx-sub {
    white-space: normal;
  }

  /* OPT-OUT (.ds-table--scroll): grades de edição (inputs por célula) e tabelas
     densas onde empilhar não ajuda — mantêm tabela + scroll horizontal no mobile.
     O surface volta a ter moldura e o scroll próprio. */
  .ds-table-surface:has(.ds-table--scroll) {
    border: 1px solid var(--ds-border);
    border-radius: var(--ds-radius-md);
    background: var(--ds-surface);
    overflow: hidden;
  }
  .ds-table-surface:has(.ds-table--scroll) .ds-table-scroll {
    overflow-x: auto;
  }
  .ds-table--scroll {
    display: table;
  }
  .ds-table--scroll thead {
    display: table-header-group;
  }
  .ds-table--scroll tbody {
    display: table-row-group;
  }
  .ds-table--scroll tbody tr {
    display: table-row;
    grid-template-columns: none;
    gap: 0;
    padding: 0;
    margin: 0;
    background: transparent;
    border: none;
    border-radius: 0;
  }
  .ds-table--scroll tbody td {
    display: table-cell;
    grid-column: auto;
    padding: 10px 12px;
    border-bottom: 1px solid var(--ds-border);
    font-size: inherit;
  }
  .ds-table--scroll tbody td::before {
    content: none !important;
  }
  .ds-table--scroll .ds-col--lg {
    display: table-cell;
  }
}

/* 4.x Tablist (.ds-tabs) — componente reaproveitável -------------------------
   Scroller horizontal com underline no item ativo (visual nascido no mobile,
   .mtx-months/.mtx-month). Usado em qualquer largura via a macro
   components/tabs.html + tabs.js. Só tokens --ds-*. */
.ds-tabs {
  display: flex;
  align-items: center;
  gap: 4px;
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
  scroll-snap-type: x proximity;
  border-bottom: 1px solid var(--ds-border);
}
.ds-tabs::-webkit-scrollbar {
  display: none;
}
.ds-tab {
  flex: 0 0 auto;
  font: inherit;
  font-size: 13.5px;
  color: var(--ds-text-muted);
  background: transparent;
  border: none;
  padding: 10px 14px 12px;
  cursor: pointer;
  position: relative;
  scroll-snap-align: center;
  white-space: nowrap;
  transition: color 0.15s;
}
.ds-tab:hover {
  color: var(--ds-text);
}
.ds-tab.is-active {
  color: var(--ds-text);
  font-weight: 500;
}
.ds-tab.is-active::after {
  content: "";
  position: absolute;
  left: 14px;
  right: 14px;
  bottom: 0;
  height: 2px;
  background: var(--ds-accent);
}
.ds-tab:focus-visible {
  outline: 2px solid var(--ds-accent);
  outline-offset: -2px;
}

/* =============================================================================
   5. UTILITÁRIAS  (eliminam o CSS inline)
============================================================================= */

/* 5.1 Mostrar/esconder — UM mecanismo único (substitui .tab-panel{display:none}
   E o style="display:none" + condicional Jinja). Use .is-hidden no servidor. */
.is-hidden {
  display: none !important;
}

/* Painéis em abas (mantém o padrão por classe, agora unificado) */
.tab-panel {
  display: none;
}

.tab-panel.active {
  display: block;
}

/* 5.2 Larguras de coluna de tabela (trocam os style="width:.." dos <th>/<td>) */
.col-w-narrow {
  width: var(--ds-col-narrow);
} /* 50px  — Tipo / coluna compacta   */
.col-w-sm {
  width: var(--ds-col-sm);
} /* 110px — colunas de cards.html    */
.col-w-md {
  width: var(--ds-col-md);
} /* 120px — Vencimento, Valor, Ações */
.col-w-lg {
  width: var(--ds-col-lg);
} /* 130px — Status                   */
.col-w-xl {
  width: var(--ds-col-xl);
} /* 140px — Contraparte              */

/* 5.3 Largura mínima do input de busca (troca style="min-width:220px") */
.field-search {
  min-width: var(--ds-col-search);
}

/* 5.4 Célula truncada (troca style="max-width:140px" + title) */
.cell-truncate {
  max-width: var(--ds-col-xl);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* =============================================================================
   6. SHELL FIXO + RESPONSIVO  (DESIGN.md §5/§6 — Fases 1 e 3)
   -----------------------------------------------------------------------------
   Topbar full-width fixa no topo em TODAS as larguras. A partir daí dois regimes:

   • Mobile (<768): a aside é um DRAWER off-canvas (translateX), aberto por
     `body.is-drawer-open` (JS) com backdrop clicável; o body rola normalmente e
     o footer fica estático no fim do conteúdo (DESIGN §6).
   • Desktop (≥768): shell fixo — aside encostada na topbar, `.page-wrapper` é a
     ÚNICA região que rola e o footer fica fixo só sobre a largura do main
     (DESIGN §5). `body.is-rail` colapsa a aside em rail de ícones (--ds-rail-w).

   Mecânica da topbar: continua DENTRO do `.page-wrapper` na marcação, mas
   `position: fixed` é relativo à viewport (ignora a margem do pai), então vira
   full-width sem reordenar o DOM. As regras de margem do main casam a
   especificidade do Tabler (0,3,0) e vencem por ordem de carga (CSS depois).
============================================================================= */

/* A marca (.ds-brand), o seletor de titular (.ds-ctx) e o rodapé (.ds-avatar-btn)
   são estilizados na camada de componentes do navbar v4 (§3). Aqui fica só o
   POSICIONAMENTO do shell (fixa/drawer/rail). */

/* Coluna central do main: gutter de 1/12 de cada lado (DESIGN §5.2) — leitura
   confortável no espírito do main de um cliente de IA. Piso p/ telas estreitas. */
.ds-main {
  padding-inline: max(var(--ds-space-4), calc(100% / 12));
}
/* No mobile o gutter de 1/12 desperdiça largura — encosta o conteúdo. */
@media (max-width: 767.98px) {
  .ds-main {
    padding-inline: var(--ds-space-3);
  }
}
/* Os ~19 templates ainda trazem um .container-* próprio; o gutter agora vive
   UMA vez no .ds-main — neutralizamos o container interno (sem cap/gutter duplo). */
.ds-main .container-xl,
.ds-main .container,
.ds-main .container-fluid {
  max-width: none;
  width: 100%;
  margin-inline: 0;
  padding-inline: 0;
}

/* Glow de IA quase imperceptível no canto sup. direito do main (DESIGN §5.2):
   amarra o produto à linguagem AI-first sem competir com o conteúdo. */
.page-wrapper {
  background-image: radial-gradient(
    110% 55% at 100% 0,
    color-mix(in srgb, var(--ds-ai-accent) 5%, transparent),
    transparent 60%
  );
  background-repeat: no-repeat;
}

/* --- 6.1 As três faixas do navbar (.ds-nav-top / .ds-nav-scroll / .ds-nav-foot)
   e seus componentes ficam na camada §3. O .ds-nav já é flex-column de altura
   cheia; aqui resta só a fixação/drawer/rail nas media queries abaixo. */

/* Botão flutuante de menu (mobile) — substitui o gatilho da topbar removida. */
.app-nav-open {
  position: fixed;
  top: calc(var(--ds-space-3) + env(safe-area-inset-top, 0px));
  inset-inline-start: calc(var(--ds-space-3) + env(safe-area-inset-left, 0px));
  z-index: calc(var(--ds-z-aside) - 2);
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  box-shadow: var(--ds-shadow-2);
}

/* --- 6.2 Mobile (<768): aside vira drawer off-canvas (do topo, sem topbar) - */
@media (max-width: 767.98px) {
  .ds-nav {
    position: fixed;
    inset-block: 0;
    inset-inline-start: 0;
    width: var(--ds-aside-w);
    z-index: var(--ds-z-aside);
    transform: translateX(-100%);
    transition: transform var(--ds-motion-slow) var(--ds-ease);
  }

  body.is-drawer-open .ds-nav {
    transform: translateX(0);
  }

  /* Backdrop sobre o main quando o drawer abre; clique fecha (JS). */
  .app-drawer-backdrop {
    position: fixed;
    inset: 0;
    background: var(--ds-backdrop);
    opacity: 0;
    visibility: hidden;
    transition:
      opacity var(--ds-motion-slow) var(--ds-ease),
      visibility var(--ds-motion-slow) var(--ds-ease);
    z-index: calc(var(--ds-z-aside) - 1);
  }

  body.is-drawer-open .app-drawer-backdrop {
    opacity: 1;
    visibility: visible;
  }
}

/* Backdrop e o gatilho flutuante só existem no mobile. */
@media (min-width: 768px) {
  .app-drawer-backdrop,
  .app-nav-open {
    display: none;
  }
}

/* --- 6.3 Desktop (≥768): shell fixo, main é a única região que rola ------- */
@media (min-width: 768px) {
  /* body deixa de rolar — só o main (page-wrapper) rola */
  html,
  body.page {
    height: 100%;
  }

  body.page {
    overflow: hidden;
  }

  /* Aside: ocupa a viewport inteira (sem topbar acima), fixa (DESIGN §5.1). */
  .ds-nav {
    position: fixed;
    inset-block: 0;
    inset-inline-start: 0;
    z-index: var(--ds-z-aside);
    transition: width var(--ds-motion) var(--ds-ease);
  }

  /* Main: ÚNICA região que rola; viewport inteira (sem desconto de topbar). */
  .ds-nav ~ .page-wrapper {
    margin-inline-start: var(--ds-aside-w);
    height: 100vh;
    overflow-y: auto;
    transition: margin-inline-start var(--ds-motion) var(--ds-ease);
  }

  /* --- 6.4 Rail colapsado (body.is-rail): só ícones, 64px (DESIGN §5.2) --- */
  :is(body.is-rail, body.is-auto-rail) .ds-nav {
    width: var(--ds-rail-w);
  }
  :is(body.is-rail, body.is-auto-rail) .ds-nav ~ .page-wrapper {
    margin-inline-start: var(--ds-rail-w);
  }

  /* No rail sobra só o ícone: esconde rótulos (nav-items, marca, seletor de
     titular) e a meta do avatar. */
  :is(body.is-rail, body.is-auto-rail) .ds-nav .label,
  :is(body.is-rail, body.is-auto-rail) .ds-avatar-btn .meta,
  :is(body.is-rail, body.is-auto-rail) .ds-avatar-caret {
    display: none;
  }
  /* Seletor de titular vira só o dot, centrado. */
  :is(body.is-rail, body.is-auto-rail) .ds-ctx svg {
    display: none;
  }
  :is(body.is-rail, body.is-auto-rail) .ds-ctx {
    justify-content: center;
    padding: 6px 0;
  }
  /* Itens centralizam o ícone. */
  :is(body.is-rail, body.is-auto-rail) .ds-nav-item {
    justify-content: center;
    padding: 9px 0;
    gap: 0;
  }
  /* Seção no rail: o rótulo some e vira um divisor fino. */
  :is(body.is-rail, body.is-auto-rail) .ds-nav-sec {
    font-size: 0;
    padding: 0;
    height: 1px;
    background: var(--ds-border);
    margin: 8px 10px;
  }
  /* Topo empilha (marca em cima, chevron embaixo) e o chevron gira/centraliza. */
  :is(body.is-rail, body.is-auto-rail) .ds-nav-top > .ds-nav-brandrow {
    flex-direction: column;
    gap: var(--ds-space-1);
  }
  :is(body.is-rail, body.is-auto-rail) .ds-rail-chevron {
    transform: rotate(180deg);
    margin: 0 auto;
  }
  /* Sem espaço para o logout solto no rail; sai do fluxo (acessível via menu). */
  :is(body.is-rail, body.is-auto-rail) .ds-logout {
    display: none;
  }
  :is(body.is-rail, body.is-auto-rail) .ds-avatar-btn {
    justify-content: center;
    padding-inline: 0;
  }

  /* Em auto-rail o chevron some (sem sentido expandir manualmente). */
  body.is-auto-rail .ds-rail-chevron {
    display: none;
  }

  /* Seletor de titular: abre para a direita do rail (flyout), sem ser cortado. */
  :is(body.is-rail, body.is-auto-rail) .ds-ctx-menu {
    left: 0;
    right: auto;
    min-width: 220px;
    top: 0;
  }

  /* Menu do avatar: abre para a direita no rail (start-menu pattern). */
  :is(body.is-rail, body.is-auto-rail) .ds-menu {
    left: 0;
    right: auto;
    bottom: 0;
    min-width: 240px;
  }
}

/* =============================================================================
   7. ASSISTENTE DE IA  (DESIGN.md §7)
   -----------------------------------------------------------------------------
   Gatilho na topbar (barra central no desktop, ícone no mobile) abre um DRAWER
   offcanvas à direita (#ai_drawer): cabeçalho, thread rolável com as respostas
   FORMATADAS (markdown via marked.js) + botão de copiar, e o campo de escrita
   fixo no rodapé. É um offcanvas do Tabler/Bootstrap (JS bootstrap.Offcanvas) —
   sem backdrop (o conteúdo atrás continua usável e não some sob um véu).
============================================================================= */

/* --- 7.1 FAB de IA (gatilho) — DESIGN §5.4/§8.2 ----------------------------
   Único elemento de IA no shell: botão flutuante no canto inferior direito do
   main, com o gradiente de marca (a única superfície com gradiente). Abre o
   drawer (.js-ai-open) e responde à tecla "/". Recolhido = só o ícone; no
   hover/foco cresce numa pílula revelando "Pergunte à IA /". */
.ds-fab {
  position: fixed;
  z-index: var(--ds-z-fab);
  bottom: calc(var(--ds-space-5) + env(safe-area-inset-bottom, 0px));
  inset-inline-end: calc(var(--ds-space-5) + env(safe-area-inset-right, 0px));
  display: inline-flex;
  align-items: center;
  height: var(--ds-fab-size);
  width: var(--ds-fab-size);
  padding-inline: 14px; /* 14 + ícone 24 + 14 = 52 → ícone centrado quando recolhido */
  border: 0;
  border-radius: var(--ds-radius-pill);
  background: var(--ds-ai-gradient);
  color: var(--ds-on-accent);
  box-shadow: var(--ds-shadow-2);
  cursor: pointer;
  overflow: hidden;
  transition:
    width var(--ds-motion) var(--ds-ease),
    box-shadow var(--ds-motion) var(--ds-ease);
}
.ds-fab-icon {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
}
.ds-fab-label {
  white-space: nowrap;
  padding-inline-start: var(--ds-space-2);
  opacity: 0;
  max-width: 0;
  transition:
    opacity var(--ds-motion) var(--ds-ease),
    max-width var(--ds-motion) var(--ds-ease);
}
.ds-fab:hover,
.ds-fab:focus-visible {
  width: auto;
  box-shadow: var(--ds-shadow-2), var(--ds-ai-glow);
}
.ds-fab:hover .ds-fab-label,
.ds-fab:focus-visible .ds-fab-label {
  opacity: 1;
  max-width: 240px;
}
.ds-fab kbd {
  margin-inline-start: var(--ds-space-1);
  padding: 0 var(--ds-space-1);
  background: rgba(255, 255, 255, 0.18);
  color: var(--ds-on-accent);
  border: 0;
}
/* Onde a projeção mobile de lançamentos (.mtx-screen) já traz o FAB "Copiloto",
   esconde o FAB global p/ não duplicar a entrada de IA no mobile. */
@media (max-width: 767.98px) {
  body:has(.mtx-screen) .ds-fab {
    display: none;
  }
}

/* O ícone de IA "respira" (escala suave) — no FAB e no cabeçalho do drawer. O
   fallback de movimento reduzido é o killswitch global da §2. */
@media (prefers-reduced-motion: no-preference) {
  .app-ai-icon,
  .ds-fab-icon {
    transform-origin: center;
    animation: ai-breathe 3.5s ease-in-out infinite;
  }
}

@keyframes ai-breathe {
  0%,
  100% {
    transform: scale(1);
    opacity: 0.8;
  }
  50% {
    transform: scale(1.12);
    opacity: 1;
  }
}

/* Rótulos do menu do avatar acompanham o estado (igual aos ícones tema/valores). */
.theme-label-light {
  display: none;
}
:root[data-bs-theme="dark"] .theme-label-dark {
  display: none;
}
:root[data-bs-theme="dark"] .theme-label-light {
  display: inline;
}
.values-label-hide {
  display: none;
}
body.values-hidden .values-label-show {
  display: none;
}
body.values-hidden .values-label-hide {
  display: inline;
}

/* --- 7.2 Drawer ------------------------------------------------------------- */

/* Ocupa a viewport inteira à direita (sem topbar), coluna flex: cabeçalho +
   thread (rola) + composer fixo. Borda esquerda primária esmaecida = AI-first. */
.app-ai-drawer.offcanvas-end {
  top: 0;
  height: 100%;
  width: min(440px, 100vw);
  display: flex;
  flex-direction: column;
  background: var(--ds-surface);
  border-left: 2px solid color-mix(in srgb, var(--tblr-primary) 40%, var(--ds-border));
}

/* Mobile: quase tela cheia (some a barra estreita que aperta a leitura). */
@media (max-width: 575.98px) {
  .app-ai-drawer.offcanvas-end {
    width: 100vw;
  }
}

.app-ai-header {
  border-bottom: 1px solid var(--ds-border);
  padding: var(--ds-space-3) var(--ds-space-4);
}

/* Thread: a única região que rola; empilha as bolhas de cima para baixo. */
.app-ai-thread {
  flex: 1 1 auto;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-3);
  padding: var(--ds-space-4);
}

/* Estado vazio centralizado (some no 1º turno via JS). */
.app-ai-empty {
  margin: auto;
  text-align: center;
  color: var(--ds-text-muted);
}

.app-ai-suggestions {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-2);
  align-items: stretch;
}

/* --- 7.3 Bolhas de mensagem ------------------------------------------------- */
.app-ai-msg {
  max-width: 92%;
  padding: var(--ds-space-2) var(--ds-space-3);
  border: 1px solid var(--ds-border);
}

/* Pergunta do usuário: encostada à direita, com leve realce primário. */
.app-ai-msg-user {
  align-self: flex-end;
  background: color-mix(in srgb, var(--tblr-primary) 10%, var(--ds-surface));
  border-color: color-mix(in srgb, var(--tblr-primary) 30%, var(--ds-border));
}

/* Resposta da IA: encostada à esquerda, largura cheia para acomodar markdown. */
.app-ai-msg-ai {
  align-self: flex-start;
  max-width: 100%;
  width: 100%;
  background: var(--ds-body-bg);
}

/* Rodapé da bolha da IA: ações (copiar) discretas, aparecem na bolha. */
.app-ai-msg-actions {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--ds-space-1);
}

/* Cursor de digitação enquanto streama. */
.app-ai-typing::after {
  content: "▍";
  animation: ai-blink 1s step-end infinite;
}

@keyframes ai-blink {
  50% {
    opacity: 0;
  }
}

/* --- 7.4 Markdown renderizado (saída da IA) --------------------------------- */
.app-ai-md > :first-child {
  margin-top: 0;
}

.app-ai-md > :last-child {
  margin-bottom: 0;
}

.app-ai-md p,
.app-ai-md ul,
.app-ai-md ol {
  margin-bottom: var(--ds-space-2);
}

.app-ai-md ul,
.app-ai-md ol {
  padding-inline-start: var(--ds-space-5);
}

.app-ai-md code {
  font-size: 0.85em;
  padding: 0.1em 0.35em;
  background: color-mix(in srgb, var(--ds-text) 8%, transparent);
}

.app-ai-md pre {
  padding: var(--ds-space-3);
  overflow-x: auto;
  background: color-mix(in srgb, var(--ds-text) 8%, transparent);
}

.app-ai-md pre code {
  padding: 0;
  background: none;
}

.app-ai-md table {
  width: 100%;
  margin-bottom: var(--ds-space-2);
  border-collapse: collapse;
}

.app-ai-md th,
.app-ai-md td {
  padding: var(--ds-space-1) var(--ds-space-2);
  border: 1px solid var(--ds-border);
  text-align: left;
}

/* --- 7.5 Composer (campo de escrita fixo no rodapé) ------------------------- */
.app-ai-composer {
  flex: 0 0 auto;
  padding: var(--ds-space-3) var(--ds-space-4);
  border-top: 1px solid var(--ds-border);
  background: var(--ds-surface);
}

.app-ai-composer textarea {
  resize: none;
  max-height: 140px;
}

.app-ai-hint {
  margin: var(--ds-space-1) 0 0;
  font-size: 11px;
  color: var(--ds-text-muted);
}

/* =============================================================================
   8. ALTERNADOR DE TEMA  (DESIGN.md §2)
   -----------------------------------------------------------------------------
   Ícone único: Tabler circle-half-2 (círculo meio-sombreado), girado 180° e
   recolorido conforme o data-bs-theme do <html> — o lado sombreado/cor sinaliza
   o tema atual, sem trocar de ícone. Usado no menu do avatar (#theme_toggle) e no
   controle fixo do topo (#theme_btn_top).
============================================================================= */
.ic-theme {
  transform: rotate(180deg);
  color: var(--ds-text-muted); /* tema claro */
}
[data-bs-theme="dark"] .ic-theme {
  color: var(--ds-warn); /* tema escuro (âmbar) */
}

/* Controle fixo do olho (topo-direito): alterna olho/olho-cortado por
   body.values-hidden. Troca por CSS. */
.ds-iconbtn .ic-eye-off {
  display: none;
}
body.values-hidden .ds-iconbtn .ic-eye {
  display: none;
}
body.values-hidden .ds-iconbtn .ic-eye-off {
  display: block;
}

/* =============================================================================
   9. DRAWER (COMPONENTE)  (docs/drawer-component.md; DESIGN.md §Drawer)
   -----------------------------------------------------------------------------
   Camada comum do componente único de drawer (macro components/drawer.html +
   classe window.Drawer). Edge-to-edge, sem border-radius (já zerado em §1.1),
   com separação de 1px no lado de encosto. Larguras por `size` em tokens FIXOS
   (§1.6.1); `width` explícito sobrepõe via a var inline `--ds-drawer-size`.

   Tudo via tokens (--ds-surface / --ds-border / --tblr-*), que JÁ trocam no
   tema escuro (:root[data-bs-theme=dark]) — ZERO cor hardcoded. O drawer NÃO
   fixa data-bs-theme: herda o do <html>. O realce 2px primário é exclusivo do
   perfil IA (.app-ai-drawer, §7), não do drawer base.
============================================================================= */
.drawer {
  background: var(--ds-surface);
  --drawer-w: var(--ds-drawer-w-md); /* default; trocado pela classe de size */
}

.drawer.drawer-sm {
  --drawer-w: var(--ds-drawer-w-sm);
}
.drawer.drawer-lg {
  --drawer-w: var(--ds-drawer-w-lg);
}
.drawer.drawer-xl {
  --drawer-w: var(--ds-drawer-w-xl);
}

/* end/start → largura; top/bottom → altura. `--ds-drawer-size` (inline, via
   param `width`) sobrepõe o token do size quando presente. */
.drawer.offcanvas-end,
.drawer.offcanvas-start {
  width: var(--ds-drawer-size, var(--drawer-w));
}

.drawer.offcanvas-top,
.drawer.offcanvas-bottom {
  height: var(--ds-drawer-size, var(--drawer-w));
}

/* Separação por 1px no lado de encosto (edge-to-edge, sem raio). */
.drawer.offcanvas-end {
  border-left: 1px solid var(--ds-border);
}
.drawer.offcanvas-start {
  border-right: 1px solid var(--ds-border);
}
.drawer.offcanvas-top {
  border-bottom: 1px solid var(--ds-border);
}
.drawer.offcanvas-bottom {
  border-top: 1px solid var(--ds-border);
}

/* Header padrão: título + descrição à esquerda, btn-close à direita. */
.drawer-header {
  align-items: flex-start;
  gap: var(--ds-space-3);
}

.drawer-description {
  font-size: 0.875rem;
}

/* Rodapé opcional (ações): encostado embaixo, borda superior, fora da rolagem. */
.drawer-footer {
  flex: 0 0 auto;
  display: flex;
  gap: var(--ds-space-2);
  padding: var(--ds-space-3) var(--ds-space-4);
  border-top: 1px solid var(--ds-border);
  background: var(--ds-surface);
}

/* scrollable=false: corpo não rola (conteúdo curto/auto-contido). */
.drawer.drawer--body-noscroll .offcanvas-body {
  overflow: hidden;
}

/* --- 9.1 Responsividade (DESIGN.md §Drawer; breakpoints 575.98 / 767.98) ----
   <576px: full-screen (100vw em end/start; 100vh em top/bottom). Forms cobrem a
   topbar (offcanvas padrão); a ancoragem abaixo da topbar é exclusiva do perfil
   IA. 576–767.98px: largura do size LIMITADA à viewport (ainda não full). */
@media (max-width: 575.98px) {
  .drawer.offcanvas-end,
  .drawer.offcanvas-start {
    width: 100vw;
  }
  .drawer.offcanvas-top,
  .drawer.offcanvas-bottom {
    height: 100vh;
  }
}

@media (min-width: 576px) and (max-width: 767.98px) {
  .drawer.offcanvas-end,
  .drawer.offcanvas-start {
    width: min(var(--ds-drawer-size, var(--drawer-w)), 100vw);
  }
}

/* =============================================================================
   10. WIZARD (COMPONENTE)  (docs/onboarding-wizard.md)
   -----------------------------------------------------------------------------
   Stepper sobre bootstrap.Modal. Macro components/wizard.html + window.Wizard.
   Passos alternam via .is-hidden (§5.1). Tudo por tokens — herda tema do <html>.
============================================================================= */
.wizard .modal-content {
  background: var(--ds-surface);
}

.wizard-header {
  align-items: baseline;
}
.wizard-counter {
  font-size: 12px;
  color: var(--ds-text-muted);
}

/* Barra de progresso (genérica o suficiente para reuso). */
.wizard-progress {
  height: 4px;
  background: color-mix(in srgb, var(--ds-text) 8%, transparent);
}
.wizard-progress-bar {
  height: 100%;
  width: 0;
  background: var(--tblr-primary);
  transition: width 0.25s ease;
}

/* Cada passo ocupa o corpo; só um visível (o resto recebe .is-hidden via JS). */
.wizard-step {
  display: block;
}

/* Nav: skip à esquerda (margin-right:auto), voltar/continuar à direita. */
.wizard-nav {
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
}
.wizard-nav .wizard-skip {
  margin-right: auto;
  padding-inline: 0;
}

/* Linha de item adicionável (entrada/despesa): grid responsivo. */
.wizard-row {
  display: grid;
  grid-template-columns: 2fr 1.2fr 0.9fr;
  gap: var(--ds-space-2);
  align-items: center;
  padding: var(--ds-space-2);
  border: 1px solid var(--ds-border);
  margin-bottom: var(--ds-space-2);
}
.wizard-row.wizard-row--installment {
  grid-template-columns: 2fr 1.2fr 0.9fr 0.9fr;
}

/* =============================================================================
   11. CHIPS  (componente reutilizável — window.Chipset)
   -----------------------------------------------------------------------------
   Grupo de seleção single/multi. Visual aqui; comportamento no chipset.js.
   Reaproveitável fora do wizard (filtros, tags, segmented controls).
============================================================================= */
.ds-chipset {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ds-space-2);
}
.ds-chipset--grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(92px, 1fr));
}

.ds-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 5px 12px;
  font-size: 13px;
  cursor: pointer;
  color: var(--ds-text);
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
}
.ds-chip:hover {
  border-color: color-mix(in srgb, var(--ds-text) 30%, var(--ds-border));
}
.ds-chip--dashed {
  border-style: dashed;
  color: var(--ds-text-muted);
}

.ds-chip.is-selected {
  color: var(--tblr-primary);
  border-color: var(--tblr-primary);
  background: color-mix(in srgb, var(--tblr-primary) 10%, var(--ds-surface));
}

/* ds-tag — rótulo estático, discreto e NÃO interativo (ao contrário de .ds-chip).
   Usado como discriminador ao lado do nome (ex.: conta "Banco do Brasil" + tag
   "Poupança 51"). Secundário: menor e mais apagado que o texto ao lado. */
.ds-tag {
  display: inline-flex;
  align-items: center;
  padding: 1px 7px;
  font-size: 11px;
  font-weight: 500;
  line-height: 1.5;
  white-space: nowrap;
  color: var(--ds-text-muted);
  background: color-mix(in srgb, var(--ds-text) 6%, var(--ds-surface));
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-xs);
}

/* =============================================================================
   ds-due-badge — alertas de vencimento (E7)
   -----------------------------------------------------------------------------
   Badge semântico de proximidade/atraso de vencimento, reusado em Transações,
   Faturas e Painel. Sem `style=` inline nos templates. Cores derivadas das
   variáveis do Tabler (que já trocam no tema escuro) e o fundo é um tint via
   color-mix sobre a superfície — legível em claro e escuro, como `.ds-chip`.
   ============================================================================= */
.ds-due-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.4;
  white-space: nowrap;
  border: 1px solid transparent;
  border-radius: var(--ds-radius-xs);
  color: var(--ds-due-fg, var(--ds-text));
  background: color-mix(in srgb, var(--ds-due-fg, var(--ds-text)) 12%, var(--ds-surface));
  border-color: color-mix(in srgb, var(--ds-due-fg, var(--ds-text)) 30%, transparent);
}
.ds-due-badge::before {
  content: "";
  width: 6px;
  height: 6px;
  flex: 0 0 auto;
  background: currentColor;
}
.ds-due-badge--overdue {
  --ds-due-fg: var(--tblr-red);
}
.ds-due-badge--today {
  --ds-due-fg: var(--tblr-orange);
}
.ds-due-badge--soon {
  --ds-due-fg: var(--tblr-blue);
}
.ds-due-badge--scheduled {
  --ds-due-fg: var(--ds-text-muted);
}

/* =============================================================================
   Toggle de privacidade (ocultar valores) — ícone olho/olho-cortado na topbar.
   Por padrão mostra o "olho" (valores visíveis); com body.values-hidden, troca.
============================================================================= */
.values-icon-hide {
  display: none;
}
body.values-hidden .values-icon-show {
  display: none;
}
body.values-hidden .values-icon-hide {
  display: inline-block;
}

/* =============================================================================
   BADGES DE TIPO DE TITULAR (PF / PJ / Fazenda)
   Famílias de cor próprias (§2.4 do DESIGN): nunca confundir com money/accent.
   Fundo translúcido + texto na cor cheia (espelha o preview v4). Os tokens
   --ds-holder-* trocam sozinhos no tema escuro.
============================================================================= */
.badge-pf {
  background: color-mix(in srgb, var(--ds-holder-pf) 16%, transparent);
  color: var(--ds-holder-pf);
}
.badge-pj {
  background: color-mix(in srgb, var(--ds-holder-pj) 16%, transparent);
  color: var(--ds-holder-pj);
}

/* =============================================================================
   ds-filterbar — Barra de filtros unificada (DESIGN item 18)
   -----------------------------------------------------------------------------
   Componente responsivo: entidade (segmentado) · busca · botão de filtros
   avançados. Funciona em mobile e desktop com o mesmo HTML; as abas de meses
   (.ds-tabs) ficam como componente irmão, separadas.
============================================================================= */
.ds-filterbar {
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
  min-width: 0;
}

/* Segmentado Tudo / PJ / PF */
.ds-filterbar__seg {
  display: inline-flex;
  flex: 0 0 auto;
  border: 1px solid var(--ds-border-strong);
  border-radius: var(--ds-radius-xs);
  overflow: hidden;
}
.ds-filterbar__seg button {
  border: none;
  border-left: 1px solid var(--ds-border);
  background: var(--ds-surface);
  color: var(--ds-text-muted);
  padding: 0 var(--ds-space-3);
  height: var(--ds-btn-h);
  font: inherit;
  font-size: var(--ds-fs-sm);
  cursor: pointer;
  transition:
    background var(--ds-motion-fast) var(--ds-ease),
    color var(--ds-motion-fast) var(--ds-ease);
}
.ds-filterbar__seg button:first-child {
  border-left: none;
}
.ds-filterbar__seg button[aria-pressed="true"] {
  background: var(--ds-accent);
  color: var(--ds-on-accent);
}

/* Input group: busca + botão de filtros numa borda única (input-group pattern) */
.ds-filterbar__group {
  position: relative;
  display: flex; /* flex (não inline-flex) — mais previsível como flex item */
  align-items: stretch; /* filhos ocupam a altura completa do grupo */
  flex: 1 1 auto;
  min-width: var(--ds-col-search);
  height: var(--ds-btn-h);
  border: 1px solid var(--ds-border-strong);
  border-radius: var(--ds-radius-xs);
  background: var(--ds-surface);
  overflow: hidden; /* garante que nada vaze fora do border-radius */
  transition:
    border-color var(--ds-motion-fast) var(--ds-ease),
    box-shadow var(--ds-motion-fast) var(--ds-ease);
}
.ds-filterbar__group:focus-within {
  border-color: var(--ds-accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ds-accent) 18%, transparent);
}
.ds-filterbar__group > svg {
  position: absolute;
  left: var(--ds-space-2);
  top: 50%;
  transform: translateY(-50%);
  width: 15px;
  height: 15px;
  color: var(--ds-text-faint);
  pointer-events: none;
  flex-shrink: 0;
  z-index: 1;
}

/* Input dentro do grupo — especificidade alta para vencer Tabler/Bootstrap */
.ds-filterbar__group .ds-filterbar__input {
  flex: 1 1 auto;
  width: 0;
  height: 100%;
  padding: 0 var(--ds-space-2) 0 28px;
  border: none !important;
  border-radius: 0 !important;
  background: transparent !important;
  box-shadow: none !important;
  color: var(--ds-text);
  font: inherit;
  font-size: var(--ds-fs-sm);
  outline: none;
}
.ds-filterbar__group .ds-filterbar__input::placeholder {
  color: var(--ds-text-faint);
}
.ds-filterbar__group .ds-filterbar__input:focus {
  border: none !important;
  box-shadow: none !important;
  outline: none !important;
}

/* Botão de filtros avançados — integrado, estica para preencher a altura do grupo */
.ds-filterbar__more {
  position: relative;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--ds-btn-h);
  height: 100%; /* preenche o grupo — divisor cobre toda a altura */
  background: transparent;
  border: none !important;
  border-left: 1px solid var(--ds-border) !important;
  border-radius: 0 !important;
  color: var(--ds-text-muted);
  cursor: pointer;
  transition:
    background var(--ds-motion-fast) var(--ds-ease),
    color var(--ds-motion-fast) var(--ds-ease);
}
.ds-filterbar__more:hover {
  background: var(--ds-surface-2);
  color: var(--ds-text);
}
.ds-filterbar__more.is-active {
  background: color-mix(in srgb, var(--ds-accent) 12%, transparent);
  border-left-color: var(--ds-accent) !important;
  color: var(--ds-accent);
}
.ds-filterbar__more svg {
  width: 15px;
  height: 15px;
}

/* Badge de filtros ativos */
.ds-filterbar__badge {
  position: absolute;
  top: -4px;
  right: -4px;
  font-size: 9px;
  font-weight: var(--ds-fw-medium);
  color: var(--ds-on-accent);
  background: var(--ds-accent);
  border-radius: var(--ds-radius-pill);
  min-width: 15px;
  height: 15px;
  padding: 0 3px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}
.ds-filterbar__badge[hidden] {
  display: none;
}

/* Atalho de teclado dentro do input (⌘K) — oculto quando em foco ou com valor */
.ds-filterbar__shortcut {
  flex: 0 0 auto;
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: 2px;
  margin-right: 4px;
  pointer-events: none;
  user-select: none;
  transition: opacity var(--ds-motion) var(--ds-ease);
}
.ds-filterbar__shortcut kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 16px;
  height: 16px;
  padding: 0 3px;
  border: 1px solid var(--ds-border);
  border-radius: 3px;
  background: var(--ds-surface-2);
  color: var(--ds-text-faint);
  font: 500 10px/1 var(--ds-font-num, monospace);
  letter-spacing: 0;
  box-shadow: 0 1px 0 var(--ds-border);
}
.ds-filterbar__group:focus-within .ds-filterbar__shortcut,
.ds-filterbar__group.has-value .ds-filterbar__shortcut {
  opacity: 0;
}

/* Retrocompatibilidade: __search sem __group (mobile-tx.js pode renderizar sem o wrapper) */
.ds-filterbar__search {
  position: relative;
  display: inline-flex;
  align-items: center;
  flex: 1 1 auto;
  min-width: 0;
}
.ds-filterbar__search svg {
  position: absolute;
  left: var(--ds-space-2);
  width: 15px;
  height: 15px;
  color: var(--ds-text-faint);
  pointer-events: none;
  flex-shrink: 0;
}

/* ds-active-filters — chips de filtros ativos, inline abaixo do filterbar */
.ds-active-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ds-space-1);
  min-height: 0;
}
.ds-active-filters[hidden] {
  display: none;
}
.ds-active-filter {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 24px;
  padding: 0 8px 0 10px;
  background: color-mix(in srgb, var(--ds-accent) 10%, var(--ds-surface));
  border: 1px solid color-mix(in srgb, var(--ds-accent) 30%, var(--ds-border));
  border-radius: var(--ds-radius-pill);
  color: var(--ds-accent);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
  transition: background var(--ds-motion-fast) var(--ds-ease);
  white-space: nowrap;
}
.ds-active-filter:hover {
  background: color-mix(in srgb, var(--ds-accent) 18%, var(--ds-surface));
}
.ds-active-filter svg {
  width: 11px;
  height: 11px;
  flex-shrink: 0;
  opacity: 0.7;
}

/* =============================================================================
   ds-filter-sheet — Bottom-sheet de filtros avançados (universal)
   -----------------------------------------------------------------------------
   Antes limitado a <768px em mobile-tx.css. Agora funciona em qualquer
   breakpoint: slide-up do bottom com max-width em desktop.
============================================================================= */
.ds-filter-backdrop {
  position: fixed;
  inset: 0;
  background: var(--ds-backdrop);
  z-index: var(--ds-z-drawer);
  display: none;
}
.ds-filter-backdrop.is-open {
  display: block;
}
.ds-filter-sheet {
  position: fixed;
  left: 50%;
  transform: translateX(-50%) translateY(100%);
  bottom: 0;
  width: 100%;
  max-width: 480px;
  background: var(--ds-surface);
  z-index: calc(var(--ds-z-drawer) + 1);
  border: 1px solid var(--ds-border);
  border-bottom: none;
  border-radius: var(--ds-radius-md) var(--ds-radius-md) 0 0;
  padding: 18px 16px calc(28px + env(safe-area-inset-bottom, 0px));
  transition: transform var(--ds-motion) var(--ds-ease);
  box-shadow: var(--ds-shadow-3);
}
.ds-filter-sheet.is-open {
  transform: translateX(-50%) translateY(0);
}
.ds-filter-sheet__grip {
  width: 38px;
  height: 4px;
  background: var(--ds-border);
  border-radius: var(--ds-radius-pill);
  margin: 0 auto 14px;
}
.ds-filter-sheet__title {
  font-weight: var(--ds-fw-semibold);
  font-size: var(--ds-fs-md);
  margin-bottom: 14px;
}
.ds-filter-group {
  margin-bottom: 16px;
}
.ds-filter-group__label {
  font-size: var(--ds-fs-xs);
  color: var(--ds-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 8px;
}
.ds-filter-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.ds-filter-chip {
  font-family: var(--ds-font-sans);
  font-size: var(--ds-fs-sm);
  color: var(--ds-text-muted);
  background: var(--ds-body-bg);
  border: 1px solid var(--ds-border);
  padding: 4px 11px;
  border-radius: var(--ds-radius-xs);
  cursor: pointer;
  transition:
    background var(--ds-motion-fast) var(--ds-ease),
    border-color var(--ds-motion-fast) var(--ds-ease),
    color var(--ds-motion-fast) var(--ds-ease);
}
.ds-filter-chip[aria-pressed="true"] {
  color: var(--ds-on-accent);
  background: var(--ds-accent);
  border-color: var(--ds-accent);
}
.ds-filter-sheet__apply {
  width: 100%;
  margin-top: 8px;
  background: var(--ds-accent);
  color: var(--ds-on-accent);
  border: none;
  font: inherit;
  font-weight: var(--ds-fw-medium);
  font-size: var(--ds-fs-md);
  padding: 10px;
  border-radius: var(--ds-radius-xs);
  cursor: pointer;
  transition: background var(--ds-motion-fast) var(--ds-ease);
}
.ds-filter-sheet__apply:hover {
  background: var(--ds-accent-strong);
}

/* Desktop/tablet (≥768px): dropdown panel ancorado abaixo do botão de filtro.
   Posição (top/left) definida por CSS vars injetadas pelo JS ao abrir. */
@media (min-width: 768px) {
  .ds-filter-backdrop {
    background: transparent; /* sem escurecimento; clique ainda fecha */
    /* backdrop desktop: sem escurecimento e abaixo dos controles fixos */
    z-index: calc(var(--ds-z-dropdown) - 1);
  }
  .ds-filter-sheet {
    /* override bottom-sheet → dropdown */
    bottom: auto;
    left: var(--ds-filter-sheet-x, auto);
    top: var(--ds-filter-sheet-y, 80px);
    transform: translateY(-6px);
    opacity: 0;
    pointer-events: none;
    max-width: 320px;
    width: 320px;
    border-radius: var(--ds-radius-md);
    border-bottom: 1px solid var(--ds-border); /* fecha a borda inferior */
    padding: 16px;
    max-height: calc(100vh - 120px);
    overflow-y: auto;
    transition:
      transform var(--ds-motion) var(--ds-ease),
      opacity var(--ds-motion) var(--ds-ease);
    z-index: var(--ds-z-dropdown); /* 1040 — abaixo do FAB (1045) e do topright (1055) */
  }
  .ds-filter-sheet.is-open {
    transform: translateY(0);
    opacity: 1;
    pointer-events: auto;
  }
  .ds-filter-sheet__grip {
    display: none;
  }
  .ds-filter-sheet__apply {
    margin-top: 4px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ds-filter-sheet {
    transition: none;
  }
}
.badge-fazenda {
  background: color-mix(in srgb, var(--ds-holder-fazenda) 16%, transparent);
  color: var(--ds-holder-fazenda);
}

/* =============================================================================
   mtx-panels — wrapper para painéis partilhados (insight + resumo)
   Visível em mobile e desktop; o .mtx-screen usa este mesmo elemento fora do
   breakpoint de tela, logo as dimensões aqui controlam o espaço em desktop.
============================================================================= */
.mtx-panels {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 16px;
}
@media (min-width: 768px) {
  .mtx-panels {
    gap: 12px;
    margin-bottom: 20px;
  }
}

/* =============================================================================
   AUTH — tela de entrada (login/registro/recuperação) sem shell (DESIGN §14.1)
   Card centralizado premium sobre o body-bg, com a marca real no topo, brilho
   sutil do gradiente de IA no fundo e tema claro/escuro (data-bs-theme).
============================================================================= */
.ds-auth {
  min-height: 100vh; /* fallback p/ WebView antigo (iOS < 15.4) sem dvh */
  min-height: 100dvh;
  margin: 0;
  background: var(--ds-body-bg);
  color: var(--ds-text);
  font-family: var(--ds-font-sans);
  letter-spacing: var(--ds-letter-spacing);
}

/* Brilho de marca: respiro do gradiente de IA no canto superior, contido (≤8%
   claro / ≤16% escuro), igual à doutrina do main autenticado. */
.ds-auth-glow {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(
      60% 50% at 78% 8%,
      color-mix(in srgb, #7c5cfb 8%, transparent),
      transparent 70%
    ),
    radial-gradient(
      50% 40% at 12% 92%,
      color-mix(in srgb, #3b5bdb 6%, transparent),
      transparent 70%
    );
}
:root[data-bs-theme="dark"] .ds-auth-glow {
  background:
    radial-gradient(
      60% 50% at 78% 8%,
      color-mix(in srgb, #7c5cfb 16%, transparent),
      transparent 70%
    ),
    radial-gradient(
      50% 40% at 12% 92%,
      color-mix(in srgb, #3b5bdb 12%, transparent),
      transparent 70%
    );
}

.ds-auth-stage {
  position: relative;
  z-index: 1;
  min-height: 100vh; /* fallback p/ WebView antigo sem dvh */
  min-height: 100dvh;
  display: grid;
  justify-items: center;
  /* `safe center` centraliza, mas cai para o topo quando o conteúdo é maior que
     a viewport (ex.: teclado aberto) — assim a marca/campo nunca ficam cortados
     e inalcançáveis. Em WebView antigo o `safe` é ignorado (vira center). */
  align-content: safe center;
  /* Respeita o notch/recortes em todos os lados (depende do viewport-fit=cover). */
  padding: calc(var(--ds-space-6) + env(safe-area-inset-top, 0px))
    calc(var(--ds-space-4) + env(safe-area-inset-right, 0px))
    calc(var(--ds-space-6) + env(safe-area-inset-bottom, 0px))
    calc(var(--ds-space-4) + env(safe-area-inset-left, 0px));
}
.ds-auth-shell {
  width: 100%;
  max-width: 360px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--ds-space-5);
}

/* Marca: glifo real (favicon) com halo sutil + wordmark. */
.ds-auth-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--ds-space-3);
  text-decoration: none;
  color: var(--ds-text);
}
.ds-auth-mark {
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  border-radius: var(--ds-radius-md);
  box-shadow: var(--ds-shadow-2);
}
.ds-auth-mark img {
  width: 48px;
  height: 48px;
  display: block;
}
.ds-auth-wordmark {
  font-size: var(--ds-fs-xl);
  font-weight: var(--ds-fw-semibold);
  letter-spacing: -0.02em;
}

/* Card de entrada — raio lg, elevação e2. */
.ds-auth-card {
  width: 100%;
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-lg);
  box-shadow: var(--ds-shadow-2);
  padding: var(--ds-space-6);
}
.ds-auth-head {
  margin-bottom: var(--ds-space-5);
  text-align: center;
}
.ds-auth-title {
  margin: 0 0 var(--ds-space-1);
  font-size: var(--ds-fs-display);
  font-weight: var(--ds-fw-semibold);
  letter-spacing: -0.02em;
  line-height: var(--ds-lh-tight);
}
.ds-auth-sub {
  margin: 0;
  color: var(--ds-text-muted);
  font-size: var(--ds-fs-sm);
}

.ds-auth-alert {
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
  margin-bottom: var(--ds-space-4);
}
.ds-auth-alert svg {
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
}

/* "Manter conectado" — checkbox alinhado, alvo de clique confortável. */
.ds-auth-remember {
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
  margin: var(--ds-space-3) 0 var(--ds-space-5);
  font-size: var(--ds-fs-sm);
  color: var(--ds-text-muted);
  cursor: pointer;
  user-select: none;
}
.ds-auth-remember .form-check-input {
  margin: 0;
  cursor: pointer;
}

.ds-auth-cta {
  width: 100%;
}

.ds-auth-foot {
  margin: 0;
  text-align: center;
  font-size: var(--ds-fs-sm);
  color: var(--ds-text-muted);
}

/* Posiciona o controle de tema também sem shell (o seletor base do .ds-topright
   já fixa no canto superior direito; aqui só garante presença sem o app shell). */
.ds-auth .ds-topright {
  position: fixed;
}
/* Alvo de toque do toggle de tema no login: 44×44 (recomendação mobile), só
   aqui — não mexe no .ds-iconbtn denso do shell autenticado. O ícone segue 20px,
   centralizado pela área maior. */
.ds-auth .ds-topright .ds-iconbtn {
  width: 44px;
  height: 44px;
}
/* Inputs do auth com >=16px: abaixo disso o iOS/WKWebView dá zoom ao focar o
   campo. O login não é denso, então 16px não conflita com o ritmo do app. */
.ds-auth .form-control {
  font-size: 16px;
}

/* Botão "Entrar com Google" — superfície neutra com a marca colorida do Google. */
.ds-auth-google {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--ds-space-2);
  width: 100%;
  min-height: 44px;
  background: var(--ds-surface);
  color: var(--ds-text);
  border: 1px solid var(--ds-border-strong);
  border-radius: var(--ds-radius-xs);
  font-size: var(--ds-fs-md);
  font-weight: var(--ds-fw-medium);
  text-decoration: none;
  transition:
    background var(--ds-motion-fast) var(--ds-ease),
    border-color var(--ds-motion-fast) var(--ds-ease);
}
.ds-auth-google:hover {
  background: var(--ds-surface-2);
  border-color: var(--ds-text-faint);
}
.ds-auth-google svg {
  flex: 0 0 18px;
}

/* Divisor "ou" entre o login social e o formulário de e-mail/senha. */
.ds-auth-divider {
  display: flex;
  align-items: center;
  gap: var(--ds-space-3);
  margin: var(--ds-space-4) 0;
  color: var(--ds-text-faint);
  font-size: var(--ds-fs-sm);
}
.ds-auth-divider::before,
.ds-auth-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--ds-border);
}

/* =============================================================================
   MÓDULO PROJETOS — fundação de DS (issue #234; spec §19.3-A). Portado do mock
   docs/preview/design-system-v4.html. Tokens-first, theme-aware, reutilizável.
   Componentes de board/roadmap/dataviz entram em #235/#236/#237.
   ========================================================================== */

/* --- .ds-card: primitivo de superfície (base de tiles, cartões, painéis) ---- */
.ds-card {
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-md);
  padding: var(--ds-space-4);
  box-shadow: var(--ds-shadow-1);
}
.ds-card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ds-space-3);
  margin-bottom: var(--ds-space-3);
}
.ds-card__title {
  font-size: var(--ds-fs-sm);
  font-weight: var(--ds-fw-semibold);
}
.ds-card__foot {
  margin-top: var(--ds-space-3);
  display: flex;
  gap: var(--ds-space-2);
}

/* --- .ds-badge: prioridade + tipo (dot + rótulo — daltônico-safe) ----------- */
.ds-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--ds-fs-xs);
  font-weight: var(--ds-fw-medium);
  line-height: 1.7;
  padding: 0 8px;
  border-radius: var(--ds-radius-pill);
  border: 1px solid transparent;
  white-space: nowrap;
}
.ds-badge__dot {
  width: 6px;
  height: 6px;
  border-radius: var(--ds-radius-round);
  flex: 0 0 6px;
}
.ds-badge--prio-low {
  color: var(--ds-prio-low);
  background: color-mix(in srgb, var(--ds-prio-low) 14%, transparent);
}
.ds-badge--prio-medium {
  color: var(--ds-prio-medium);
  background: color-mix(in srgb, var(--ds-prio-medium) 14%, transparent);
}
.ds-badge--prio-high {
  color: var(--ds-prio-high);
  background: color-mix(in srgb, var(--ds-prio-high) 16%, transparent);
}
.ds-badge--prio-urgent {
  color: var(--ds-prio-urgent);
  background: color-mix(in srgb, var(--ds-prio-urgent) 15%, transparent);
}
.ds-badge--prio-low .ds-badge__dot {
  background: var(--ds-prio-low);
}
.ds-badge--prio-medium .ds-badge__dot {
  background: var(--ds-prio-medium);
}
.ds-badge--prio-high .ds-badge__dot {
  background: var(--ds-prio-high);
}
.ds-badge--prio-urgent .ds-badge__dot {
  background: var(--ds-prio-urgent);
}
.ds-badge--type-epic {
  color: var(--ds-type-epic);
  border-color: color-mix(in srgb, var(--ds-type-epic) 42%, transparent);
  background: color-mix(in srgb, var(--ds-type-epic) 9%, transparent);
}
.ds-badge--type-story {
  color: var(--ds-type-story);
  border-color: color-mix(in srgb, var(--ds-type-story) 42%, transparent);
  background: color-mix(in srgb, var(--ds-type-story) 9%, transparent);
}
.ds-badge--type-task {
  color: var(--ds-type-task);
  border-color: color-mix(in srgb, var(--ds-type-task) 42%, transparent);
  background: color-mix(in srgb, var(--ds-type-task) 9%, transparent);
}
.ds-badge--type-bug {
  color: var(--ds-type-bug);
  border-color: color-mix(in srgb, var(--ds-type-bug) 42%, transparent);
  background: color-mix(in srgb, var(--ds-type-bug) 9%, transparent);
}
.ds-badge--type-spike {
  color: var(--ds-type-spike);
  border-color: color-mix(in srgb, var(--ds-type-spike) 42%, transparent);
  background: color-mix(in srgb, var(--ds-type-spike) 9%, transparent);
}

/* --- .ds-meter: progresso / capacidade / WIP (substitui progress-bar Tabler) - */
.ds-meter {
  position: relative;
  height: 6px;
  background: var(--ds-surface-2);
  border-radius: var(--ds-radius-pill);
  overflow: hidden;
}
.ds-meter--lg {
  height: 8px;
}
.ds-meter__fill {
  position: absolute;
  inset: 0 auto 0 0;
  height: 100%;
  background: var(--ds-accent);
  border-radius: inherit;
  transition: width var(--ds-motion) var(--ds-ease);
}
.ds-meter.is-over .ds-meter__fill {
  background: var(--ds-wip-over);
}

/* --- .ds-avatar-stack: múltiplos responsáveis -------------------------------- */
.ds-avatar-stack {
  display: inline-flex;
  align-items: center;
}
.ds-avatar-stack .ds-avatar {
  width: 24px;
  height: 24px;
  font-size: 11px;
  border: 2px solid var(--ds-surface);
  margin-left: -7px;
}
.ds-avatar-stack .ds-avatar:first-child {
  margin-left: 0;
}
.ds-avatar-stack__more {
  width: 24px;
  height: 24px;
  border-radius: var(--ds-radius-round);
  background: var(--ds-surface-2);
  color: var(--ds-text-muted);
  border: 2px solid var(--ds-surface);
  display: grid;
  place-items: center;
  font-size: 10px;
  font-weight: var(--ds-fw-semibold);
  margin-left: -7px;
}

@media (prefers-reduced-motion: reduce) {
  .ds-meter__fill {
    transition: none;
  }
}

/* =============================================================================
   MÓDULO PROJETOS — Board Kanban (issue #235; spec §19.3-B). Portado do mock.
   DnD via SortableJS (static/vendor/sortablejs) + fallback de teclado (board.js).
   ========================================================================== */

/* --- selo GitHub no cartão (estado de sync) --------------------------------- */
.ds-gh-seal {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--ds-fs-xs);
  color: var(--ds-text-muted);
  font-variant-numeric: tabular-nums;
}
.ds-gh-seal svg {
  width: 13px;
  height: 13px;
}
.ds-gh-seal.is-synced {
  color: var(--ds-chart-3);
}
.ds-gh-seal.is-conflict {
  color: var(--ds-warn);
}
.ds-gh-seal.is-pending {
  color: var(--ds-text-faint);
}

/* --- cartão de work item (board + backlog) — borda esquerda = prioridade ----- */
.ds-item-card {
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-left: 2px solid var(--ds-border-strong);
  border-radius: var(--ds-radius-sm);
  padding: 9px 10px;
  box-shadow: var(--ds-shadow-1);
  cursor: grab;
  transition:
    border-color var(--ds-motion-fast) var(--ds-ease),
    box-shadow var(--ds-motion-fast) var(--ds-ease),
    opacity var(--ds-motion-fast) var(--ds-ease);
}
.ds-item-card:hover {
  border-color: var(--ds-border-strong);
  box-shadow: var(--ds-shadow-2);
}
.ds-item-card:active {
  cursor: grabbing;
}
.ds-item-card:focus-visible {
  outline: 2px solid var(--ds-accent);
  outline-offset: 2px;
}
.ds-item-card.is-dragging,
.ds-item-card[aria-grabbed="true"] {
  opacity: 0.5;
  box-shadow: var(--ds-shadow-3);
}
.ds-item-card[aria-grabbed="true"] {
  outline: 2px dashed var(--ds-accent);
}
.ds-item-card--low {
  border-left-color: var(--ds-prio-low);
}
.ds-item-card--medium {
  border-left-color: var(--ds-prio-medium);
}
.ds-item-card--high {
  border-left-color: var(--ds-prio-high);
}
.ds-item-card--urgent {
  border-left-color: var(--ds-prio-urgent);
}
.ds-item-card__top {
  display: flex;
  align-items: center;
  gap: 6px;
}
.ds-item-card__key {
  font-size: var(--ds-fs-xs);
  color: var(--ds-text-faint);
  font-variant-numeric: tabular-nums;
}
.ds-item-card__title {
  font-size: var(--ds-fs-sm);
  color: var(--ds-text);
  margin: 4px 0 0;
  line-height: 1.35;
}
.ds-item-card__badges {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
  margin-top: 7px;
}
.ds-item-card__meta {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
}
.ds-item-card__pts {
  font-size: var(--ds-fs-xs);
  color: var(--ds-text-muted);
  font-weight: var(--ds-fw-medium);
}
.ds-item-card__aging {
  margin-left: auto;
  font-size: var(--ds-fs-xs);
  color: var(--ds-text-faint);
  display: inline-flex;
  align-items: center;
  gap: 3px;
}
.ds-item-card__handle {
  color: var(--ds-text-faint);
  display: inline-flex;
  cursor: grab;
}
.ds-item-card__handle svg {
  width: 14px;
  height: 14px;
}

/* --- board Kanban ----------------------------------------------------------- */
.ds-board {
  display: flex;
  gap: var(--ds-space-3);
  overflow-x: auto;
  padding-bottom: var(--ds-space-2);
}
.ds-board__column {
  flex: 0 0 268px;
  display: flex;
  flex-direction: column;
  background: var(--ds-surface-2);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-md);
  max-height: 600px;
}
.ds-board__column.is-over-wip {
  border-color: color-mix(in srgb, var(--ds-wip-over) 50%, transparent);
}
.ds-board__col-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 11px;
  border-bottom: 1px solid var(--ds-border);
}
.ds-board__col-head .name {
  font-size: var(--ds-fs-sm);
  font-weight: var(--ds-fw-semibold);
}
.ds-board__wip {
  margin-left: auto;
  font-size: var(--ds-fs-xs);
  color: var(--ds-text-muted);
  font-variant-numeric: tabular-nums;
  padding: 1px 8px;
  border-radius: var(--ds-radius-pill);
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
}
.ds-board__wip.is-over {
  color: var(--ds-wip-over);
  border-color: color-mix(in srgb, var(--ds-wip-over) 45%, transparent);
  background: color-mix(in srgb, var(--ds-wip-over) 12%, transparent);
  font-weight: var(--ds-fw-semibold);
}
.ds-board__list {
  padding: 9px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow-y: auto;
  min-height: 40px;
}
.ds-board__list.is-drop {
  outline: 2px dashed color-mix(in srgb, var(--ds-accent) 55%, transparent);
  outline-offset: -4px;
  border-radius: var(--ds-radius-sm);
}
.ds-board__lane-head {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--ds-fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ds-text-faint);
  padding: 6px 2px 2px;
}
.ds-board__lane-head .ds-badge {
  text-transform: none;
  letter-spacing: 0;
}
.ds-board__add {
  margin: 0 9px 9px;
  padding: 7px;
  border: 1px dashed var(--ds-border-strong);
  border-radius: var(--ds-radius-sm);
  background: transparent;
  color: var(--ds-text-muted);
  font: inherit;
  font-size: var(--ds-fs-sm);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.ds-board__add:hover {
  background: var(--ds-surface);
  color: var(--ds-text);
}

/* =============================================================================
   MÓDULO PROJETOS — Dataviz (issue #236; spec §19.3-E). Portado do mock.
   Wrapper p/ Chart.js (static/vendor/chartjs) fiado aos tokens --ds-chart-*.
   SVG estático só no styleguide; no app o canvas é Chart.js. Paleta = §19.7.
   ========================================================================== */
.ds-chart {
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-md);
  padding: var(--ds-space-4);
  box-shadow: var(--ds-shadow-1);
}
.ds-chart__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}
.ds-chart__title {
  font-size: var(--ds-fs-sm);
  font-weight: var(--ds-fw-semibold);
}
.ds-chart__legend {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  font-size: var(--ds-fs-xs);
  color: var(--ds-text-muted);
}
.ds-chart__legend .k {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.ds-chart__legend .sw {
  width: 10px;
  height: 10px;
  border-radius: 2px;
  flex: 0 0 10px;
}
.ds-chart__canvas {
  width: 100%;
  overflow-x: auto;
}
.ds-chart__canvas svg {
  display: block;
  width: 100%;
  height: auto;
}
.ds-chart__grid {
  stroke: var(--ds-border);
  stroke-width: 1;
}
.ds-chart__axis {
  fill: var(--ds-text-faint);
  font-size: 9px;
}
.ds-stat {
  background: var(--ds-surface);
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-md);
  padding: var(--ds-space-3) var(--ds-space-4);
  box-shadow: var(--ds-shadow-1);
}
.ds-stat__label {
  font-size: var(--ds-fs-xs);
  color: var(--ds-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.ds-stat__value {
  font-size: var(--ds-fs-display);
  font-weight: var(--ds-fw-semibold);
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
  margin-top: 2px;
}
.ds-stat__delta {
  font-size: var(--ds-fs-xs);
  font-weight: var(--ds-fw-medium);
  margin-top: 3px;
  color: var(--ds-text-muted);
  display: flex;
  align-items: center;
  gap: 5px;
}
.ds-stat__delta.up {
  color: var(--ds-money-in);
}
.ds-stat__delta.down {
  color: var(--ds-money-out);
}
.ds-sparkline {
  display: block;
  width: 64px;
  height: 22px;
}
.ds-palette {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.ds-palette .sw {
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: center;
  font-size: var(--ds-fs-xs);
  color: var(--ds-text-faint);
}
.ds-palette .sw i {
  width: 44px;
  height: 26px;
  border-radius: var(--ds-radius-sm);
  display: block;
}

/* =============================================================================
   MÓDULO PROJETOS — Roadmap/Gantt-lite + timeline (issue #237; spec §19.3-D).
   Portado do mock. FullCalendar free não cobre Gantt → barras/dependências SVG
   autorais. "Concluído" = chart-3 (teal); crítico = --ds-critical; marco = warn.
   ========================================================================== */
.ds-roadmap {
  border: 1px solid var(--ds-border);
  border-radius: var(--ds-radius-md);
  background: var(--ds-surface);
  overflow: hidden;
}
.ds-roadmap__head,
.ds-roadmap__row {
  display: grid;
  grid-template-columns: 180px 1fr;
  align-items: stretch;
}
.ds-roadmap__head {
  border-bottom: 1px solid var(--ds-border);
  background: var(--ds-surface-2);
}
.ds-roadmap__head .corner {
  padding: 8px 12px;
  font-size: var(--ds-fs-xs);
  color: var(--ds-text-faint);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.ds-roadmap__months {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
}
.ds-roadmap__months span {
  padding: 8px 6px;
  font-size: var(--ds-fs-xs);
  color: var(--ds-text-muted);
  border-left: 1px solid var(--ds-border);
  text-align: center;
}
.ds-roadmap__body {
  position: relative;
}
.ds-roadmap__row {
  border-bottom: 1px solid var(--ds-border);
}
.ds-roadmap__row:last-child {
  border-bottom: none;
}
.ds-roadmap__name {
  padding: 0 12px;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--ds-fs-sm);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ds-roadmap__track {
  position: relative;
  height: 40px;
  background-image: repeating-linear-gradient(
    to right,
    transparent,
    transparent calc(100% / 6 - 1px),
    var(--ds-border) calc(100% / 6 - 1px),
    var(--ds-border) calc(100% / 6)
  );
}
.ds-roadmap__bar {
  position: absolute;
  top: 12px;
  height: 16px;
  border-radius: var(--ds-radius-sm);
  background: var(--ds-accent);
  display: flex;
  align-items: center;
  padding: 0 8px;
  color: var(--ds-on-accent);
  font-size: var(--ds-fs-xs);
  white-space: nowrap;
  box-shadow: var(--ds-shadow-1);
}
.ds-roadmap__bar.is-done {
  background: var(--ds-chart-3);
}
.ds-roadmap__bar.is-critical {
  background: var(--ds-critical);
}
.ds-roadmap__dep {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: visible;
}
.ds-roadmap__milestone {
  position: absolute;
  top: 11px;
  width: 16px;
  height: 16px;
  transform: translateX(-8px) rotate(45deg);
  background: var(--ds-warn);
  border: 1px solid color-mix(in srgb, var(--ds-warn) 55%, #000);
}
.ds-roadmap__legend {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  font-size: var(--ds-fs-xs);
  color: var(--ds-text-muted);
  padding: 8px 12px;
  border-top: 1px solid var(--ds-border);
}
.ds-roadmap__legend .k {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.ds-roadmap__legend .sw {
  width: 14px;
  height: 8px;
  border-radius: 2px;
}
.ds-timeline {
  display: flex;
  align-items: flex-start;
  position: relative;
  padding: 22px 0 0;
}
.ds-timeline::before {
  content: "";
  position: absolute;
  top: 27px;
  left: 6%;
  right: 6%;
  height: 2px;
  background: var(--ds-border);
}
.ds-timeline__node {
  flex: 1;
  position: relative;
  text-align: center;
  font-size: var(--ds-fs-xs);
  color: var(--ds-text-muted);
}
.ds-timeline__dot {
  width: 12px;
  height: 12px;
  border-radius: var(--ds-radius-sm);
  background: var(--ds-text-faint);
  margin: 0 auto 7px;
  transform: rotate(45deg);
  border: 2px solid var(--ds-surface);
  position: relative;
  z-index: 1;
  box-shadow: 0 0 0 3px var(--ds-body-bg);
}
.ds-timeline__node.is-reached .ds-timeline__dot {
  background: var(--ds-chart-3);
}
.ds-timeline__node.is-next .ds-timeline__dot {
  background: var(--ds-warn);
}
.ds-timeline__node strong {
  display: block;
  color: var(--ds-text);
  font-weight: var(--ds-fw-medium);
}

/* =============================================================================
   MÓDULO PROJETOS — Board em altura cheia (página do board). Escopado a
   body.has-board / .proj-board para NÃO afetar boards embutidos nem outras telas.
   A página não rola; o board preenche o main e as COLUNAS rolam por dentro.
   ========================================================================== */
body.has-board .page-wrapper {
  height: 100dvh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
body.has-board .page-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
body.has-board .ds-main {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding-block: var(--ds-space-3);
}
.proj-board {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.proj-board .ds-board {
  flex: 1;
  min-height: 0;
  margin: 0;
}
.proj-board .ds-board__column {
  max-height: 100%;
}
.proj-board .ds-board__list {
  flex: 1;
  min-height: 0;
}

/* Celular: uma coluna por vez (largura quase total) + snap horizontal (swipe). */
@media (max-width: 767.98px) {
  body.has-board .ds-main {
    padding-top: var(--ds-space-6);
  } /* clareia o botão de menu flutuante */
  .proj-board .ds-board {
    scroll-snap-type: x mandatory;
    gap: var(--ds-space-2);
  }
  .proj-board .ds-board__column {
    flex: 0 0 86%;
    scroll-snap-align: start;
  }
}

/* ---------------------------------------------------------------------------
   .ds-prose — texto rico renderizado a partir de Markdown (descrições de itens
   de projeto etc.). Escopo restrito: só as tags que markdown_lite emite.
--------------------------------------------------------------------------- */
.ds-prose {
  color: var(--ds-text);
  font-size: var(--ds-fs-md);
  line-height: 1.6;
}
.ds-prose > :first-child {
  margin-top: 0;
}
.ds-prose > :last-child {
  margin-bottom: 0;
}
.ds-prose h2,
.ds-prose h3,
.ds-prose h4,
.ds-prose h5,
.ds-prose h6 {
  margin: var(--ds-space-5) 0 var(--ds-space-2);
  font-weight: 600;
  line-height: 1.3;
  color: var(--ds-text);
}
.ds-prose h2 {
  font-size: var(--ds-fs-lg);
}
.ds-prose h3 {
  font-size: var(--ds-fs-md);
}
.ds-prose h4,
.ds-prose h5,
.ds-prose h6 {
  font-size: var(--ds-fs-sm);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--ds-text-muted);
}
.ds-prose p {
  margin: 0 0 var(--ds-space-3);
}
.ds-prose ul,
.ds-prose ol {
  margin: 0 0 var(--ds-space-3);
  padding-left: var(--ds-space-5);
}
.ds-prose li {
  margin: var(--ds-space-1) 0;
}
.ds-prose li::marker {
  color: var(--ds-text-faint);
}
.ds-prose strong {
  font-weight: 600;
}
.ds-prose em {
  font-style: italic;
}

/* ============================================================
   §DRE — grade multi-período, árvore de linhas, subtotais e impressão
   Fundação de design da DRE (F-DS, spec §4.6.2). Tudo tokenizado; zero inline.
   ============================================================ */

/* Árvore de linhas: indentação por nível no rótulo (1ª célula). O toggle global
   resumida×detalhada reusa tabs; a expansão por linha-pai usa [hidden] nos filhos. */
.ds-table--tree .ds-row--level-0 > :first-child {
  padding-left: var(--ds-space-3);
}
.ds-table--tree .ds-row--level-1 > :first-child {
  padding-left: calc(var(--ds-space-3) + var(--ds-space-4));
}
.ds-table--tree .ds-row--level-2 > :first-child {
  padding-left: calc(var(--ds-space-3) + var(--ds-space-5) + var(--ds-space-3));
  font-weight: 400;
}

/* Subtotais e totais (substitui o fw-semibold+text-danger ad-hoc). */
.ds-row--subtotal > * {
  font-weight: 600;
  background: var(--ds-surface-2);
  border-top: 1px solid var(--ds-border);
}
.ds-row--total > * {
  font-weight: var(--ds-fw-bold);
  border-top: 2px solid var(--ds-border);
  border-bottom: 2px solid var(--ds-border);
}

/* Grade larga (§3.4): scroll horizontal + 1ª coluna (rótulos) congelada — nos dois
   breakpoints. Envolver a tabela em .ds-grid-wrap. */
.ds-grid-wrap {
  overflow-x: auto;
}
.ds-table--grid {
  min-width: max-content;
}
.ds-table--grid th,
.ds-table--grid td {
  text-align: right;
  white-space: nowrap;
}
.ds-table--grid thead th:first-child,
.ds-table--grid tbody th:first-child,
.ds-table--grid tbody td:first-child {
  text-align: left;
}
.ds-table--grid thead th:first-child,
.ds-table--grid tbody th:first-child,
.ds-table--grid tbody td:first-child {
  position: sticky;
  left: 0;
  z-index: 3;
  background: var(--ds-surface);
  border-right: 1px solid var(--ds-border);
}
/* o cabeçalho da coluna de rótulos fica acima do thead sticky (canto). */
.ds-table--grid thead th:first-child {
  z-index: 4;
}

/* Colunas de total (T/S/Ano) realçadas. */
.ds-col--total {
  background: var(--ds-surface-2);
  font-weight: 600;
}

/* AV%/Δ% como texto pequeno na MESMA célula (sinal via .ds-tx-revenue/-expense). */
.ds-cell-note {
  display: block;
  font-size: 10px;
  line-height: 1.2;
  color: var(--ds-text-faint);
  font-variant-numeric: tabular-nums;
}

/* Selo "gerencial" ao pé da DRE / impressão. */
.ds-dre-selo {
  font-size: 11px;
  color: var(--ds-text-faint);
  font-style: italic;
}

/* MOBILE — a grade é uma MATRIZ (linha × período): não pode virar cartão (o
   opt-out .ds-table--scroll já evita o empilhamento; aqui afinamos a leitura).
   O rótulo (1ª coluna, congelada) passa a QUEBRAR em 2 linhas em vez de esticar
   a coluna; números seguem tabulares e sem quebra, com fonte/tokens menores para
   caber mais período por tela. */
@media (max-width: 767.98px) {
  .ds-table--grid th,
  .ds-table--grid td {
    font-size: var(--ds-fs-xs);
    padding: 6px 8px;
  }
  .ds-table--grid thead th:first-child,
  .ds-table--grid tbody th:first-child,
  .ds-table--grid tbody td:first-child {
    white-space: normal;
    min-width: 8.5rem;
    max-width: 8.5rem;
    line-height: var(--ds-lh-tight);
    hyphens: auto;
  }
  /* dá um respiro de rolagem: sombra sutil na borda da coluna congelada. */
  .ds-table--grid tbody th:first-child,
  .ds-table--grid tbody td:first-child {
    box-shadow: 2px 0 0 -1px var(--ds-border);
  }
}

/* Impressão (§4.6.2): esconde o chrome, reseta sticky/sombra, paisagem. O DS não
   tinha NENHUMA regra @media print antes desta fase. */
@media print {
  @page {
    size: landscape;
    margin: 12mm;
  }
  .ds-nav,
  .ds-topright,
  .ds-fab,
  #ai_drawer,
  .app-ai-drawer,
  .ds-print-hide {
    display: none !important;
  }
  body,
  .page-wrapper,
  .ds-main {
    margin: 0 !important;
    padding: 0 !important;
    overflow: visible !important;
    display: block !important;
  }
  /* sticky/sombra viram artefato no papel. */
  .ds-table thead th,
  .ds-table--grid thead th:first-child,
  .ds-table--grid tbody th:first-child,
  .ds-table--grid tbody td:first-child {
    position: static !important;
    box-shadow: none !important;
  }
  .ds-grid-wrap {
    overflow: visible !important;
  }
  /* variante de impressão da grade: 19 colunas não cabem — mostra só rótulo +
     colunas de total (T/S/Ano). Ative com .ds-print-totals na tabela da grade. */
  .ds-table--grid.ds-print-totals thead th:not(.ds-col--total):not(:first-child),
  .ds-table--grid.ds-print-totals tbody td:not(.ds-col--total):not(:first-child) {
    display: none;
  }
}
