/* =========================================================================
   FECHO DE CONTAS — DESIGN SYSTEM · "GAZETA OFICIAL DE CONTAS"
   Camadas: 1) primitivas (--c-*, cores fixas) 2) tokens semânticos (mudam
   com o tema) 3) aliases legados (--ink, --muted, --line, --paper, --rust,
   --amber-tint... — nomes já usados em estilos inline dentro de script.js,
   mantidos de propósito para o JS nunca precisar de saber o nome do tema).

   THESIS: um instrumento de fecho de contas lê-se como um diploma angolano
   — numerado, rigoroso, tipografado com autoridade — nunca "SaaS genérico"
   nem "terminal neon". Recusa tanto o clichê creme+serifa+terracota como o
   clichê escuro+brilho que a própria app já usou.
   OWN-WORLD: papel institucional frio (grafite/branco-acinzentado, nunca
   creme), tinta preto-grafite para texto, UM acento de autoridade — vermelho
   de selo/decreto (--c-garnet-*) — reservado a ações primárias, números de
   nota e ao selo de certificação, mais um azul de tinta de assinatura
   (--c-inkblue-*) só para diferenciação funcional discreta (links, uma 2ª
   série de dados) — nunca a competir em protagonismo com o garnet. Cantos
   quase-retos (documento, não app "fofa"); pill reservado só a controlos
   pequenos (badges, avatar, switch). Sem brilho/glow nenhum — a autoridade
   vem da tinta e da régua, não do néon. Totais fecham com uma régua dupla
   (border-bottom-style:double), a mesma convenção contabilística de sempre.
   ========================================================================= */
:root{
  /* ---------- primitivas — neutros (papel institucional frio, inalterados) + o par de acentos
     "tinta de selo" (garnet, primário) e "tinta de assinatura" (inkblue, secundário/discreto). ---------- */
  --c-ink-950:#0B0B0C; --c-ink-900:#131315; --c-ink-800:#1C1C20; --c-ink-700:#2B2B30; --c-ink-600:#3D3D43;
  --c-ink-500:#57575D; --c-ink-400:#6B6F75; --c-ink-300:#9CA3A2;
  --c-ink-200:#CBD3D2; --c-ink-100:#E2E7E6; --c-ink-50:#F3F6F6; --c-white:#FFFFFF;
  /* Acento primário — vermelho de selo/decreto (carimbo oficial, número de artigo). 700/600 seguros
     como texto/preenchimento sobre CLARO (≥4.5:1 contra branco, verificado); 400/300 são o tom vivo
     sobre fundo escuro (também verificado ≥4.5:1 contra os dois fundos escuros) — nunca usados como
     texto sobre claro. */
  --c-garnet-900:#3A0A0D; --c-garnet-800:#541015; --c-garnet-700:#71161D; --c-garnet-600:#8F1E24;
  --c-garnet-500:#AD262D; --c-garnet-400:#DA5850; --c-garnet-300:#EE9089;
  /* Acento secundário — azul de tinta de assinatura (o azul-caneta usado para assinar por cima de um
     documento impresso a preto): mesma disciplina de contraste, sempre um tom mais discreto do que o
     garnet, nunca uma segunda cor a competir pelo mesmo protagonismo. */
  --c-inkblue-900:#0A1B2C; --c-inkblue-800:#0F2338; --c-inkblue-700:#1B3A5C; --c-inkblue-600:#254D78;
  --c-inkblue-500:#33629A; --c-inkblue-400:#5F87B7; --c-inkblue-300:#9AB4D4;
  --c-green-700:#1F6B4A; --c-green-600:#2C8964; --c-green-100:#E4F3EA; --c-green-300:#A9DABF;
  --c-red-700:#9A2A20; --c-red-600:#C8402F; --c-red-100:#FBEAE7; --c-red-300:#EFB3A8;
  --c-amber-700:#8A6A05; --c-amber-600:#B8901A; --c-amber-100:#FBF2DC; --c-amber-300:#E8D080;
  /* Par de cores do logótipo real (FECS — águia/chama, ver pasta img/), amostrado por pixel
     diretamente do ficheiro: laranja vivo (~#F87800) + azul-marinho profundo (~#001858). Usadas com
     moderação — a "tinta de selo" garnet continua o acento de ação primária de sempre — só para dar
     à sidebar a sua cor de marca fixa e ao modo claro dois tons subtis que tirem o aspeto vazio,
     nunca como substituto do acento funcional (--accent). --c-brand-orange é deliberadamente mais
     suave do que o laranja puro do logótipo (mistura com o neutro), para nunca competir com o
     garnet nem ficar "gritante" como wash de fundo. */
  --c-brand-navy-950:#0A1526; --c-brand-navy-900:#0D1B33; --c-brand-navy-800:#16273D; --c-brand-navy-700:#213756;
  --c-brand-orange-600:#D9791E; --c-brand-orange-500:#F2A03D; --c-brand-orange-300:#F6C384;

  /* ---------- tokens semânticos (modo claro, valor por omissão) ---------- */
  /* Fundo de página deixou de ser um cinza plano — pedido explícito ("o modo claro está muito
     branco e muito simples"): dois washes radiais muito subtis (5-7% de opacidade), um em cada
     canto oposto, com os 2 tons do logótipo (--c-brand-navy/--c-brand-orange) — nunca um acento
     funcional novo, só textura de fundo. Fixo (`background-attachment:fixed`, ver regra `body`)
     para não deslizar com o scroll. Ausente no tema escuro (--page-wash:none, ver
     [data-theme="dark"]) — o escuro já foi validado como está, só o claro precisava de mais corpo. */
  --page-wash:radial-gradient(1100px 640px at -6% -10%, rgba(13,27,51,.05), transparent 60%), radial-gradient(1000px 620px at 106% 110%, rgba(242,160,61,.07), transparent 58%);
  --bg-page:var(--c-ink-50);
  --bg-surface:var(--c-white);
  --bg-subtle:var(--c-ink-100);
  --bg-subtle-strong:var(--c-ink-200);
  --text-primary:var(--c-ink-900);
  --text-secondary:var(--c-ink-600);
  --text-muted:var(--c-ink-400);
  --border:var(--c-ink-200);
  --border-strong:var(--c-ink-300);
  --accent:var(--c-garnet-600);
  --accent-strong:var(--c-garnet-700);
  --accent-tint:#F7E3E0;
  --accent-2:var(--c-inkblue-700);
  --accent-2-tint:#E6ECF3;
  --focus-ring:var(--c-garnet-600);
  /* Cor do texto/ícone quando --accent-strong/--accent-2 são usados como PREENCHIMENTO sólido de um
     botão (.btn.primary/.ledger/.rust, label.btn) — no claro são tons escuros e seguros com texto
     branco; no escuro, --accent-strong/--accent-2 passam a tons claros ("vivos", pensados para texto
     sobre fundo escuro, nunca para preencher com texto branco por cima) — sem este token o botão
     primário no tema escuro ficava com texto branco sobre um vermelho já muito claro, ilegível.
     Mesmo padrão já usado por --chrome-accent-ink, agora também para os botões fora da moldura. */
  --accent-ink:#fff;
  --success:var(--c-green-600); --success-strong:var(--c-green-700); --success-tint:var(--c-green-100); --success-border:var(--c-green-300);
  --danger:var(--c-red-600); --danger-strong:var(--c-red-700); --danger-tint:var(--c-red-100); --danger-border:var(--c-red-300);
  --warning:var(--c-amber-600); --warning-strong:var(--c-amber-700); --warning-tint:var(--c-amber-100); --warning-border:var(--c-amber-300);
  /* Chevron do <select> nativo (ver regra `select{}` abaixo) — cor fixa embutida no SVG (não pode usar
     currentColor num background-image), por isso precisa de uma variante por tema. */
  --select-caret:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2357575D' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  --select-caret-disabled:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239C9CA1' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");

  /* ---------- moldura ("chrome") — cabeçalho fixo, separadores, barra do Menu. Segue sempre o tema
     claro/escuro da área de trabalho (ver [data-theme="dark"] abaixo). Já não leva nenhum contorno
     "neon" — é uma moldura de documento oficial: hairline discreta, sem brilho, a autoridade vem da
     tinta (garnet) usada com intenção nos estados ativos, não de um contorno luminoso. ---------- */
  --chrome-bg:var(--bg-surface);
  --chrome-bg-raised:var(--bg-subtle);
  --chrome-border:var(--border);
  --chrome-text:var(--text-primary);
  --chrome-text-muted:var(--text-muted);
  --chrome-accent:var(--accent-strong);
  --chrome-accent-strong:var(--accent);
  /* Cor do texto/ícone quando --chrome-accent é usado como PREENCHIMENTO sólido (ex.: hover do botão
     "Menu") — no claro, --chrome-accent é um garnet escuro (seguro como texto), por isso o
     preenchimento precisa de texto claro; no escuro é o inverso (ver [data-theme="dark"]). */
  --chrome-accent-ink:#fff;
  /* Sem glow em lado nenhum da moldura, em nenhum tema — sombra transparente de raio 0, só para o
     box-shadow continuar uma lista válida onde ainda é composto com --shadow-sm. */
  --chrome-glow:0 0 0 0 transparent;

  /* ---------- sidebar — identidade FIXA, azul-marinho da própria marca (nunca segue --chrome-*,
     nem o tema claro/escuro, tal como o selo de marca): pedido explícito para a barra lateral ter sempre
     "uma coloração azul escuro que não agride os olhos", a mesma disciplina de "isto não pisca ao
     mudar de tema" já usada em .brand-mark. Contraste de texto verificado (fórmula WCAG) ≥4.5:1 em
     todos os pares abaixo. ---------- */
  /* Largura da sidebar expandida — token novo (era um "248px" literal repetido em 3 sítios: a própria
     `.app-sidebar`, `.screen-with-sidebar{margin-left}` e a posição da orelha `.sidebar-ear{left}`) —
     agora também referenciado pelo painel informativo direito das Ferramentas (`.conc-split-layout`),
     que passou a ter a MESMA largura da sidebar, pedido explícito ("identica a nossa sidebar"). Uma
     única fonte de verdade evita as 2 larguras derivarem sem querer uma da outra no futuro. */
  --sidebar-width:248px;
  --sidebar-bg:var(--c-brand-navy-900);
  --sidebar-bg-raised:var(--c-brand-navy-800);
  --sidebar-border:rgba(255,255,255,.09);
  /* Branco puro (era #EAF1FA, um branco com leve travo azulado) — pedido explícito: "a cor de texto
     dos menus deve ser branca mesmo para qualquer situação". Cascata automática para tudo o que já
     usava este token (nome do utilizador, hover dos itens, hover do botão de tema). */
  --sidebar-text:#FFFFFF;
  --sidebar-text-muted:#93A8C4;
  --sidebar-accent:var(--c-garnet-400);
  --sidebar-accent-strong:var(--c-garnet-300);
  /* Tinta sobre o acento rosa (`--sidebar-accent`) — pedido explícito: "os elementos que atribuímos a
     cor laranja devem pegar a cor azul do sidebar para criar um bom contraste". Era `--c-ink-950`
     (quase-preto); passa a `--sidebar-bg`, o mesmo azul-marinho da própria sidebar — já é a "cor azul
     do sidebar" literal, não uma nova cor inventada, por isso cascata sozinha para qualquer elemento
     que já usasse este token (avatar, pontos da orelha em hover) sem precisar de mudar mais nada. */
  --sidebar-accent-ink:var(--sidebar-bg);
  --sidebar-item-active-bg:rgba(218,88,80,.16);
  /* Texto dos itens de menu — branco puro (era #CDD5DE, um branco com leve travo de cinzento;
     antes disso, #93A8C4, azulado) — pedido explícito, 2ª ronda: "a cor de texto dos menus deve ser
     branca mesmo para qualquer situação". */
  --sidebar-nav-text:#FFFFFF;
  /* Borda do botão de tema — branco sólido, pedido explícito ("o botão do tema deve ter a borda de
     cor branca também"); era `rgba(255,255,255,.32)` (32% branco, já visível mas não "branca" a
     sério como pedido agora). */
  --sidebar-border-strong:#FFFFFF;

  /* ---------- anel de foco — um só uso legítimo de "brilho": o contorno de foco de um campo/controlo
     (acessibilidade, não decoração). Sempre um anel sólido (raio de desfoque 0), nunca um halo difuso —
     é essa a diferença entre um indicador de foco e o "glow neon" que a app já teve e abandonou. ---------- */
  --glow-sm:0 0 0 3px rgba(143,30,36,.22);

  /* ---------- escala — cantos quase-retos, de documento (não "app fofa"): cartões 12px, inputs 9px,
     botões com o mesmo --radius (nunca pill) — --radius-pill fica reservado a controlos mesmo pequenos
     (badges, avatar, switch), como recomenda o piso de qualidade do design system. ---------- */
  --radius-sm:6px; --radius:9px; --radius-lg:12px; --radius-pill:999px;
  --shadow-sm:0 1px 2px rgba(20,18,15,0.06);
  --shadow:0 1px 2px rgba(20,18,15,0.04), 0 4px 10px -4px rgba(20,18,15,0.10);
  --shadow-md:0 8px 20px -6px rgba(20,18,15,0.16);
  /* Elevação para elementos com borda visível (cartão em hover, etc.) — desfoque sempre < 16px, para
     nunca cair no padrão "ghost card" (borda 1px + sombra larga e macia ao mesmo tempo). Elementos
     verdadeiramente flutuantes (popover, dropdown) continuam a usar --shadow-md, mas SEM borda. */
  --shadow-hover:0 6px 14px -5px rgba(20,18,15,0.18);
  --space-1:4px; --space-2:8px; --space-3:12px; --space-4:16px; --space-5:20px; --space-6:24px; --space-8:32px;

  /* ---------- escala z-index semântica — cada camada só compete com a de baixo, nunca com valores
     arbitrários tipo 999/9999. Do fundo para o topo: barra sticky secundária (ex.: faixa de filtros
     dentro de um separador) < cabeçalho fixo principal < dropdown/autocomplete (tem de ficar sempre
     por cima de qualquer sticky que possa deslizar por baixo) < fundo do modal < modal < toast (nunca
     tapado por nada, é sempre a última coisa que o utilizador tem de ver). ---------- */
  --z-sticky-sub:5; --z-sticky:40; --z-dropdown:50; --z-modal-backdrop:100; --z-modal:101; --z-toast:200;
}

/* ---------- aliases legados — usados diretamente em style="" dentro de script.js. Fora do :root
   porque não fazem parte da escala de tema (não precisam de existir dentro de [data-theme="dark"]
   também) — apontam sempre para o token semântico já resolvido, por isso cascatam sozinhos. ---------- */
:root{
  --ink:var(--text-primary);
  --ink-soft:var(--text-secondary);
  --muted:var(--text-muted);
  --line:var(--border);
  --line-strong:var(--border-strong);
  --paper:var(--bg-page);
  --paper-raised:var(--bg-surface);
  --rust:var(--danger);
  --rust-tint:var(--danger-tint);
  --amber:var(--warning);
  --amber-tint:var(--warning-tint);
  --wine:var(--accent);
  --wine-tint:var(--accent-tint);
  --plum:var(--accent-strong);
  --berry:var(--accent-2);
  --coral:var(--accent-2);
  --peach:var(--accent-2);
}

/* ---------- modo escuro: só a camada semântica muda — tudo o resto cai em cascata. A moldura
   mantém-se quase-preta neste tema (como sempre foi), agora sem nenhum contorno neon — nem aqui
   nem no claro, ver comentário no :root principal. ---------- */
[data-theme="dark"]{
  --chrome-bg:var(--c-ink-950);
  --chrome-bg-raised:var(--c-ink-800);
  --chrome-border:rgba(255,255,255,.09);
  --chrome-text:#F4FBFA;
  --chrome-text-muted:#8FA3A0;
  --chrome-accent:var(--c-garnet-400);
  --chrome-accent-strong:var(--c-garnet-300);
  --chrome-accent-ink:var(--c-ink-950);
  --chrome-glow:0 0 0 0 transparent;
  --page-wash:none;
  --bg-page:var(--c-ink-950);
  --bg-surface:#151517;
  --bg-subtle:#1B1B1E;
  --bg-subtle-strong:#232326;
  --text-primary:#F2F0EC;
  --text-secondary:#C7C5C0;
  --text-muted:#93918C;
  --border:#29292C;
  --border-strong:#38383C;
  --accent:var(--c-garnet-400);
  --accent-strong:var(--c-garnet-300);
  --accent-tint:rgba(218,88,80,0.16);
  --accent-2:var(--c-inkblue-400);
  --accent-2-tint:rgba(95,135,183,0.16);
  --focus-ring:var(--c-garnet-400);
  --accent-ink:var(--c-ink-950);
  --success-tint:rgba(44,137,100,0.18); --success-border:rgba(169,218,191,0.3);
  --danger-tint:rgba(200,64,47,0.18); --danger-border:rgba(239,179,168,0.3);
  --warning-tint:rgba(184,144,26,0.18); --warning-border:rgba(232,208,128,0.3);
  --shadow:0 1px 2px rgba(0,0,0,0.35), 0 4px 14px -6px rgba(0,0,0,0.55);
  --shadow-md:0 10px 26px -8px rgba(0,0,0,0.6);
  --shadow-hover:0 6px 14px -5px rgba(0,0,0,0.5);
  --select-caret:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2393918C' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  --select-caret-disabled:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234A4A4E' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");

  /* ---------- sidebar — pedido explícito: "no modo light o painel lateral está ok, mas no modo dark
     deve inverter as cores primárias azul e rosa". No claro, a sidebar continua uma parede azul-
     marinho (`--sidebar-bg`) com destaques rosa (`--sidebar-accent`) — inalterado. No escuro, os
     destaques continuam a inversão original (azul-marinho, `--c-brand-navy-900`), mas a PAREDE deixou
     de ser rosa — pedido explícito, 2ª ronda: "em vez da cor rosa, coloca uma cor branca a ir
     levemente para o cinza... não algo totalmente branco". `--sidebar-bg`/`--sidebar-bg-raised`
     passam a `--c-ink-100`/`--c-ink-50` (os 2 neutros mais claros da escala "papel institucional
     frio" já usada no resto da app — nunca `--c-white` puro, como pedido), com "raised" um passo mais
     claro do que a parede, a mesma relação que já existia (bg-raised sempre mais claro que bg, em
     qualquer variante desta paleta). `--sidebar-accent-ink` (definida uma única vez em `:root` como
     `var(--sidebar-bg)`) volta a resolver-se sozinha — agora para este cinza-quase-branco, em vez do
     rosa anterior — sem precisar de ser redefinida aqui.
     Texto/contornos que assentam DIRETAMENTE na parede (`--sidebar-text`/`--sidebar-nav-text`/
     `--sidebar-text-muted`/`--sidebar-border`/`--sidebar-border-strong`) mantêm-se em tons de
     azul-marinho (escolhidos na 1ª ronda desta inversão, quando a parede ainda era rosa) — o
     contraste só melhora com um fundo mais claro (`navy-950` vs `ink-100` = 14.6:1, ainda mais folgado
     do que os 4.78:1 já verificados contra o rosa), por isso não precisaram de mudar outra vez.
     `--sidebar-item-active-bg` (token de reserva, hoje sem uso) mantém-se também, já era azul desde a
     1ª ronda. ---------- */
  --sidebar-bg:var(--c-ink-100);
  --sidebar-bg-raised:var(--c-ink-50);
  --sidebar-border:rgba(10,21,38,.18);
  --sidebar-text:var(--c-brand-navy-950);
  --sidebar-text-muted:var(--c-brand-navy-800);
  --sidebar-accent:var(--c-brand-navy-900);
  --sidebar-accent-strong:var(--c-brand-navy-800);
  --sidebar-item-active-bg:rgba(13,27,51,.16);
  --sidebar-nav-text:var(--c-brand-navy-950);
  --sidebar-border-strong:var(--c-brand-navy-950);
}

/* Zoom de 90% aplicado à app inteira — pedido explícito do utilizador, que testou manualmente a
   zoom do próprio browser a 90% e preferiu esse tamanho. Não existe nenhuma API que force o zoom
   NATIVO do browser a partir da página (é reservado de propósito ao utilizador); `zoom` é a
   propriedade de CSS que reproduz o mesmo efeito — é literalmente o mecanismo interno que
   Chrome/Edge/Safari já usam para o próprio zoom nativo (Ctrl +/-), por isso recalcula layout e
   `position:fixed` da mesma forma que um zoom manual, ao contrário de `transform:scale()` (que só
   reescala visualmente, sem recalcular layout, e quebraria a sidebar fixa). Suporte de browser:
   universal em Chrome/Edge/Safari; Firefox desde a versão 126 (2024).
   Aplicado no `html` (não no `body`) para cobrir tudo, incluindo elementos com `position:fixed`
   ancorados à viewport (ex.: `.app-sidebar`, `.loading-overlay`).
   ATENÇÃO — `100vh`/`100vw` NÃO acompanham este zoom: ao contrário do zoom nativo do browser (onde
   as unidades de viewport se recalculam sozinhas contra o viewport "efetivo"), a propriedade `zoom`
   aplicada a um elemento continua a resolver `vh`/`vw` dos descendentes contra o viewport FÍSICO
   real, sem encolher — só DEPOIS o resultado é que é pintado a 90%. Um elemento com `height:100vh`
   fica visualmente 10% mais baixo do que o ecrã real, deixando uma faixa vazia por baixo (bug real
   relatado pelo utilizador na sidebar). Sempre que um elemento precisar de encostar mesmo ao limite
   físico do ecrã, a altura declarada tem de compensar o zoom: `calc(100vh / var(--app-zoom))` (ver
   `.app-sidebar`) — 111.1vh declarados × 0.9 de zoom = 100vh físicos, exatamente encostado. */
:root{ --app-zoom:0.9; }
html{zoom:var(--app-zoom);}
*{box-sizing:border-box;}
::selection{ background:var(--accent-2); color:#fff; }

body{
  /* Sem padding no topo: os cabeçalhos fixos (moldura) ficam sempre encostados ao limite superior
     da viewport, sem margem nenhuma — só sobra espaço nas laterais/fundo para o resto do conteúdo.
     max(...,env(safe-area-inset-*)) preserva as margens de sempre em qualquer ecrã "normal" e só
     cresce quando o dispositivo tem notch/home-indicator (iPhone em paisagem, etc.). */
  margin:0; color:var(--text-primary); font-family:'IBM Plex Sans',-apple-system,'Segoe UI',Roboto,sans-serif;
  /* Margem lateral direita reduzida ainda mais (30px→15px→3px agora), pedido explícito — a esquerda
     mantém-se (a sidebar global fixa já ocupa essa faixa por cima, ver .screen-with-sidebar), só a
     direita ficava como espaço vazio genuíno entre o conteúdo e o limite da janela. */
  padding:0 max(3px, env(safe-area-inset-right)) max(80px, env(safe-area-inset-bottom)) max(30px, env(safe-area-inset-left));
  background-color:var(--bg-page); background-image:var(--page-wash); background-attachment:fixed;
  font-variant-numeric:tabular-nums;
  transition:background-color .18s ease, color .18s ease;
}
/* Sem margem lateral nenhuma no mobile (pedido explícito: "remover a margem que existe entre o body
   e a tela") — as 30px de sempre (pensadas para dar respiro às pré-visualizações de tabela num ecrã
   largo) só fazem sentido em desktop; no telemóvel, com a sidebar já reduzida a 4px de margem
   própria (ver .app-sidebar dentro do @media abaixo), a faixa de 30px do body por fora dela ficava
   redundante e desperdiçava largura útil num ecrã já pequeno. */
@media (max-width:900px){
  body{ padding:0 env(safe-area-inset-right) max(40px, env(safe-area-inset-bottom)) env(safe-area-inset-left); }
}
/* Layout encostado à esquerda (30px do limite da janela, ver padding acima), sem largura máxima
   centrada — dá mais espaço horizontal às tabelas (Notas, Balanço), que já precisavam de scroll
   lateral com poucas colunas a mais. */
.wrap{max-width:none; margin:0;}

::-webkit-scrollbar{width:10px; height:10px;}
::-webkit-scrollbar-track{background:transparent;}
::-webkit-scrollbar-thumb{background:var(--border-strong); border-radius:99px; border:2px solid var(--bg-page);}
::-webkit-scrollbar-thumb:hover{background:var(--text-muted);}
* { scrollbar-color: var(--border-strong) transparent; scrollbar-width: thin; }

a{ color:var(--accent-2); }

/* Par tipográfico: IBM Plex Sans (corpo/dados/UI, sempre) + Source Serif 4 (só h1/h2/h3) — a voz de
   um diploma/gazeta oficial, não a de um SaaS genérico. IBM Plex Sans substitui a Inter (pedido
   explícito do utilizador, depois de a skill impeccable assinalar Inter como uma das fontes mais
   "batidas"/genéricas de interfaces geradas por IA) — escolhida por ter métricas de largura muito
   próximas da Inter (risco mínimo de desalinhar tabelas/colunas densas já ajustadas para essa
   largura) e por ter sido desenhada pela própria IBM para interfaces com muitos dados/números,
   o que serve bem uma app financeira. Deliberadamente NÃO uma serifa de exibição de alto contraste
   (Playfair/Fraunces e afins) — essa combinação (serifa de contraste alto + acento vermelho + papel
   claro) é precisamente o 1º clichê de interface gerada por IA já nomeado no histórico deste
   projeto, e esta app já tem o acento vermelho e o papel claro; a Source Serif 4 tem contraste de
   traço moderado (uma serifa de texto/editorial, não Didone) e não está em nenhuma lista de fontes
   "batidas" — dá caráter sem reforçar o clichê. Tracking quase neutro (serifas não precisam do
   aperto negativo de uma sans de exibição). */
h1,h2,h3{font-family:'Source Serif 4','IBM Plex Sans',serif; font-weight:800; letter-spacing:-0.005em;}

/* ---------- ícones — um único estilo (outline, stroke) em toda a app ---------- */
.icon, .ic-wrap svg{display:block; flex-shrink:0;}
.ic-wrap{display:inline-flex; align-items:center; justify-content:center; flex-shrink:0;}

/* ======================= MASTHEAD ======================= */
.masthead{position:relative; display:flex; justify-content:space-between; align-items:flex-end; gap:16px; flex-wrap:wrap;}
.masthead-left{display:flex; gap:14px; align-items:center; min-width:0;}
/* min-width:0 no wrapper de texto (título+subtítulo, reaproveitado também em .menu-topbar para a
   saudação) permite que um nome/saudação comprido quebre em várias linhas em vez de forçar a
   página a alargar (mesmo "flex blowout" já documentado noutros pontos da app — só nunca tinha
   sido exercitado aqui, por os nomes de teste serem sempre curtos). */
.masthead-left > div{min-width:0;}
.masthead h1, .menu-welcome-title, .masthead .sub, .menu-topbar .sub{overflow-wrap:break-word;}
/* Seletor de idioma — botão redondo com a bandeira desenhada em SVG (ver BANDEIRAS_SVG/
   renderIdiomaSwitches em script.js). Bug real corrigido: um `<option>` só pode conter texto — o
   emoji de bandeira que lá vivia (`🇵🇹`) só é desenhado a cores em macOS/iOS/Android; o Windows não
   tem glifo de bandeira em nenhuma fonte do sistema e cai sempre para o código do país em texto
   ("PT"/"EN"/"FR"), mesmo com o CSS certo — por isso deixou de ser um `<select>` nativo, passou a um
   botão + um pequeno dropdown próprio (mesmo padrão do `.nav-dropdown` mobile), com a bandeira em
   `<svg>` inline (não depende de nenhuma fonte, nunca falha). `.idioma-switch` é o `<div>` vazio já
   presente no HTML (`data-idioma-switch`, único, no rodapé da sidebar — os 7 mastheads já não têm
   nenhum, o widget vive só ali agora) que `renderIdiomaSwitches()` preenche. */
.idioma-switch{ position:relative; flex-shrink:0; }
.idioma-switch-btn{
  appearance:none; -webkit-appearance:none; -moz-appearance:none;
  width:36px; height:36px; padding:0; margin:0; flex-shrink:0;
  display:flex; align-items:center; justify-content:center;
  border-radius:50%; background-color:var(--chrome-bg-raised); border:1px solid var(--chrome-border);
  cursor:pointer; transition:border-color .15s, transform .15s;
}
.idioma-switch-btn:hover{ border-color:var(--chrome-accent); transform:translateY(-1px); }
.idioma-switch-btn svg{ width:19px; height:13px; border-radius:2px; display:block; box-shadow:0 0 0 1px rgba(0,0,0,.15); }
@media (pointer:coarse){ .idioma-switch-btn{ width:44px; height:44px; } }
.idioma-switch-menu{
  position:absolute; top:calc(100% + 6px); right:0; min-width:152px;
  background:var(--bg-surface); border:1px solid var(--border); border-radius:var(--radius-sm);
  box-shadow:var(--shadow-md); padding:4px; z-index:var(--z-dropdown);
}
.idioma-switch-menu.hidden{ display:none; }
.idioma-switch-item{
  display:flex; align-items:center; gap:9px; width:100%; padding:8px 10px; border:none; background:transparent;
  border-radius:var(--radius-sm); cursor:pointer; font-family:inherit; font-size:12.5px; font-weight:600; color:var(--text-primary); text-align:left;
}
.idioma-switch-item:hover, .idioma-switch-item:focus-visible{ background:var(--bg-subtle); outline:none; }
.idioma-switch-item svg{ width:19px; height:13px; border-radius:2px; flex-shrink:0; box-shadow:0 0 0 1px rgba(0,0,0,.15); }
/* Selo de marca — "squircle" (quadrado muito arredondado) em tinta quase-preta fixa (SEMPRE a mesma,
   por primitiva direta — já não segue --chrome-*, que passou a acompanhar o tema; um selo de marca
   não deve "piscar" ao mudar de tema NEM ao mudar a cor da moldura à sua volta) + o ícone de visto
   ("✓"), o mesmo traço que um auditor risca ao lado de um valor reconciliado — motivo genuíno do
   domínio (fecho = contas conferidas e fechadas), não um ícone genérico. Fundo sólido, cantos
   moderadamente arredondados (não um pill, não um círculo com gradiente/brilho interior — o "orb"
   genérico de logótipo gerado por IA). Sem sombra/glow: um selo oficial é definido pela tinta e pela
   borda, nunca por um halo luminoso. Módulos sem este motivo (ex. "Reports Mensais", ainda
   placeholder) continuam a usar as iniciais como texto. */
.brand-mark{
  width:40px; height:40px; flex-shrink:0; border-radius:14px; padding:7px;
  background:var(--c-ink-900); border:1px solid var(--c-garnet-700);
  color:var(--c-garnet-400); display:flex; align-items:center; justify-content:center;
  font-weight:700; font-size:14px; letter-spacing:.02em;
}
.brand-mark svg{width:19px; height:19px;}
/* Logótipo real da FECS (ver pasta img/) dentro do selo — o fundo fixo --c-ink-900 nunca muda de
   tema (mesma razão de sempre: uma marca não deve "piscar" ao alternar tema), por isso não precisa
   de variante clara/escura própria, ao contrário do logótipo da sidebar (ver .side-brand). */
.brand-mark img{width:100%; height:100%; object-fit:contain;}
/* Selo grande do ecrã de login — o "hero" da app: mesma marca sólida, com um anel tracejado solto à
   volta (referência direta a um carimbo/selo oficial angolano — o único ornamento que este ecrã se
   permite) e uma pequena entrada suave ao carregar a página (respeita prefers-reduced-motion). */
.brand-mark-seal{width:58px; height:58px; margin:0 auto 18px; position:relative; border-radius:18px; padding:9px;}
.brand-mark-seal::before{
  content:''; position:absolute; inset:-9px; border-radius:28px;
  border:1.5px dashed var(--c-garnet-400); opacity:.4;
}
@media (prefers-reduced-motion: no-preference){
  .brand-mark-seal, .auth-title, .pilot-tag{ animation:fc-rise .55s cubic-bezier(.16,1,.3,1) both; }
  .auth-title{ animation-delay:.06s; }
  .pilot-tag{ animation-delay:.11s; }
  @keyframes fc-rise{ from{opacity:0; transform:translateY(7px);} to{opacity:1; transform:translateY(0);} }
}
/* Margem vertical reduzida a metade (18px→9px, topo e fundo) — pedido explícito para ganhar espaço
   vertical; a horizontal (24px) mantém-se. */
.masthead{padding:max(9px, env(safe-area-inset-top)) 24px 9px; color:var(--chrome-text);}
.masthead h1{font-weight:700; font-size:21px; margin:0; letter-spacing:-0.01em; color:var(--chrome-text);}
.masthead .sub{color:var(--chrome-text-muted); font-size:12.5px; margin-top:3px;}
.ref-code{font-size:11px; color:var(--chrome-text-muted); text-align:right; font-variant-numeric:tabular-nums;}
.pilot-tag{display:inline-flex; align-items:center; gap:6px; background:var(--bg-subtle); color:var(--text-muted); border:1px solid var(--border); font-size:10px; font-weight:600; letter-spacing:.04em; padding:3px 10px; border-radius:var(--radius-pill); margin-top:7px;}

/* Ecrãs sem nav-tabs/breadcrumb (Admin, Reports Mensais — masthead é filho direto de .wrap, não vive
   dentro de .fecho-sticky-header) ganham a moldura completa (fundo, cantos, sombra, contorno) sozinhos,
   para nunca aparecer "nu" sobre o fundo da página — mesmo tratamento da moldura das outras telas. */
.wrap > .masthead{
  background:var(--chrome-bg); border:1px solid var(--chrome-border); border-radius:var(--radius-lg);
  box-shadow:var(--shadow-sm), var(--chrome-glow); margin-bottom:20px;
}

/* ======================= BREADCRUMB ======================= */
.breadcrumb{display:flex; align-items:center; gap:6px; font-size:12px; color:var(--chrome-text-muted); margin:7px 0 0; padding:0 24px; font-weight:500;}
.breadcrumb .crumb-link{cursor:pointer; transition:color .12s;}
.breadcrumb .crumb-link:hover{color:var(--chrome-accent);}
.breadcrumb .crumb-current{color:var(--chrome-text); font-weight:600;}
.breadcrumb .icon{color:var(--chrome-text-muted);}

/* ---------- empresa ativa (Fase 3) — etiqueta + indicador de gravação + trocar, no masthead ---------- */
.empresa-ativa-bar{display:flex; align-items:center; gap:10px; flex-wrap:wrap; font-size:12px; color:var(--chrome-text-muted); margin:3px 0 0; padding:0 24px;}
.empresa-ativa-bar .empresa-ativa-nome{font-weight:600; color:var(--chrome-text);}
.empresa-ativa-status{font-size:11px;}
.empresa-ativa-status.status-a-guardar{color:var(--warning);}
.empresa-ativa-status.status-guardado{color:var(--success);}
.empresa-ativa-status.status-erro{color:var(--danger); font-weight:600;}
.link-btn{background:none; border:none; padding:0; margin:0; font:inherit; font-size:12px; color:var(--chrome-accent); cursor:pointer; text-decoration:underline; text-underline-offset:2px;}
.link-btn:hover{color:var(--chrome-accent-strong);}

/* ======================= CABEÇALHO FIXO (Fecho de Contas) =======================
   Masthead + breadcrumb + nav-tabs ficam juntos num único bloco sticky, para não ter
   de calcular offsets entre eles — todo o bloco fica visível ao fazer scroll pelas secções, sempre
   encostado ao limite superior da viewport (sem margem, ver body{}). Moldura ("chrome") segue o tema
   claro/escuro da área de trabalho — clara com contorno em ciano no tema claro, quase-preta (como
   sempre foi) no tema escuro — ver DESIGN.md. */
.fecho-sticky-header{
  position:sticky; top:0; z-index:var(--z-sticky); background:var(--chrome-bg);
  border:1px solid var(--chrome-border); box-shadow:var(--shadow-sm), var(--chrome-glow);
  border-radius:0 0 var(--radius-lg) var(--radius-lg);
}
.fecho-sticky-header .masthead{border-bottom:1px solid var(--chrome-border);}

/* Botões/select que vivem dentro da moldura escura precisam da sua própria variante — as classes
   .btn.secondary/.btn.highlight e o <select> genérico foram desenhados para superfícies claras
   (--bg-surface/--border-strong), invisíveis ou quase sobre --chrome-bg. `.masthead` cobre os dois
   casos (dentro de `.fecho-sticky-header` OU sozinho, em Admin/Reports Mensais) porque ambos já
   herdam --chrome-bg de alguma forma (ver ".wrap > .masthead" acima). */
.masthead select, .menu-topbar select{
  background-color:var(--chrome-bg-raised); color:var(--chrome-text); border-color:var(--chrome-border);
}
.masthead .btn.secondary, .menu-topbar .btn.secondary{
  background:var(--chrome-bg-raised); color:var(--chrome-text); border-color:var(--chrome-border);
}
.masthead .btn.secondary:hover, .menu-topbar .btn.secondary:hover{ border-color:var(--chrome-accent); color:var(--chrome-accent); }
.masthead .btn.highlight, .menu-topbar .btn.highlight{
  background:rgba(143,30,36,.10); color:var(--chrome-accent); border-color:rgba(143,30,36,.32);
}
.masthead .btn.highlight:hover, .menu-topbar .btn.highlight:hover{ background:var(--chrome-accent); color:var(--chrome-accent-ink); border-color:var(--chrome-accent); }

/* ======================= NAV TABS =======================
   Margens/padding verticais reduzidos a metade (pedido explícito, mesmo critério do .masthead acima):
   margin-top 10→5, padding-bottom 14→7, padding vertical de cada aba 10→5. */
.nav-tabs{display:flex; gap:4px; margin:5px 0 0; padding:0 24px 7px; flex-wrap:wrap;}
.nav-tab{
  padding:5px 12px; margin-right:4px; border:none; background:transparent; border-bottom:2px solid transparent;
  border-radius:var(--radius-sm) var(--radius-sm) 0 0;
  font-size:12.5px; font-weight:600; color:var(--chrome-text-muted); cursor:pointer; display:flex; align-items:center; gap:7px;
  transition:color .15s, border-color .15s, background-color .15s;
}
.nav-tab .icon{color:var(--chrome-text-muted); transition:color .15s;}
/* Separador ativo: cor + sublinhado + fundo em tinta — sem brilho nenhum, a certeza vem do peso da
   cor e da régua, não de um halo. */
.nav-tab.active{color:var(--chrome-accent); border-bottom-color:var(--chrome-accent); background:rgba(143,30,36,.09); font-weight:700;}
.nav-tab.active .icon{color:var(--chrome-accent);}
.nav-tab:hover:not(.active){color:var(--chrome-text); background:var(--chrome-bg-raised);}

/* ---------- Menu mobile (hambúrguer + dropdown) — abaixo de 680px, ver renderNavResponsiva() em
   script.js. Nunca tabs+dropdown em paralelo: é sempre um OU outro no DOM, decidido no render. ---------- */
.nav-tabs.nav-tabs-mobile{display:block;}
.nav-hamburger{
  display:flex; align-items:center; gap:8px; width:100%; padding:10px 14px;
  border:1px solid var(--chrome-border); border-radius:var(--radius-sm); background:var(--chrome-bg-raised);
  color:var(--chrome-text); font-size:12.5px; font-weight:600; cursor:pointer; font-family:inherit;
}
.nav-hamburger-label{flex:1; text-align:left; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.nav-hamburger:hover, .nav-hamburger[aria-expanded="true"]{ border-color:var(--chrome-accent); color:var(--chrome-accent); }
.nav-hamburger .icon{color:inherit;}
@media (pointer:coarse){ .nav-hamburger{ padding:13px 14px; } }
.nav-dropdown{
  margin-top:6px; border:1px solid var(--chrome-border); border-radius:var(--radius-sm);
  background:var(--chrome-bg-raised); overflow:hidden; box-shadow:var(--shadow-sm);
  position:relative; z-index:var(--z-dropdown);
}
.nav-dropdown-item{
  display:flex; align-items:center; gap:9px; padding:12px 14px; font-size:12.5px; font-weight:600;
  color:var(--chrome-text-muted); cursor:pointer; border-bottom:1px solid var(--chrome-border);
}
.nav-dropdown-item:last-child{border-bottom:none;}
.nav-dropdown-item:hover, .nav-dropdown-item:focus-visible{ background:var(--chrome-bg); color:var(--chrome-text); outline:none; }
.nav-dropdown-item.active{ color:var(--chrome-accent); }
.nav-dropdown-item .icon{color:inherit;}
@media (pointer:coarse){ .nav-dropdown-item{ padding:14px; } }

.card{background:var(--bg-surface); border:1px solid var(--border); border-radius:var(--radius-lg); padding:26px; margin-bottom:18px; margin-top:0; box-shadow:var(--shadow-sm);}
/* Cartões que não precisam da largura toda do ecrã (ex.: Parâmetros do relatório) — ocupam a
   largura toda em telas pequenas/médias e vão estreitando progressivamente até ~50% em ecrãs
   grandes, para não ficarem desproporcionalmente largos num layout já sem coluna central. */
.card-narrow{max-width:100%;}
@media (min-width:900px){ .card-narrow{max-width:78%;} }
@media (min-width:1200px){ .card-narrow{max-width:62%;} }
@media (min-width:1600px){ .card-narrow{max-width:50%;} }
.card h2{font-size:16px; margin:0 0 6px; font-weight:700; color:var(--text-primary);}
.card .desc{color:var(--text-secondary); font-size:13px; margin:0 0 18px; line-height:1.6;}
.card .desc code{background:var(--bg-subtle); border-radius:4px; padding:1px 5px; font-size:12px;}
.waBot-checklist{list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:10px;}
.waBot-checklist li{position:relative; padding-left:26px; font-size:13px; color:var(--text-secondary); line-height:1.5;}
.waBot-checklist li::before{content:''; position:absolute; left:0; top:3px; width:16px; height:16px; border-radius:50%; border:1.5px solid var(--border-strong); background:var(--bg-subtle);}
.waBot-checklist li code{background:var(--bg-subtle); border-radius:4px; padding:1px 5px; font-size:12px;}
label{display:block; font-size:11px; font-weight:600; color:var(--text-secondary); margin-bottom:6px; text-transform:uppercase; letter-spacing:.05em;}
select, input[type=text], input[type=number], input[type=password], input[type=email], input[type=tel], textarea{
  width:100%; padding:9px 12px; border:1px solid var(--border-strong); border-radius:var(--radius-sm);
  background:var(--bg-surface); font-family:'IBM Plex Sans',sans-serif; font-size:13px; color:var(--text-primary);
  transition:border-color .12s, box-shadow .12s;
}
/* Abaixo de 13px, o Safari iOS dá zoom automático ao focar um campo — incómodo em formulários
   "normais" (login, parâmetros, diálogos). As tabelas densas (Notas/Balanço/Conciliação) ficam de
   fora de propósito (ver .mini-input, densidade "tipo folha de cálculo" já documentada) — a regra
   de baixo, mais específica, garante que nunca são tocadas mesmo estando fisicamente dentro de um
   .card. */
@media (max-width:680px){
  select, input[type=text], input[type=number], input[type=password], input[type=email], input[type=tel], textarea{ font-size:16px; }
}
.table-scroll input, .table-scroll select, .mini-input{ font-size:12px !important; }
/* A seta nativa do <select> tem um estilo diferente em cada browser/SO — substituída por um chevron
   próprio (mesma linguagem outline dos outros ícones da app) para o campo ficar visualmente consistente
   com os inputs de texto ao lado; continua a ser um <select> nativo, só a seta muda. */
select{
  appearance:none; -webkit-appearance:none; -moz-appearance:none;
  background-image:var(--select-caret); background-repeat:no-repeat; background-position:right 12px center; background-size:14px;
  padding-right:34px;
}
select:disabled{background-image:var(--select-caret-disabled);}
select:disabled, input:disabled, input:read-only{background:var(--bg-subtle); color:var(--text-muted); cursor:not-allowed;}
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none; margin:0;}
input[type=number]{-moz-appearance:textfield; appearance:textfield;}
select:focus, input:focus, textarea:focus{ outline:none; border-color:var(--focus-ring); box-shadow:var(--glow-sm); }
button:focus-visible, .nav-tab:focus-visible, .note-item:focus-visible{ outline:2px solid var(--focus-ring); outline-offset:2px; }
input[type=checkbox], input[type=radio]{ accent-color:var(--accent-2); width:15px; height:15px; }

/* ======================= TOGGLE SWITCH =======================
   Reservado a preferências binárias ligar/desligar (ex.: "Ativar regra de referência", "Ocultar
   linhas vazias") — nunca usado para seleção em lista/tabela, onde a checkbox normal continua a ser
   o componente certo. Embrulha o <input type=checkbox> nativo (mantém foco/teclado/estado reais);
   só a aparência é substituída, por isso qualquer código que já leia `.checked` continua a funcionar
   sem alterações de lógica. */
.switch{position:relative; display:inline-flex; align-items:center; gap:9px; cursor:pointer; user-select:none; margin-bottom:0; text-transform:none; letter-spacing:normal; font-weight:400;}
.switch input{position:absolute; opacity:0; width:1px; height:1px; margin:0;}
.switch-track{position:relative; flex-shrink:0; width:36px; height:21px; border-radius:var(--radius-pill); background:var(--bg-subtle-strong); border:1px solid var(--border-strong); transition:background-color .15s ease, border-color .15s ease, box-shadow .15s ease;}
.switch-track::before{content:''; position:absolute; top:1px; left:1px; width:17px; height:17px; border-radius:50%; background:var(--c-white); box-shadow:var(--shadow-sm); transition:transform .18s cubic-bezier(.16,1,.3,1);}
/* Estado ligado: só a cor da faixa muda (tinta sólida, sem brilho) — o deslize do círculo já é
   feedback suficiente de que o estado mudou. */
.switch input:checked ~ .switch-track{background:var(--accent-strong); border-color:var(--accent-strong);}
.switch input:checked ~ .switch-track::before{transform:translateX(15px);}
.switch input:focus-visible ~ .switch-track{outline:2px solid var(--focus-ring); outline-offset:2px;}
.switch input:disabled ~ .switch-track{opacity:.5; cursor:not-allowed;}
.switch-label{font-size:13px; color:var(--text-primary); font-weight:500;}
.grid{display:grid; gap:14px;}
.grid.cols-2{grid-template-columns:1fr 1fr;}
.grid.cols-3{grid-template-columns:1fr 1fr 1fr;}
.grid.cols-5{grid-template-columns:2fr 1fr 1fr 1.2fr 1fr;}
@media (max-width:820px){ .grid.cols-2, .grid.cols-3, .grid.cols-5{grid-template-columns:1fr;} }
/* Ecrã Empresas — "Criar empresa" (esquerda) e "As minhas empresas" (direita), 50/50, pedido
   explícito para entrar direto aqui a partir de "Relatório e Contas" na sidebar (ver script.js).
   align-items:start evita o esticamento por omissão do grid — cada cartão fica com a sua própria
   altura, em vez dos dois serem forçados ao tamanho do mais alto. */
.empresas-layout{align-items:start;}
/* Lista de exercícios (Gestão de Empresas) — a mesma grelha de 2 colunas serve tanto uma linha de
   exercício já existente (col1=ano, col2=botão Eliminar) como a linha "Criar/Salvar exercício"
   (col1=botão, col2=caixa do ano). Col1 (o botão "Criar/Salvar exercício" e, por partilhar a mesma
   grelha, também a etiqueta do ano nas linhas já existentes) mede 1/3 da largura que ocupava antes
   (quando era 1fr, ou seja, "100% menos col2 menos o gap") menos mais 5px — pedido explícito. Col2
   (botão Eliminar / caixa do ano) mantém a mesma largura (110px) e o mesmo gap (8px) de sempre; como
   col1 encolheu bastante, col2 acaba a "encostar mais à esquerda" (mais perto do início da linha) em
   vez de ficar empurrada para a direita como antes. */
.exercicio-row-grid{display:grid; grid-template-columns:calc((100% - 110px - 8px)/3 - 5px) 110px; align-items:center; gap:8px;}
/* Campo destacado — usado quando um input aparece de propósito para chamar a atenção (ex.: o campo
   do ano ao clicar "Criar exercício"), sem inventar uma cor nova: reaproveita --accent-2 (o mesmo azul
   de .btn.rust) + o glow de foco já usado no resto da app. */
.input-destaque{border-color:var(--accent-2) !important; box-shadow:var(--glow-sm);}
/* min-width:0 evita o "grid blowout": sem isto, um <select>/<input> dentro de uma coluna 1fr impõe
   a sua largura intrínseca mínima à faixa da grid, e a grid inteira (e a página) fica mais larga do
   que o ecrã em vez de encolher — a partir daqui, colunas 1fr encolhem sempre que for preciso. */
.grid > *{min-width:0;}
.field{margin-bottom:12px; min-width:0;}
.hint{font-size:11.5px; color:var(--text-muted); margin-top:4px; line-height:1.5;}

/* Gráficos — área de trabalho densa, com propriedades sempre ao lado da pré-visualização. */
.grafico-cabecalho{display:flex; align-items:flex-start; justify-content:space-between; gap:18px;}
.grafico-cabecalho h2{margin:0 0 4px;}
.grafico-card{padding:0; overflow:hidden;}
.grafico-card-topo{min-height:58px; display:flex; align-items:center; justify-content:space-between; gap:14px; padding:12px 16px; border-bottom:1px solid var(--border); background:var(--bg-subtle);}
.grafico-card-topo h3{margin:0; font-size:16px;}
.grafico-card-acoes{display:flex; gap:8px; flex-wrap:wrap;}
.grafico-editor{display:grid; grid-template-columns:minmax(250px, 340px) minmax(0,1fr); min-height:390px;}
.grafico-propriedades{padding:16px; border-right:1px solid var(--border); overflow:auto; max-height:620px;}
.grafico-preview{position:relative; min-height:390px; padding:34px 18px 18px; background:var(--bg-page);}
.grafico-canvas{width:100%; height:330px; max-width:100%; margin:0 auto;}
.grafico-preview-etiqueta{position:absolute; top:12px; left:18px; color:var(--text-muted); font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.06em;}
.grafico-series{margin:0 0 14px; padding:10px 12px 8px; border:1px solid var(--border); border-radius:var(--radius-sm);}
.grafico-series legend{padding:0 4px; font-size:12px; font-weight:700; color:var(--text-primary);}
.grafico-check{display:flex; align-items:center; gap:6px; margin:6px 0; font-size:12px; font-weight:500; text-transform:none; letter-spacing:normal; cursor:pointer;}
.grafico-cores{display:flex; gap:7px; flex-wrap:wrap; margin-top:8px;}
.grafico-cores input{width:28px; height:28px; padding:2px; border-radius:var(--radius-sm); cursor:pointer;}
.grafico-vazio{margin-top:16px; padding:28px; border:1px dashed var(--border-strong); color:var(--text-muted); text-align:center; background:var(--bg-subtle);}
@media (max-width:820px){.grafico-cabecalho{flex-direction:column;}.grafico-editor{grid-template-columns:1fr;}.grafico-propriedades{border-right:0;border-bottom:1px solid var(--border);max-height:none;}.grafico-preview{min-height:300px;}.grafico-canvas{height:270px;}}

/* ======================= BOTÕES =======================
   Cantos a --radius (9px, não pill) — um botão de texto não é um "controlo pequeno"; o pill fica
   reservado a badges/avatar/switch. Sem glow no hover: a mudança de cor sólida já basta como feedback. */
.btn{
  font-family:'IBM Plex Sans',sans-serif; font-weight:600; font-size:13px; padding:10px 18px; border-radius:var(--radius); border:1px solid var(--accent-strong);
  background:var(--accent-strong); color:var(--accent-ink); cursor:pointer; display:inline-flex; align-items:center; gap:7px; line-height:1.2;
  transition:background .13s, color .13s, border-color .13s, transform .13s;
}
.btn .icon{flex-shrink:0;}
.btn:hover{ background:var(--accent); border-color:var(--accent); }
.btn:active{ background:var(--accent-strong); transform:scale(.98); }
.btn.primary{background:var(--accent-strong); border-color:var(--accent-strong); color:var(--accent-ink);}
.btn.primary:hover{background:var(--accent); border-color:var(--accent);}
.btn.secondary{background:transparent; color:var(--text-primary); border-color:var(--border-strong);}
.btn.secondary:hover{ background:var(--bg-subtle); border-color:var(--text-muted); }
.btn.ledger{background:var(--accent-strong); border-color:var(--accent-strong); color:var(--accent-ink);}
.btn.ledger:hover{ background:var(--accent); border-color:var(--accent); }
.btn.rust{background:var(--accent-2); border-color:var(--accent-2); color:var(--accent-ink);}
.btn.rust:hover{ background:var(--c-inkblue-800); border-color:var(--c-inkblue-800); }
.btn.highlight{background:var(--accent-2-tint); border-color:var(--accent-2); color:var(--accent-2); font-weight:700;}
.btn.highlight:hover{ background:var(--accent-2); border-color:var(--accent-2); color:var(--accent-ink); }
.btn.danger{background:transparent; border-color:var(--danger-border); color:var(--danger);}
.btn.danger:hover{background:var(--danger-tint); border-color:var(--danger);}
/* Variante preenchida — só para quando a ação destrutiva É a ação primária do ecrã/diálogo (ex.: o
   botão "Eliminar" de um modal de confirmação), nunca dentro de uma lista/linha, onde .btn.danger
   (contorno) já basta e não deve competir visualmente com o resto da fila de ações. */
.btn.danger-solid{background:var(--danger); border-color:var(--danger); color:#fff;}
.btn.danger-solid:hover{background:var(--danger-strong); border-color:var(--danger-strong);}
.btn.ghost{background:transparent; color:var(--accent-2); border-color:transparent; font-size:12.5px; padding:7px 10px;}
.btn.ghost:hover{ background:var(--accent-2-tint); }
.btn.icon-btn{padding:9px; width:36px; justify-content:center;}
/* Alvo de toque mínimo recomendado (~44px, Apple HIG/Material) em dispositivos touch — nunca em
   ecrã com rato/trackpad, onde 36px já é confortável e maior mudaria a densidade visual à toa. */
@media (pointer:coarse){ .btn.icon-btn{ width:44px; height:44px; } }
label.btn{text-transform:none; font-size:13px; font-weight:600; letter-spacing:normal; color:var(--accent-ink); margin-bottom:0;}
label.btn.secondary{color:var(--text-primary);}
.btn:disabled{opacity:.45; cursor:not-allowed; box-shadow:none;}
.btn-row{display:flex; gap:10px; justify-content:flex-end; margin-top:20px; flex-wrap:wrap;}
.btn-row.split{justify-content:space-between;}

.dropzone{border:1.5px dashed var(--border-strong); border-radius:var(--radius); padding:28px 18px; text-align:center; cursor:pointer; transition:border-color .12s, background .12s; color:var(--text-muted);}
.dropzone:hover, .dropzone.drag{border-color:var(--accent-2); background:var(--accent-2-tint);}
/* Fonte de dados ainda por carregar — pisca com uma cor chamativa (vermelho de aviso) enquanto o
   utilizador estiver nesta secção, para nunca passar despercebido que falta alimentar essa fonte.
   Pára de piscar sozinho assim que a fonte deixa de estar vazia (deixa de receber esta classe). */
@keyframes fc-dropzone-pulse{
  0%, 100%{ border-color:var(--border-strong); box-shadow:0 0 0 0 transparent; }
  50%{ border-color:var(--danger-strong); box-shadow:0 0 0 4px var(--danger-tint); }
}
.dropzone.dropzone-pendente{ animation:fc-dropzone-pulse 1.8s ease-in-out infinite; }
.dropzone.dropzone-pendente:hover, .dropzone.dropzone-pendente.drag{ animation:none; border-color:var(--accent-2); background:var(--accent-2-tint); }
@media (prefers-reduced-motion: reduce){
  .dropzone.dropzone-pendente{ animation:none; border-color:var(--danger-strong); border-width:2px; }
}
.dropzone .icon{margin:0 auto 8px; color:var(--text-muted);}
.dropzone .main{font-weight:600; font-size:13.5px; color:var(--text-primary);}
.dropzone .sub{color:var(--text-muted); font-size:11.5px; margin-top:3px;}
.file-chip{display:inline-flex; align-items:center; gap:8px; background:var(--bg-subtle); color:var(--text-secondary); padding:6px 12px; border-radius:var(--radius-pill); font-size:12.5px; font-weight:600; margin-top:10px; border:1px solid var(--border);}
.file-chip button{background:none; border:none; color:var(--text-muted); cursor:pointer; display:inline-flex; padding:0;}
.file-chip button:hover{color:var(--danger);}

.balancete-block{border:1px solid var(--border); border-radius:var(--radius); padding:18px; margin-bottom:14px; background:var(--bg-surface);}
.balancete-block h3{font-size:14px; margin:0 0 4px; display:flex; align-items:center; gap:8px; color:var(--text-primary); font-weight:700;}
.balancete-block .tag{font-size:10px; color:var(--text-muted); font-weight:500;}
.skip-row{display:flex; align-items:center; gap:8px; margin-bottom:12px;}
.skip-row input{width:auto;}
.skip-row label{margin:0; text-transform:none; font-weight:500; letter-spacing:0; color:var(--text-primary); font-size:13px;}

/* ======================= TABELAS =======================
   width:auto (em vez de 100%) — a tabela nunca estica artificialmente para preencher o espaço
   disponível; fica do tamanho que o seu conteúdo real precisa (poucas colunas → tabela compacta),
   crescendo apenas conforme as colunas/valores precisarem. Scroll horizontal só aparece (via
   .table-scroll/.doc-fixo-preview, que envolvem a tabela) quando o conteúdo real ultrapassa o espaço
   disponível — nunca antes disso. */
table{width:auto; max-width:100%; border-collapse:collapse; font-size:12.5px;}
th{
  text-align:left; padding:9px 10px; font-size:10.5px; text-transform:uppercase; letter-spacing:.045em; color:var(--text-muted);
  font-weight:700; background:var(--bg-subtle); position:sticky; top:0; border-bottom:1px solid var(--border-strong);
  white-space:normal; word-wrap:break-word; overflow-wrap:break-word; vertical-align:middle;
}
td{padding:8px 10px; border-bottom:1px solid var(--border); vertical-align:middle; overflow-wrap:break-word; word-break:break-word; color:var(--text-primary);}
tbody tr:nth-child(even) td{ background:var(--bg-subtle); }
tbody tr:hover td{ background:var(--accent-2-tint); }
.num{text-align:right; white-space:nowrap; font-variant-numeric:tabular-nums;}
.table-scroll{max-height:360px; overflow:auto; border:1px solid var(--border); border-radius:var(--radius);}
/* Pré-visualizações (Notas, Balanço): espaçamento mínimo (2px) entre as caixas de cada coluna —
   assim as caixas ficam mesmo coladas aos limites da coluna, alinhadas com a linha de Total. */
.table-scroll th{padding:2px;}
.table-scroll td{padding:2px;}
.table-scroll .mini-input{padding:4px 6px;}
/* Régua dupla no fundo — a mesma convenção contabilística de sempre para fechar um total (nunca
   inventada por este design system: é como qualquer folha de cálculo/livro-razão fecha uma soma). Uma
   única régua acima separa o total das linhas que soma. */
.row-total td{border-top:1px solid var(--border-strong); border-bottom:3px double var(--text-primary); font-weight:700; background:var(--bg-subtle-strong);}
tbody tr[data-row]{cursor:pointer;}
tbody tr[data-row].row-selected td{background:var(--accent-2-tint);}
/* Subcontas expandidas preservam a formatação das linhas normais; só a rubrica
   recebe avanço de 0,4 cm para evidenciar a hierarquia. */
.parent-expanded td{font-weight:700;}
.parent-expanded td .mini-input{font-weight:700;}
.child-row td{font-style:italic;}
.child-row-label{padding-left:calc(2px + .4cm) !important;}
.mini-input{padding:5px 7px; font-size:12px; border-radius:var(--radius-sm); width:100%;}
.mini-input.manual{background:var(--warning-tint); border-color:var(--warning-border);}
/* .col-desc-primeira (truncamento com reticências + tooltip) fica sempre na 1ª coluna de uma tabela
   de Notas às Contas/Relatórios Mensais, tenha ela largura própria (régua, ver larguraEfetivaColunaPx
   em script.js) ou não; só .col-desc-fixed acrescenta o piso/teto rígido de 8cm — aplicada só enquanto
   o utilizador nunca arrastou a régua PARA esta coluna especificamente (col0TemLarguraPropria, em
   renderTabelaPreview), para não voltar a prender a largura assim que ele a redimensiona. */
.mini-input.col-desc-primeira{overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.mini-input.col-desc-fixed{width:8cm; min-width:8cm; max-width:8cm;}
/* Quinta dos Reis — o select de "Modo" (Aplicar margem→PVP / Definir PVP alvo→margem) tem texto
   mais comprido do que os outros campos dessa tabela densa; sem isto esticaria a coluna toda. */
.qr-margem-modo-select{max-width:220px;}
/* Quinta dos Reis — tabelas de lançamento (Registar Movimento / Consultar Lançamentos): +2px de
   altura por linha (pedido explícito), para facilitar a leitura em ecrãs de trabalho. */
.qr-tabela-lancamentos td, .qr-tabela-lancamentos th{padding:4px 10px;}
/* Tabelas/quadros de Notas às Contas e Relatórios Mensais (renderTabelaPreview, script.js) — pedido
   explícito: fonte Calibri 10 por padrão no cabeçalho/linhas/linha de Total, e bordas de linha SEMPRE
   transparentes — só o cabeçalho/Total ganham borda superior+inferior, e só quando o Tema Visual
   (Preenchido/Contorno) a define (ver bordaTemaContornoCss/thStyle/bordaTotCss, inline por célula, que
   continuam a vencer esta base transparente sempre que aplicável). Altura da linha — pedido explícito:
   "a altura de cada linha deve ter 4px a mais para baixo ou cima em relação ao seu conteúdo... não
   pode ter mais espaço do que essa configuração" — `padding-top`/`padding-bottom:4px` (vence o
   `padding:2px` genérico de `.table-scroll th/td`, acima, por vir depois no ficheiro com a mesma
   especificidade — só top/bottom, o padding horizontal de 2px mantém-se) é a ÚNICA fonte de espaço
   vertical extra; removido o antigo `height:14px` (um piso fixo, à parte do padding, que contradizia
   "não pode ter mais espaço do que essa configuração" — a altura da linha passa a ser sempre
   `conteúdo + 8px`, nunca mais do que isso). `!important` no tamanho dos inputs é necessário para
   vencer a regra `.table-scroll input,.table-scroll select,.mini-input{font-size:12px !important;}`
   (linha 554, acima) que senão manteria 12px dentro desta tabela em concreto. */
.tabela-quadro-notas th, .tabela-quadro-notas td{
  font-family:Calibri,'Trebuchet MS',Arial,sans-serif; font-size:10pt;
  padding-top:4px; padding-bottom:4px;
  border-top:1px solid transparent; border-bottom:1px solid transparent;
}
.tabela-quadro-notas th,
.tabela-quadro-notas td,
.tabela-quadro-notas input.mini-input,
.tabela-quadro-notas select,
.cr-preview-table th,
.cr-preview-table td{
  text-transform:none;
  letter-spacing:normal;
}
.tabela-quadro-notas th{padding-top:3px; padding-bottom:3px;}
.tabela-quadro-notas tr.linha-negrito input,
.tabela-quadro-notas tr.linha-negrito select{font-weight:700 !important;}
.tabela-quadro-notas.sem-linhas-dados td{border-top-color:transparent !important; border-bottom-color:transparent !important;}
.tabela-quadro-notas .subtotal-row td{font-weight:700; background:var(--bg-subtle);}
.tabela-quadro-notas .linha-vazia td{height:18px;}
.tabela-quadro-notas input.mini-input, .tabela-quadro-notas select{
  font-family:Calibri,'Trebuchet MS',Arial,sans-serif !important; font-size:10pt !important;
}
/* Quinta dos Reis — Consultar Stock: a tabela herdava o padding de 2px pensado para as pré-visualizações
   densas de Notas/Balanço (ver §2.4 do CLAUDE.md) — sufocava o texto numa tabela de só 4 colunas, com
   muito espaço livre por preencher no ecrã. Padding mais generoso + colgroup (ver script.js) para as
   colunas usarem a largura disponível em vez de encolherem ao conteúdo. */
.qr-tabela-stock td, .qr-tabela-stock th{padding:10px 16px;}
/* Quinta dos Reis — Registar Movimento em accordion no mobile (ver trQrRegistroLinha/
   renderQrRegistarPanel em script.js). No desktop (>680px), ".qr-cell-toggle-wrap" fica sempre
   escondida (só existe para o layout de cartão) — o Tipo já não repete por linha em lado nenhum
   (é escolhido uma única vez no cabeçalho do formulário, para o lote inteiro). */
.qr-tabela-registo .qr-cell-toggle-wrap,
.qr-tabela-registo thead th:nth-child(4){ display:none; }
@media (max-width:680px){
  .qr-tabela-registo thead{ display:none; }
  .qr-tabela-registo, .qr-tabela-registo tbody{ display:block; width:100%; }
  .qr-tabela-registo tr{
    display:flex; flex-wrap:wrap; align-items:center; gap:8px 10px;
    border:1px solid var(--border); border-radius:var(--radius); padding:10px 12px; margin-bottom:10px;
    background:var(--bg-surface);
  }
  .qr-tabela-registo td{ display:block; padding:0; border:none; }
  /* Artigo — recolhido, fica sempre visível, com fundo destacado para se distinguir logo do resto do
     cartão (pedido explícito: "destaque o background do artigo"). */
  .qr-tabela-registo .qr-cell-artigo{
    order:1; flex:1 1 100%; min-width:0;
    background:var(--accent-tint); border-radius:var(--radius-sm); padding:6px 8px;
  }
  .qr-tabela-registo .qr-cell-artigo select{ width:100%; }
  /* Unidade — sempre visível no resumo (recolhido), no lugar onde antes estava o badge de Tipo. */
  .qr-tabela-registo .qr-cell-un{
    display:inline-flex; order:2; font-size:12px; font-weight:600; padding:2px 10px;
    border-radius:var(--radius-pill); background:var(--bg-subtle); color:var(--text-muted);
  }
  .qr-tabela-registo .qr-cell-qtd{ order:3; margin-left:auto; width:120px; }
  .qr-tabela-registo .qr-cell-qtd input{ width:100%; }
  .qr-tabela-registo .qr-cell-toggle-wrap{ display:block; order:4; }
  .qr-tabela-registo .qr-cell-toggle{
    display:flex; align-items:center; justify-content:center; width:30px; height:30px;
    border:1px solid var(--border-strong); border-radius:var(--radius-sm); background:transparent; color:var(--text-muted);
    cursor:pointer; transition:transform .15s;
  }
  .qr-tabela-registo tr.qr-row-expanded .qr-cell-toggle{ transform:rotate(180deg); }
  .qr-tabela-registo .qr-cell-detail{ order:5; flex:1 1 100%; display:none; }
  .qr-tabela-registo tr.qr-row-expanded .qr-cell-detail{ display:block; }
  .qr-tabela-registo .qr-cell-detail[data-label]::before{
    content:attr(data-label) ':'; display:block; font-size:11px; font-weight:600; color:var(--text-muted); margin-bottom:3px;
  }
  .qr-tabela-registo .qr-cell-detail input{ width:100%; }
  .qr-tabela-registo .qr-cell-del{ display:flex; justify-content:flex-end; }
}
/* Quinta dos Reis — Margem Bruta de Venda em lista de cards no mobile: cada linha vira um cartão com
   os campos empilhados (nunca em grelha 2 colunas — o texto do "Modo" é comprido de mais para meia
   largura sem ficar cortado), rótulo por cima de cada campo via data-label (mesmo padrão do accordion
   de Registar Movimento, acima). */
@media (max-width:680px){
  .qr-tabela-margem thead{ display:none; }
  .qr-tabela-margem, .qr-tabela-margem tbody{ display:block; width:100%; }
  .qr-tabela-margem tr{
    display:flex; flex-direction:column; gap:10px;
    border:1px solid var(--border); border-radius:var(--radius); padding:12px; margin-bottom:10px; background:var(--bg-surface);
  }
  .qr-tabela-margem td{ display:block; padding:0; border:none; }
  .qr-tabela-margem td[data-label]::before{
    content:attr(data-label) ':'; display:block; font-size:11px; font-weight:600; color:var(--text-muted); margin-bottom:3px;
  }
  .qr-tabela-margem input, .qr-tabela-margem select{ width:100%; }
  .qr-tabela-margem .qr-margem-modo-select{ max-width:none; }
  .qr-tabela-margem td:last-child{ display:flex; justify-content:flex-end; }
}
/* Campo de valor com máscara (moeda/percentagem, ver criarInputValorMask em script.js) — alinha à
   direita como qualquer outro campo numérico da app. */
.qr-input-valor{text-align:right;}
/* Campo de data digitável (DD/MM/AAAA) + botão de calendário — o <input type=date> nativo fica
   presente no DOM (para o showPicker() funcionar) mas visualmente escondido; só o campo de texto e o
   botão do calendário são visíveis. */
.qr-data-wrap{display:flex; align-items:center; gap:4px;}
.qr-data-wrap .qr-data-texto{width:100px; flex:0 0 auto;}
.qr-data-wrap .qr-data-nativo{position:absolute; width:1px; height:1px; opacity:0; pointer-events:none;}
.qr-data-wrap .qr-data-btn{flex:0 0 auto;}
/* .col-value-min já não impõe uma largura mínima fixa — a largura de cada coluna de valor vem do
   colgroup (ver estimarLarguraColunaPx em script.js para as Notas; state.colWidths, lido do próprio
   ficheiro, para o Balanço/Demonstração de Resultados); a classe continua a existir só para o
   autoSizeInput saber que esta caixa deve preencher sempre 100% da coluna (ver comentário em autoSizeInput). */
.doc-fixo-preview{max-height:720px;}
/* table-layout:fixed obriga o browser a respeitar o colgroup (larguras reais do Excel, ver
   renderDocFixoPanel) em vez de alargar colunas ao conteúdo — visão muito mais parecida com o ficheiro.
   Partilhada pelo Balanço e pela Demonstração de Resultados — mesma lógica de documento de layout fixo. */
.doc-fixo-table{table-layout:fixed;}
.doc-fixo-table td{white-space:normal;}

.rubrica-row{display:flex; gap:10px; align-items:center; padding:9px 0; border-bottom:1px solid var(--border); flex-wrap:wrap;}
.rubrica-row:last-child{border-bottom:none;}
.rubrica-row input{width:auto; min-width:4ch;}
.rubrica-row .del-btn{background:transparent; border:1px solid var(--border-strong); color:var(--text-muted); border-radius:var(--radius-sm); cursor:pointer; height:32px; width:32px; margin-left:auto; flex-shrink:0; display:inline-flex; align-items:center; justify-content:center; transition:background .12s, border-color .12s, color .12s;}
.rubrica-row .del-btn:hover{ background:var(--danger-tint); border-color:var(--danger-border); color:var(--danger); }
/* Botão de eliminar linha dentro de uma célula de tabela (Quinta dos Reis: Registar Movimento,
   Margem) — nunca tinha estilo próprio fora de .rubrica-row, ficava "nu". Mesmo tratamento visual. */
td .del-btn{background:transparent; border:1px solid var(--border-strong); color:var(--text-muted); border-radius:var(--radius-sm); cursor:pointer; height:28px; width:28px; display:inline-flex; align-items:center; justify-content:center; transition:background .12s, border-color .12s, color .12s;}
td .del-btn:hover{background:var(--danger-tint); border-color:var(--danger-border); color:var(--danger);}
.rubrica-head{display:flex; gap:10px; font-size:11px; text-transform:uppercase; letter-spacing:.03em; color:var(--text-muted); font-weight:600; padding-bottom:8px; border-bottom:1px solid var(--border-strong); margin-bottom:4px;}
.rubrica-head > div{min-width:120px;}

.badge{display:inline-flex; align-items:center; gap:6px; padding:4px 10px; border-radius:var(--radius-pill); font-size:11.5px; font-weight:700; font-variant-numeric:tabular-nums;}
.badge.ok{background:var(--success-tint); color:var(--success-strong); border:1px solid var(--success-border);}
.badge.bad{background:var(--danger-tint); color:var(--danger-strong); border:1px solid var(--danger-border);}
.badge.warn{background:var(--warning-tint); color:var(--warning-strong); border:1px solid var(--warning-border);}

.section-title{font-size:14px; font-weight:700; margin:22px 0 10px; padding-bottom:7px; border-bottom:1px solid var(--border-strong); display:flex; justify-content:space-between; align-items:baseline; color:var(--text-primary);}
.section-title .tag{font-size:10px; color:var(--text-muted); font-weight:400;}

/* ======================= ALERTAS — ícone por tipo, sem emoji ======================= */
.alert{position:relative; padding:11px 14px 11px 40px; border-radius:var(--radius-sm); font-size:12.5px; margin-bottom:12px; line-height:1.55; border:1px solid var(--border); background:var(--bg-subtle); color:var(--text-secondary);}
.alert::before{content:''; position:absolute; left:13px; top:12px; width:16px; height:16px; background-repeat:no-repeat; background-position:center; background-size:16px;}
.alert.info{background:var(--accent-2-tint); border-color:var(--accent-2); color:var(--text-primary);}
.alert.info::before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230E6E77' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 11.08V12a10 10 0 1 1-5.93-9.14'/%3E%3Cpolyline points='22 4 12 14.01 9 11.01'/%3E%3C/svg%3E");}
.alert.warn{background:var(--danger-tint); border-color:var(--danger-border); color:var(--danger-strong);}
.alert.warn::before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23C0362A' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z'/%3E%3Cline x1='12' y1='9' x2='12' y2='13'/%3E%3Cline x1='12' y1='17' x2='12.01' y2='17'/%3E%3C/svg%3E");}
.alert.amber{background:var(--warning-tint); border-color:var(--warning-border); color:var(--warning-strong);}
.alert.amber::before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23AD7A0C' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z'/%3E%3Cline x1='12' y1='9' x2='12' y2='13'/%3E%3Cline x1='12' y1='17' x2='12.01' y2='17'/%3E%3C/svg%3E");}
.alert.plain{background:var(--bg-subtle); border-color:var(--border); color:var(--text-secondary);}
.alert.plain::before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' y1='16' x2='12' y2='12'/%3E%3Cline x1='12' y1='8' x2='12.01' y2='8'/%3E%3C/svg%3E");}

.manual-panel{border:1px dashed var(--warning-border); background:var(--warning-tint); border-radius:var(--radius); padding:16px 18px; margin:14px 0;}
.manual-panel .ttl{font-weight:700; font-size:12.5px; color:var(--warning-strong); text-transform:uppercase; letter-spacing:.03em; margin-bottom:10px; display:flex; align-items:center; gap:7px;}

.kpi-grid{display:grid; grid-template-columns:repeat(3,1fr); gap:14px; margin:16px 0;}
@media (max-width:760px){ .kpi-grid{grid-template-columns:1fr;} }
.kpi{border:1px solid var(--border); border-radius:var(--radius); padding:14px 16px; background:var(--bg-subtle);}
.kpi .label{font-size:10.5px; text-transform:uppercase; letter-spacing:.03em; color:var(--text-muted); font-weight:600;}
.kpi .value{font-size:18px; font-weight:700; margin-top:4px; font-variant-numeric:tabular-nums; color:var(--text-primary);}

/* NOTES SCREEN LAYOUT */
.notes-layout{display:grid; grid-template-columns:250px 1fr; gap:20px;}
@media (max-width:900px){ .notes-layout{grid-template-columns:1fr;} }
/* min-width:0 nos itens da grid — sem isto, o conteúdo do editor de notas (nomes de linha, contas,
   fórmulas) impõe a sua própria largura mínima à faixa "1fr" e a grid recusa-se a encolher abaixo
   disso, arrastando o cartão/página inteiros para uma largura maior do que o ecrã. Com isto, a faixa
   encolhe sempre que precisar e cada peça de conteúdo que ainda precisar de mais espaço (ex.: a
   pré-visualização da tabela) trata do seu próprio scroll internamente (.table-scroll). */
.notes-layout > *{min-width:0;}
.notes-sidebar{border:1px solid var(--border); border-radius:var(--radius); background:var(--bg-surface); max-height:640px; overflow:auto;}
.note-item{padding:10px 14px; font-size:12.5px; cursor:pointer; border-bottom:1px solid var(--border); display:flex; justify-content:space-between; align-items:center; gap:6px; border-left:2px solid transparent; color:var(--text-secondary);}
.note-item:last-child{border-bottom:none;}
.note-item:hover:not(.active){ background:var(--bg-subtle); }
.note-item.active{background:var(--accent-2-tint); color:var(--accent-2); font-weight:700; border-left-color:var(--accent-2);}
.note-item.disabled{color:var(--text-muted); cursor:not-allowed;}
.note-item .tag-mini{font-size:9px; background:var(--bg-subtle-strong); padding:1px 6px; border-radius:4px; color:var(--text-muted); flex-shrink:0;}

.collapsible-header{display:flex; justify-content:space-between; align-items:center; cursor:pointer; padding:10px 14px; background:var(--bg-subtle); border:1px solid var(--border); border-radius:var(--radius-sm); transition:border-color .12s, background-color .12s;}
.collapsible-header:hover{ border-color:var(--border-strong); background:var(--bg-subtle-strong); }
.collapsible-title{display:inline-flex; align-items:center; gap:8px; font-weight:600; font-size:13px; color:var(--text-primary);}
.collapsible-header .chev{transition:transform .15s; color:var(--text-muted); display:inline-flex;}
.collapsible-header.collapsed .chev{transform:rotate(-90deg);}
.collapsible-body{padding:16px 2px 4px;}

.stub-panel{text-align:center; padding:56px 20px; color:var(--text-muted);}
.stub-panel .icon{margin:0 auto 14px; width:56px; height:56px; display:flex; align-items:center; justify-content:center; border-radius:var(--radius-lg); background:var(--bg-subtle); color:var(--accent);}
.stub-panel .ttl{font-size:16px; font-weight:700; color:var(--text-primary); margin-bottom:6px;}
.stub-panel .txt{font-size:13px; max-width:440px; margin:0 auto; line-height:1.55;}

/* ---------- Auth screen ----------
   Fundo liso (--bg-page), sem glow/gradiente radial decorativo — o antigo halo suave ancorado no
   topo era o mesmo truque genérico de qualquer ecrã de login gerado por IA (glow de acento a esbater
   para o fundo). O selo + tipografia + bloco de confiança já dão presença suficiente ao cartão; um
   fundo plano lê-se mais confiante do que um fundo decorado. Sem padrões decorativos (sem
   grelhas/riscas) e sem a antiga faixa de 3px no topo do cartão. */
.auth-screen{
  min-height:100vh; display:flex; align-items:center; justify-content:center; padding:24px;
  background:var(--bg-page);
}
/* Sem borda — só sombra (elevação "flutuante" genuína, não o padrão "ghost card" de borda+sombra
   larga ao mesmo tempo). Cantos a 16px (não 20px): teto do design system para cartões. */
.auth-card{background:var(--bg-surface); border-radius:var(--radius-lg); box-shadow:var(--shadow-md); padding:44px 32px 34px; width:100%; max-width:408px; text-align:center; position:relative;}
.auth-title{font-size:27px; font-weight:700; margin:0 0 2px; color:var(--text-primary); letter-spacing:-0.03em;}
.auth-sub{color:var(--text-muted); font-size:13px; margin-bottom:22px;}
.auth-card .field{text-align:left;}
/* Prefixo fixo "+244" colado ao input de telemóvel — mesma filosofia de "nunca deixar o formato
   ambíguo" já usada no seletor Dia/Mês/Ano dos relatórios (ver CLAUDE.md) em vez de confiar num
   <input type=tel> livre. */
.phone-input-row{display:flex; align-items:stretch;}
.phone-prefix{display:flex; align-items:center; padding:0 10px; border:1px solid var(--border-strong); border-right:none; border-radius:var(--radius-sm) 0 0 var(--radius-sm); background:var(--bg-subtle); color:var(--text-muted); font-size:13px; font-weight:600; white-space:nowrap;}
.phone-input-row input{border-radius:0 var(--radius-sm) var(--radius-sm) 0;}
/* Texto + link em destaque para trocar entre "Entrar"/"Criar conta" — substitui as antigas abas
   (o ecrã abre sempre direto em "Entrar", sem escolha inicial). */
.auth-switch-text{margin-top:14px; font-size:12.5px; color:var(--text-muted); text-align:center;}
.auth-switch-link{margin-left:4px; font-weight:700; color:var(--accent); text-decoration:none; cursor:pointer;}
.auth-switch-link:hover{text-decoration:underline;}
/* Selo de confiança (processamento local) — reforça, com um ícone + texto dedicados, a única garantia
   de segurança real que a app pode dar (nada sai do browser); deliberadamente mais visível do que um
   .hint normal, mas sem inventar nenhuma alegação que a app não cumpra. */
.auth-trust{display:flex; align-items:flex-start; gap:8px; text-align:left; margin-top:18px; padding:10px 12px; border-radius:var(--radius-sm); background:var(--bg-subtle); border:1px solid var(--border); color:var(--text-secondary); font-size:11.5px; line-height:1.5;}
.auth-trust .icon{flex-shrink:0; margin-top:1px; color:var(--accent-2);}
.legal-links{display:flex; align-items:center; justify-content:center; flex-wrap:wrap; gap:7px; color:var(--text-muted); font-size:11.5px; line-height:1.5;}
.legal-links a{color:var(--accent-2); text-decoration:underline; text-decoration-color:transparent; text-underline-offset:3px; transition:text-decoration-color .16s ease,color .16s ease;}
.legal-links a:hover{text-decoration-color:currentColor; color:var(--accent);}
.legal-links a:focus-visible{outline:2px solid var(--focus-ring); outline-offset:3px; border-radius:2px;}
.legal-links-auth{margin-top:16px;}

/* ---------- Login: "esqueci a senha" / regras de senha / Google ---------- */
.auth-forgot-link{text-align:right; margin-top:6px;}
.auth-forgot-link a, .auth-back-link a{font-size:12px; font-weight:600; color:var(--accent); text-decoration:none; cursor:pointer;}
.auth-forgot-link a:hover, .auth-back-link a:hover{text-decoration:underline;}
.auth-back-link{text-align:left; margin-bottom:6px;}
.password-rules{display:flex; flex-direction:column; gap:4px; margin:-4px 0 14px; padding:9px 11px; border-radius:var(--radius-sm); background:var(--bg-subtle); border:1px solid var(--border);}
.password-rule{font-size:11.5px; color:var(--text-muted); display:flex; align-items:center; gap:6px; transition:color .15s;}
.password-rule::before{content:''; flex-shrink:0; width:6px; height:6px; border-radius:50%; background:var(--text-muted); transition:background .15s;}
.password-rule.met{color:var(--success-strong);}
.password-rule.met::before{background:var(--success-strong);}
.auth-divider{display:flex; align-items:center; gap:10px; margin:16px 0; color:var(--text-muted); font-size:11.5px;}
.auth-divider::before, .auth-divider::after{content:''; flex:1; height:1px; background:var(--border);}
#btnAuthGoogle{color:var(--text-primary); background:var(--bg-surface); border-color:var(--border);}
#btnAuthGoogle:hover{background:var(--bg-subtle);}

/* ---------- Menu screen ----------
   Mesma paleta navy/petróleo de sempre — "emprestar a energia" de uma landing calorosa sem trocar de
   cor: cantos mais arredondados, tipografia de boas-vindas maior, cartões com mais respiração/hover
   mais vivo, e UM único toque pontual de glass na barra fixa do topo (não um padrão espalhado pela
   app — glassmorphism como decoração por todo o lado está deliberadamente fora do vocabulário desta
   app financeira). */
.menu-screen{min-height:100vh; padding:0; background:var(--bg-page);}
/* O topbar/conteúdo já não têm max-width/margin:auto próprios — preenchem sempre a largura
   disponível de #screenMenu (já deslocado da sidebar fixa via .screen-with-sidebar). */
/* Margens/padding verticais reduzidos a metade (margin-bottom 28→14, padding vertical 16→8) — mesmo
   pedido explícito já aplicado ao .masthead (ver acima), aqui no equivalente do ecrã Menu. */
.menu-topbar{
  margin:0 0 14px; display:flex; justify-content:space-between; align-items:center; gap:12px; flex-wrap:wrap;
  padding:max(8px, env(safe-area-inset-top)) 28px 8px; position:sticky; top:0; z-index:var(--z-sticky);
  background:var(--chrome-bg); color:var(--chrome-text); border-bottom:1px solid var(--chrome-border);
  box-shadow:var(--shadow-sm);
}
.menu-welcome-title{font-size:24px; font-weight:800; letter-spacing:-0.03em; margin:0; color:var(--chrome-text);}
.menu-topbar .sub, .menu-topbar p{color:var(--chrome-text-muted);}
.app-content{padding:0 28px 48px;}
.menu-section-label{margin:0 0 12px; font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.06em; color:var(--text-muted);}
.menu-status-grid + .menu-section-label{margin-top:34px;}
/* Uma única barra de estado (não 4 cartões idênticos repetidos) — mesmos 4 dados reais de sempre,
   agora como grupos dentro de UM cartão, separados por divisórias em vez de 4 sombras/bordas
   independentes; lê-se como um resumo, não como uma grelha de métricas genérica. */
.menu-status-grid{margin:0 0 32px; display:flex; flex-wrap:wrap; background:var(--bg-surface); border:1px solid var(--border); border-radius:var(--radius); box-shadow:var(--shadow-sm);}
.status-bar-item{flex:1 1 220px; display:flex; gap:12px; align-items:flex-start; padding:16px 20px; border-right:1px solid var(--border);}
.status-bar-item:last-child{border-right:none;}
@media (max-width:820px){
  .status-bar-item{flex-basis:50%; border-right:1px solid var(--border);}
  .status-bar-item:nth-child(2n){border-right:none;}
  .status-bar-item:nth-last-child(-n+2){border-bottom:none;}
  .status-bar-item{border-bottom:1px solid var(--border);}
}
@media (max-width:520px){ .status-bar-item{flex-basis:100%; border-right:none;} }
.status-card-ic{width:34px; height:34px; flex-shrink:0; border-radius:var(--radius-sm); background:var(--accent-2-tint); color:var(--accent-2); display:flex; align-items:center; justify-content:center;}
/* min-width:0 — o outro filho flex de `.status-bar-item` (ao lado do ícone, de largura fixa acima);
   sem isto herda min-width:auto e não encolhe abaixo do seu texto mais comprido, empurrando para fora
   de painéis estreitos (ver comentário em `.conc-split-side .status-bar-item`). */
.status-card-body{min-width:0;}
.status-card-label{font-size:10.5px; text-transform:uppercase; letter-spacing:.04em; color:var(--text-muted); font-weight:600;}
.status-card-value{font-size:19px; font-weight:700; color:var(--text-primary); margin-top:3px; font-variant-numeric:tabular-nums;}
.status-card-desc{font-size:11.5px; color:var(--text-muted); margin-top:3px; line-height:1.4;}

/* ======================= PAINEL ADMIN — dashboard (KPIs + gráficos) =======================
   Mesma receita visual de .menu-status-grid (reaproveita .status-bar-item/.status-card-* tal como
   estão), mas sem max-width/margin:auto — o ecrã Admin usa layout .wrap a largura total, não a
   coluna central do Menu. Gráficos via Chart.js (CDN, ver index.html) — biblioteca de gráficos
   moderna pedida explicitamente, substituindo as barras/anéis feitos à mão em CSS puro que a app
   tinha antes (renderAdminBarChart/renderAdminStackedBar continuam com o mesmo nome/assinatura em
   script.js, só o desenho interno mudou de <div> para <canvas>+Chart.js). */
.admin-stat-grid{display:flex; flex-wrap:wrap; background:var(--bg-surface); border:1px solid var(--border); border-radius:var(--radius-lg); box-shadow:var(--shadow-sm); margin-bottom:20px;}
.admin-charts-grid{display:grid; grid-template-columns:repeat(auto-fit, minmax(260px,1fr)); gap:16px; margin-bottom:20px;}
.admin-chart-card h3{font-size:13px; margin:0 0 14px; color:var(--text-primary);}
.admin-chart-canvas-wrap{position:relative; height:190px;}
.admin-chart-canvas-wrap-donut{height:220px;}
.admin-hbar-list{display:flex; flex-direction:column; gap:9px;}
.admin-hbar-row{display:flex; align-items:center; gap:8px;}
.admin-hbar-label{flex:0 0 auto; max-width:42%; font-size:12px; color:var(--text-secondary); overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.admin-hbar-track{flex:1 1 auto; height:8px; background:var(--bg-subtle); border-radius:var(--radius-pill); overflow:hidden;}
.admin-hbar-fill{height:100%; background:var(--accent-2); border-radius:var(--radius-pill);}
.admin-hbar-value{flex:0 0 auto; font-size:11.5px; font-variant-numeric:tabular-nums; color:var(--text-muted);}

/* ======================= MENU — Início (dashboard real, dados globais da conta) =======================
   Mesma receita visual do dashboard do Admin acima (admin-stat-grid/admin-charts-grid/status-bar-item)
   — dois painéis de "estado geral", um para administradores (Admin) e outro para qualquer utilizador
   (Início), com a MESMA linguagem visual em vez de reinventar uma segunda. Só os 3 blocos abaixo
   (lista/avisos/acessos rápidos) são específicos do Início. */
.inicio-row-3{display:grid; grid-template-columns:1.3fr 1fr 1fr; gap:16px; align-items:start;}
@media (max-width:1080px){ .inicio-row-3{grid-template-columns:1fr 1fr;} }
@media (max-width:700px){ .inicio-row-3{grid-template-columns:1fr;} }
.inicio-list-item{display:flex; align-items:center; justify-content:space-between; gap:10px; padding:10px 0; border-bottom:1px solid var(--border);}
.inicio-list-item:last-child{border-bottom:none;}
.inicio-list-item-main{min-width:0;}
.inicio-list-item-title{font-size:13px; font-weight:650; color:var(--text-primary); overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.inicio-list-item-sub{font-size:11.5px; color:var(--text-muted); margin-top:2px;}
.inicio-avisos{display:flex; flex-direction:column; gap:10px;}
.quick-tiles{display:grid; grid-template-columns:1fr; gap:8px;}
.quick-tile{
  display:flex; align-items:center; gap:10px; padding:11px 12px; border:1px solid var(--border); border-radius:var(--radius);
  background:var(--bg-surface); cursor:pointer; text-align:left; font-family:inherit; width:100%;
  transition:border-color .15s, box-shadow .15s, transform .15s;
}
.quick-tile:hover{border-color:var(--accent); box-shadow:var(--shadow-hover); transform:translateY(-1px);}
.quick-tile-ic{width:30px; height:30px; flex-shrink:0; border-radius:var(--radius-sm); background:var(--accent-tint); color:var(--accent); display:flex; align-items:center; justify-content:center;}
.quick-tile-label{font-size:12.5px; font-weight:650; color:var(--text-primary);}

/* Hierarquia real em vez de 4 cartões idênticos: só "Fecho de Contas" está construído, por isso é o
   único que se comporta como destaque (linha própria, mais largo) — os outros 3 (1 funcional + 2
   placeholders) ficam numa segunda linha, mais pequenos. Resolve um problema real de UX: antes, os
   4 cartões pareciam igualmente prontos a usar quando só 1 estava de facto pronto. */
.menu-grid{display:flex; flex-direction:column; gap:16px;}
.menu-grid-secondary{display:grid; grid-template-columns:repeat(auto-fit, minmax(220px,1fr)); gap:16px;}
@media (max-width:760px){ .menu-grid-secondary{grid-template-columns:1fr;} }
.menu-card{position:relative; background:var(--bg-surface); border:1px solid var(--border); border-radius:var(--radius-lg); padding:24px; box-shadow:var(--shadow-sm); transition:border-color .15s, box-shadow .15s, transform .15s;}
.menu-card-active{cursor:pointer;}
/* --shadow-hover (não --shadow-md): mantém a borda visível no hover sem cair no padrão "ghost card"
   (borda 1px + sombra larga de 16px+ de desfoque ao mesmo tempo). */
.menu-card-active:hover{border-color:var(--accent); box-shadow:var(--shadow-hover); transform:translateY(-3px);}
/* Cartões "em desenvolvimento" têm um tratamento próprio (não é só a versão desbotada do cartão
   clicável) — borda tracejada + sem sombra sinalizam "ainda não é uma superfície real", o selo "Em
   breve" reforça o estado sem depender só da opacidade para comunicar "não clicável". */
.menu-card-disabled{cursor:not-allowed; border-style:dashed; box-shadow:none; background:var(--bg-subtle);}
.menu-card-disabled .menu-card-title, .menu-card-disabled .menu-card-desc{color:var(--text-muted);}
.menu-card-badge{position:absolute; top:16px; right:16px; padding:2px 9px; font-size:10px;}
/* Quadrado arredondado (não pill/círculo) — a mesma linguagem de forma do .brand-mark, para o
   vocabulário de "chips" de ícone da app ficar coerente e menos parecido com o círculo colorido
   genérico de ícone de cartão SaaS. */
.menu-card-icon{margin-bottom:16px; width:50px; height:50px; display:flex; align-items:center; justify-content:center; border-radius:var(--radius-lg); background:var(--accent-tint); color:var(--accent);}
.menu-card-disabled .menu-card-icon{background:var(--bg-subtle-strong); color:var(--text-muted);}
.menu-card-title{font-size:15.5px; font-weight:700; margin-bottom:6px; color:var(--text-primary);}
.menu-card-desc{color:var(--text-secondary); font-size:13px; line-height:1.5;}
/* Cartão em destaque — linha inteira, layout horizontal (ícone · texto · seta), ícone maior, fundo
   liso (nunca gradiente — um documento oficial não tem degradê). É a ÚNICA ação primária desta barra:
   a borda cheia (1.5px, nos 4 lados — não um border-left decorativo) em tinta de selo já basta para a
   distinguir, sem precisar de brilho nenhum. */
.menu-card-featured{display:flex; align-items:center; gap:22px; padding:28px 30px;
  border-width:1.5px; border-color:var(--accent); box-shadow:var(--shadow-sm);}
.menu-card-featured:hover{box-shadow:var(--shadow-hover);}
.menu-card-featured .menu-card-icon{margin-bottom:0; width:58px; height:58px; flex-shrink:0; background:var(--c-ink-950); color:var(--c-garnet-400);}
.menu-card-featured .menu-card-body{flex:1; min-width:0;}
.menu-card-featured .menu-card-title{font-size:19px; margin-bottom:4px;}
.menu-card-featured .menu-card-desc{max-width:60ch;}
.menu-card-arrow{flex-shrink:0; color:var(--accent); transition:transform .18s ease;}
.menu-card-featured:hover .menu-card-arrow{transform:translateX(4px);}
@media (max-width:640px){
  .menu-card-featured{flex-wrap:wrap; padding:22px;}
  .menu-card-arrow{display:none;}
}

/* ======================= BARRA LATERAL GLOBAL — um único elemento (`#globalSidebar`, ver
   index.html), sempre fixo à viewport (nunca rola com o conteúdo), colado ao limite esquerdo real
   da janela (position:fixed ignora o padding lateral do body), presente em QUALQUER ecrã pós-login
   — Menu, Admin, Empresas, Fecho de Contas, Conciliações. Cada ecrã (`.screen-with-sidebar`) só
   ganha um margin-left igual à largura atual da sidebar, para o conteúdo nunca ficar por baixo
   dela. ======================= */
/* `width` (não grid-template-columns, já que a sidebar deixou de ser uma faixa de grid) —
   transição de `width` numa caixa `position:fixed` NÃO participa de nenhum layout de outros
   elementos (está fora do fluxo normal), por isso não sofre do "layout thrash" que motivou o uso de
   grid quando a sidebar ainda vivia dentro de `.app-shell` (ver histórico) — aqui é seguro. */
.app-sidebar{
  position:fixed; top:0; left:0; height:calc(100vh / var(--app-zoom)); width:var(--sidebar-width); z-index:var(--z-sticky);
  /* padding-top 14px (era 18) — pedido explícito: o logótipo tem de ficar exatamente centrado entre
     o topo da viewport e a linha separadora (`.side-brand{border-bottom}`) — ver `.side-brand` mais
     abaixo, onde padding-top passou a 0 e padding-bottom passou a 14px, o MESMO valor daqui, para as
     duas margens (acima/abaixo do logótipo) serem sempre iguais, independente da altura da imagem. */
  display:flex; flex-direction:column; padding:max(14px, env(safe-area-inset-top)) 14px 16px max(14px, env(safe-area-inset-left));
  background:var(--sidebar-bg); border-right:1px solid var(--sidebar-border);
  /* `overflow:visible` nos dois eixos (era `hidden`, depois tentei `overflow-x:visible;overflow-y:
     auto`) — pedido explícito: o item de menu em destaque (`.side-item:hover`) tem de "sair até fora
     do painel lateral" para a direita; um `overflow:hidden` aqui cortava exatamente essa saliência.
     Bug real corrigido: `overflow-x:visible` + `overflow-y:auto` (eixos DIFERENTES, um deles
     "visible") — a especificação do CSS obriga o browser a tratar o eixo "visible" como "auto"
     sempre que o outro eixo não é "visible" (regra "overflow computed value"); na prática, o
     `overflow-x` continuava a valer "auto" por trás dos panos, e sempre que o item crescia ao passar
     o rato (mais largo do que a sidebar) o browser desenhava uma barra de rolagem horizontal
     genuína — que ocupa espaço vertical real dentro da caixa, empurrando o rodapé (cartão do
     utilizador + botão de tema) ligeiramente para cima enquanto estivesse visível. Um único
     `overflow:visible` (os dois eixos, sem misturar) evita esse recálculo — sem barra nenhuma, sem a
     estrutura do rodapé a mexer-se. Como consequência aceite, a sidebar deixa de ter scroll vertical
     próprio se algum dia a lista de itens crescer mais do que 100vh — não é um cenário real hoje (a
     app tem sempre um número fixo e pequeno de vistas). */
  overflow:visible; transition:width .2s cubic-bezier(.16,1,.3,1);
}
body.sidebar-collapsed .app-sidebar{width:68px; padding-left:10px; padding-right:10px;}
/* Qualquer ecrã pós-login ganha esta classe (ver index.html) — o único ponto que sabe "há uma
   sidebar fixa à esquerda, dá-lhe espaço": nunca duplicado por ecrã, só a classe muda de sítio. */
.screen-with-sidebar{margin-left:var(--sidebar-width); transition:margin-left .2s cubic-bezier(.16,1,.3,1);}
body.sidebar-collapsed .screen-with-sidebar{margin-left:68px;}
/* "Orelha" de recolher/expandir — nova geometria, pedida explicitamente depois de 2 tentativas
   anteriores com `clip-path` (silhueta moldada na parede, cantos côncavos/convexos) não terem
   acertado o resultado pretendido: passou a ser um CÍRCULO PERFEITO, com o centro exatamente sobre o
   limite direito da sidebar (`left:<largura da sidebar>` + `transform:translate(-50%,-50%)`, que
   centra nos dois eixos ao mesmo tempo) — metade do círculo cai dentro do painel, metade cai fora,
   "50%/50%" tal como pedido, sem depender de nenhum offset ajustado à mão.
   Tamanho: diâmetro = altura da orelha anterior (66px) − 6px = 60px. A borda de 6px pedida
   ("Adicione uma borda de 6px com a cor do fundo da tela") entra DENTRO desses 60px
   (`box-sizing:border-box`), por isso o círculo visível de preenchimento (a "peça" da orelha em si)
   fica com 48px de diâmetro, cercado por um anel de 6px na cor do FUNDO DA PÁGINA (`--bg-page`, não
   `--sidebar-bg`) — é esse anel, ao mostrar a cor de trás em vez da cor da sidebar, que dá a ilusão
   de "um corte" na própria sidebar, como pedido. `--bg-page` já é um token que muda sozinho por tema
   (claro/escuro, ver `:root`/`[data-theme="dark"]`) — a borda ajusta-se à cor certa sem precisar de
   nenhum override extra aqui. */
.sidebar-ear{
  position:fixed; top:46px; left:var(--sidebar-width); transform:translate(-50%,-50%);
  width:60px; height:60px; box-sizing:border-box; border-radius:50%;
  padding:0; margin:0; cursor:pointer;
  background:var(--sidebar-bg); border:6px solid var(--bg-page);
  z-index:calc(var(--z-sticky) + 1);
  transition:left .2s cubic-bezier(.16,1,.3,1), top .2s cubic-bezier(.16,1,.3,1), background-color .15s, border-color .15s;
}
/* left:68px/top:38px (colapsada) — mesmo raciocínio da versão expandida: 68px é a largura real da
   sidebar recolhida (`body.sidebar-collapsed .app-sidebar{width:68px}`), por isso o centro do círculo
   continua exatamente sobre o limite direito do painel, 50%/50% também aqui; top:38px é o centro do
   logótipo recolhido (`.side-brand-mark`), inalterado desta mudança. */
body.sidebar-collapsed .sidebar-ear{left:68px; top:38px;}
.sidebar-ear:hover, .sidebar-ear:focus-visible{background:var(--sidebar-accent);}
.sidebar-ear:focus-visible{outline:2px solid var(--sidebar-accent); outline-offset:2px;}
/* Seta (em vez dos antigos 3 pontos) — indica a DIREÇÃO da ação: aponta para a esquerda quando a
   sidebar está expandida (a orelha vai "fechar" para esse lado), e roda 180º para apontar para a
   direita assim que `body.sidebar-collapsed` é aplicado (a orelha vai "abrir" para esse lado) — pedido
   explícito, para o próprio ícone comunicar se o clique recolhe ou expande, sem depender só da cor de
   hover. Reaproveita literalmente o path de `ICONS.arrowLeft` (script.js) — este botão vive em HTML
   estático, por isso o SVG é escrito por extenso aqui, mesma convenção já seguida pelo resto da app
   para ícones fora do `icon()`/`el()`. Centrado com `position:absolute` + `translate(-50%,-50%)`
   (mesma técnica dos antigos pontos), a rotação soma-se ao mesmo `transform` sem perder a centragem. */
.sidebar-ear-arrow{
  /* +5px pedido explícito (era 20px) — largura E altura juntas (não só a largura à letra), para o
     SVG (viewBox quadrado) não distorcer — mesmo raciocínio já seguido da vez anterior que este
     tamanho cresceu (ver comentário histórico acima, agora resolvido). */
  position:absolute; left:50%; top:50%; width:25px; height:25px; z-index:1;
  transform:translate(-50%,-50%);
  color:var(--sidebar-text-muted); pointer-events:none;
  transition:transform .3s cubic-bezier(.16,1,.3,1), color .15s;
}
.sidebar-ear:hover .sidebar-ear-arrow, .sidebar-ear:focus-visible .sidebar-ear-arrow{color:var(--sidebar-accent-ink);}
body.sidebar-collapsed .sidebar-ear-arrow{transform:translate(-50%,-50%) rotate(180deg);}
/* Traço neon a rodar REMOVIDO por pedido explícito (era um `::after` a fazer uma volta completa em
   ~6,5s, cor `--fc-ear-neon` + box-shadow de halo — ver histórico no git). No lugar disso, só o
   BACKGROUND da própria orelha (nunca um elemento decorativo à parte) ganha um efeito ambiente,
   contínuo e discreto: `filter:saturate()` a oscilar entre 100% e ~170% num ciclo lento (~5s) — dá a
   sensação de "algo vivo" sem introduzir nenhuma cor/brilho novo (usa sempre a cor de fundo já
   definida, `--sidebar-bg`, só varia a saturação dela). Aplicado ao PRÓPRIO elemento (não a um
   pseudo-elemento), por isso não interfere com a seta (`.sidebar-ear-arrow`) nem com o hover (que já
   troca o background por inteiro para `--sidebar-accent`, sobrepondo-se sem conflito). */
@media (prefers-reduced-motion: no-preference){
  .sidebar-ear{ animation:fc-ear-pulse 5s ease-in-out infinite; }
  .sidebar-ear:hover, .sidebar-ear:focus-visible{ animation-play-state:paused; }
  @keyframes fc-ear-pulse{
    0%, 100%{ filter:saturate(100%); }
    50%{ filter:saturate(170%) contrast(112%); }
  }
}
/* Logótipo real da FECS no topo da sidebar — sempre a variante clara (fundo da sidebar é sempre
   escuro, nunca muda com o tema, ver --sidebar-bg em :root), sem troca de imagem por tema. Área da
   caixa (`.side-brand`) mantida igual à de sempre — só a imagem em si cresce, ocupando quase toda
   essa área (pedido explícito: "não aumenta a área, apenas aumenta o logo"); por isso o padding
   vertical encolheu exatamente o mesmo tanto que a imagem cresceu, mantendo a altura total do bloco
   praticamente inalterada. */
/* Margem acima do logótipo = margem abaixo dele (até à linha separadora) — pedido explícito: "o
   logótipo tenha a mesma margem dessa linha igual à margem que terá do topo da viewport, exatamente
   no centro". A margem "acima" é a soma do padding-top do `.app-sidebar` (14px, ver acima) + o
   padding-top daqui (agora 0) = 14px; a margem "abaixo" (até ao `border-bottom`) é o padding-bottom
   daqui, também 14px — as duas iguais por construção, em vez de depender de comparação visual (era
   2px topo/6px fundo antes desta correção, resultado de uma ilusão de ótica corrigida numa sessão
   anterior só para o padding LOCAL desta caixa, sem contar com o padding do próprio `.app-sidebar`
   por cima, que é a verdadeira margem "do topo da viewport" pedida agora). Vale tanto expandida como
   recolhida — o padding é o mesmo nos dois casos, só a imagem lá dentro muda de tamanho. */
/* Linha divisória logótipo→menu — pedido explícito para ficar mais visível: 2px (era 1px) e a cor
   "forte" já definida por tema (`--sidebar-border-strong` — branco sólido no claro, azul-marinho
   sólido no escuro, o mesmo par já usado na borda do botão de tema), em vez do `--sidebar-border`
   original (translúcido a 9-18%, pensado só para uma separação subtil). */
.side-brand{display:flex; align-items:center; min-height:46px; padding:0 6px 14px 6px; margin-bottom:4px; border-bottom:2px solid var(--sidebar-border-strong);}
.side-brand img{max-width:100%; object-fit:contain;}
.side-brand-full{height:59px; width:auto;}
/* Variante clara do logótipo por omissão (parede da sidebar escura no tema claro); a variante escura
   ("Black Horiz") só entra no tema escuro, onde a parede passou a clara (--sidebar-bg, ver :root) —
   pedido explícito: "altere o logo desse tema para o horizontal escuro". `body.sidebar-collapsed
   .side-brand-full{display:none}` (abaixo) continua a esconder as DUAS variantes por igual — tem mais
   especificidade (o seletor `body` conta como elemento extra) do que estas regras de tema, por isso
   vence sempre, mesmo escrito antes no ficheiro. */
.side-brand-full-dark{display:none;}
[data-theme="dark"] .side-brand-full-light{display:none;}
[data-theme="dark"] .side-brand-full-dark{display:block;}
.side-brand-mark{width:48px; height:48px; display:none;}
body.sidebar-collapsed .side-brand-full{display:none;}
/* Pedido explícito: sem logótipo nenhum quando a sidebar está recolhida — a "orelha" (`.sidebar-ear`,
   `position:fixed` sobre o limite direito da sidebar) tapa parte da marca recolhida (`.side-brand-mark`),
   por isso deixou de fazer sentido mostrá-la aí. `display:none` (era `block`) — a caixa `.side-brand`
   em si mantém-se (mesma altura/divisória de sempre, só sem imagem lá dentro), para o resto do layout
   da sidebar (nav a seguir) não saltar de posição. */
body.sidebar-collapsed .side-brand-mark{display:none;}
body.sidebar-collapsed .side-brand{justify-content:center; padding-left:0; padding-right:0;}
/* `.side-nav` estende-se por margem negativa até à borda verdadeira da sidebar (cancela o padding
   lateral do `.app-sidebar`, 14px expandida/10px recolhida) — pedido explícito ("colocar os menus a
   preencher toda a barra lateral"). Sozinho isto não desloca nada visível: em repouso `.side-item`
   não tem fundo nenhum (só ganha cor em `:hover`/`.active`), por isso só passa a ter efeito quando
   um item é realçado — nessa altura o realce cobre agora a barra de ponta a ponta, não só a faixa
   central de antes. */
.side-nav{display:flex; flex-direction:column; gap:2px; margin:8px -14px 0 -14px;}
body.sidebar-collapsed .side-nav{margin:8px -10px 0 -10px;}
.side-item{
  display:flex; align-items:center; gap:12px; text-decoration:none;
  /* padding-top/bottom em 14px (era 9px) — pedido explícito, "altura de cada menu para mais 10px"
     (+5px de cada lado = +10px de altura no total); simétrico como já era, para o ícone/texto se
     manterem centrados na vertical (ver nota em `:hover` abaixo — o mesmo princípio). */
  padding-top:14px; padding-right:14px; padding-bottom:14px; padding-left:28px;
  /* Raio só do lado direito — pedido explícito: "cada botão de menu deve ter a sua esquerda sem
     borda radius, a borda radius atinge apenas a lateral direita". A esquerda do item está sempre
     encostada à borda verdadeira da sidebar (full-bleed, ver `.side-nav` acima) — um canto
     arredondado aí destacava-se contra essa borda reta; só o lado direito (o lado "livre", que
     ainda por cima é o que sai para fora da barra ao passar o rato, ver `:hover` abaixo) faz
     sentido arredondar, como a face de uma aba/lingueta — a mesma linguagem de forma já usada na
     `.sidebar-ear` (parede reta, face arredondada). */
  border-radius:0 var(--radius-sm) var(--radius-sm) 0;
  color:var(--sidebar-nav-text); font-size:13.5px; font-weight:560; white-space:nowrap; overflow:hidden; cursor:pointer;
  margin-right:0;
  transition:background .15s ease, color .15s ease, margin-right .18s cubic-bezier(.16,1,.3,1),
    padding-top .18s cubic-bezier(.16,1,.3,1), padding-bottom .18s cubic-bezier(.16,1,.3,1);
}
/* O padding-left ganhou +14px (28px, era 14px) para compensar o padding que a sidebar já não dá —
   mantém o ícone/texto exatamente na mesma posição visual de antes (14+14=28 da borda real, tal
   como já era 14(sidebar)+14(item)=28 antes desta mudança) apesar do item agora ocupar a barra
   inteira. Em modo recolhido o conteúdo fica CENTRADO (`justify-content:center`), por isso o
   padding tem de voltar a ser simétrico (14/14) — um padding assimétrico deslocaria o ícone do
   centro visual da barra. */
body.sidebar-collapsed .side-item{justify-content:center; padding-left:14px; padding-right:14px;}
.side-item .icon{flex-shrink:0;}
/* Hover: fundo mais evidente (era rgba(255,255,255,.13), quase impercetível) + crescimento da
   própria caixa, agora maior e mais preciso (pedido explícito, 2ª ronda de afinação):
     - ALTURA: bug real corrigido — a 1ª versão só aumentava `padding-bottom` (+10px), o que
       deixava o conteúdo (ícone+texto, centrado por `align-items:center` dentro da área SEM
       padding) encostado ao topo da caixa maior, não centrado nela. `padding-top` e `padding-bottom`
       agora crescem SEMPRE em partes iguais (14→21.5px cada, +7.5 dos dois lados = +15px de altura
       no total a partir da base já aumentada, mais do que os +10px de antes, pedido explícito "está
       muito pequeno") — com os dois lados iguais, o conteúdo fica matematicamente centrado na caixa
       nova, seja ela qual for o tamanho (o centro de uma caixa com padding simétrico é sempre o
       centro geométrico da caixa).
     - LARGURA: já não é um valor arbitrário — pedido explícito para o limite direito alcançar
       exatamente 2px além do limite direito da própria orelha (`.sidebar-ear`, que termina em
       left:246px+width:14px=260px) — ou seja, o item em hover tem de chegar a 262px. Em repouso o
       item já ocupa a barra quase toda, mas só 247px (não 248) — o `border-right:1px` da própria
       sidebar (ver `.app-sidebar`) consome 1px que nenhum filho, mesmo com margem negativa, consegue
       ocupar (a borda vive fora da content-box onde os filhos residem); confirmado por medição real
       (`getBoundingClientRect`) antes de fixar o valor, em vez de assumir 248 de cabeça.
       `margin-right:-15px` alarga-o para 247+15=262px, o valor exato. Mecanismo: como o item já
       ocupa 100% da largura da nav (`align-items:
       stretch`, o padrão de um filho de flex-column sem largura própria), reduzir a margem direita
       alarga o próprio item além do limite da nav/sidebar — combinado com `overflow:visible` no
       `.app-sidebar` (ver acima), essa saliência fica mesmo visível fora da barra, criando o
       impacto "mais elaborado e distinto" pedido.
   `.active:hover` só define o fundo (mantém a cor do item ativo) — margem/padding do hover base
   aplicam-se de qualquer forma, por não serem tocadas por essa regra mais específica.
   Cor de fundo trocada para `var(--sidebar-accent)` (era `#ee5224`, um laranja escrito à mão que
   nunca fez parte da paleta "Gazeta Oficial de Contas" — ver `:root`, topo do ficheiro — e já não
   batia certo com o resto da sidebar) — pedido explícito: "a cor para o tema dark deve ser a cor
   rosa que já está incluída no nosso design system... já faz parte de alguns elementos" (o mesmo
   rosa/garnet já usado pela orelha em hover e pelo avatar do utilizador, `--sidebar-accent`). O texto/
   ícone por cima passa de branco para `var(--sidebar-accent-ink)` — "os elementos que atribuímos a
   cor laranja devem pegar a cor azul do sidebar para criar um bom contraste": esse token já é agora o
   próprio azul-marinho da sidebar (`--sidebar-bg`, ver `:root`), por isso rosa+azul-marinho passam a
   ser o par de sempre em qualquer preenchimento sólido do acento, não só aqui. */
/* margin-right:-16px (era -15) — recalculado porque a orelha cresceu 1px (limite direito 260→261px);
   o alvo continua "2px além do limite da orelha" (261+2=263), com a mesma base real de 247px (ver
   nota mais abaixo sobre o border-right de 1px da sidebar). */
.side-item:hover{background:var(--sidebar-accent); color:var(--sidebar-accent-ink); margin-right:-16px; padding-top:21.5px; padding-bottom:21.5px;}
/* Item selecionado/clicado — mesmo rosa do hover (`--sidebar-accent`), sem `border-radius` (era `0
   var(--radius-sm) var(--radius-sm) 0` nos restantes) e sem crescer em REPOUSO (`margin-right:0`) —
   "não terá border radius e não irá sair do painel, deve ficar até o limite do painel". */
.side-item.active{background:var(--sidebar-accent); border-radius:0; margin-right:0; color:var(--sidebar-accent-ink); font-weight:650;}
/* Passar o rato num item JÁ selecionado — pedido explícito, 2ª ronda: "o limite da lateral também
   deve sair do painel como quando não está selecionado" (revertido da 1ª ronda: agora cresce/escapa
   igual aos restantes, `margin-right:-16px`, mesmo valor do hover normal) "e a sombra deve ter mais
   um pouco de desfoque" (`box-shadow` ganhou `blur:6px` e `spread:1px`, era um anel nítido sem
   desfoque nenhum — `0 0 0 1px`). O fundo continua a recuar para a cor do painel (o mesmo azul-marinho
   já usado como "ink" do acento, ver acima — nunca repete o rosa, que já está "ligado") e o texto
   continua branco (`--sidebar-text`), com bom contraste sobre esse fundo azul-marinho. Cantos
   arredondados só do lado direito (`0 var(--radius-sm) var(--radius-sm) 0`, a MESMA curvatura de
   `.side-item:hover` acima) — pedido explícito, 3ª ronda: "arredonda as bordas laterais do menu para
   quando passar num menu selecionado, a mesma curvatura que existe quando passa num menu não
   selecionado". O item ativo em REPOUSO (`.side-item.active`, acima) continua sem nenhum
   arredondamento — só o hover muda.
   Sombra branca substituída por um "neon" na borda — pedido explícito: em vez de um halo branco
   genérico, um anel fino cravado na própria cor do item ativo (`var(--sidebar-accent)`, `inset` — não
   ocupa espaço de layout) mais um brilho para fora com a mesma cor (mesmo rgb de `--c-garnet-400`,
   218/88/80 — `rgba()` não lê variáveis CSS, por isso o valor vem escrito por extenso), mais intenso
   do que o hover normal (que não tem glow nenhum), para reforçar "este item já está selecionado". */
.side-item.active:hover{background:var(--sidebar-bg); border-radius:0 var(--radius-sm) var(--radius-sm) 0; margin-right:-16px; box-shadow:0 0 0 1.5px var(--sidebar-accent) inset, 0 0 10px 2px rgba(218,88,80,.65); color:var(--sidebar-text);}
body.sidebar-collapsed .side-item span{display:none;}
/* Em modo recolhido a barra é estreita e centrada — crescer para a direita aqui deslocaria o ícone
   do centro visual sem nenhum ganho (não há texto a revelar), por isso o crescimento lateral fica só
   para o estado expandido (o crescimento em altura, simétrico, continua a acontecer nos dois). */
body.sidebar-collapsed .side-item:hover{margin-right:0;}
/* Linha divisória menu→utilizador — mesmo par de tokens/espessura do `.side-brand` acima (2px,
   `--sidebar-border-strong`), pedido explícito para ficar mais visível. */
.side-footer{margin-top:auto; padding-top:14px; border-top:2px solid var(--sidebar-border-strong); display:flex; flex-direction:column; gap:8px;}
/* Identidade real do utilizador ligado — iniciais + nome/email, mesma info que já existia como
   texto solto no topbar ("Olá, Nome"), agora também presente na sidebar como um verdadeiro
   rodapé de conta (padrão comum a qualquer app com sidebar). */
.side-user{display:flex; align-items:center; gap:10px; padding:8px 6px; border-radius:var(--radius-sm);}
.side-user-avatar{width:30px; height:30px; flex-shrink:0; border-radius:var(--radius-pill); background:var(--sidebar-accent); color:var(--sidebar-accent-ink); display:flex; align-items:center; justify-content:center; font-size:12px; font-weight:700;}
.side-user-info{min-width:0; overflow:hidden;}
.side-user-name{font-size:12.5px; font-weight:650; color:var(--sidebar-text); white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}
/* `var(--sidebar-text)` (era `#fff` fixo) — no modo claro continua a resolver para branco puro,
   preservando o pedido antigo ("a cor de texto dos menus deve ser branca... incluindo... email");
   só passou a variável para poder participar na inversão de cores do modo escuro (ver
   `[data-theme="dark"]`, mais abaixo) — um branco fixo nunca acompanharia essa troca. */
.side-user-email{font-size:10.5px; color:var(--sidebar-text); white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}
body.sidebar-collapsed .side-user-info{display:none;}
body.sidebar-collapsed .side-user{justify-content:center;}
/* Idioma + Alternador de tema + "Sair" — vivem lado a lado no rodapé (pedido explícito: "colocar
   antes do botão do tema... o botão para alterar idioma"; "o botão sair deve mudar de posição e
   ficar ao lado direito do botão de tema... com o mesmo padrão do botão do tema"). Só o botão de
   idioma fica redondo (mesmo widget de sempre, `.idioma-switch`/`renderIdiomaSwitches()` — ver
   script.js) — os outros dois ("mantém... o restante assume o padrão do botão de sair") continuam
   `.side-theme-btn`, agora a repartir o espaço a 2 (em vez de sozinho), o que já reduz o Sair (e o
   tema) um pouco, como pedido, sem precisar de um tamanho à parte para cada um. Em modo recolhido
   não há largura para 3 lado a lado (sidebar só tem 68px) — a fila empilha (`flex-direction:column`),
   cada botão volta a ocupar a largura toda, um por cima do outro. */
.side-footer-actions{display:flex; align-items:center; gap:8px;}
.side-footer-actions > .idioma-switch{flex:0 0 auto;}
/* Com 3 botões a repartir a fila (era só o tema, sozinho, largura toda), "Modo escuro"/"Modo claro"
   deixou de caber numa linha só — sem isto, quebrava para 2 linhas e ficava mais alto do que o
   "Sair" ao lado, uma assimetria visual que o pedido ("o restante assume o padrão do botão de
   sair") não previa. Reticências em vez de quebra — mantém as duas caixas com a mesma altura. */
.side-footer-actions .side-theme-btn span{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; min-width:0; }
body.sidebar-collapsed .side-footer-actions{flex-direction:column;}
/* Pele redonda da sidebar (sempre escura, nunca segue `--chrome-*`) para o mesmo widget de idioma já
   usado nos 7 mastheads — ali segue o tema claro/escuro (`--chrome-bg-raised`/`--chrome-border`),
   aqui precisa da mesma pele fixa que `.side-theme-btn` já usa. `left:0` (era `right:0`, herdado do
   masthead) — dentro da sidebar o botão fica perto da borda ESQUERDA do rodapé; com `right:0` o menu
   abriria para a esquerda e saía do ecrã (a sidebar só tem 248px, o próprio menu tem ~152px de
   largura mínima) — `left:0` abre para a direita, dentro/perto da sidebar, sem cortar. */
.app-sidebar .side-footer .idioma-switch-btn{ background:transparent; border:1.5px solid var(--sidebar-border-strong); }
.app-sidebar .side-footer .idioma-switch-btn:hover{ border-color:var(--sidebar-accent); }
/* O rodapé fica colado ao fundo da janela — um menu que abrisse para BAIXO (`top:calc(100% + 6px)`,
   o padrão dos mastheads) saía sempre do ecrã, invisível/impossível de clicar (bug relatado). Aqui
   abre sempre para CIMA (`bottom`, não `top`) — só este widget, os mastheads já não têm nenhum. */
.app-sidebar .idioma-switch-menu{ left:0; right:auto; top:auto; bottom:calc(100% + 6px); }
/* Pele própria (não `.masthead .btn.secondary`, pensada para a moldura que segue o tema): a sidebar
   é sempre escura, por isso os botões precisam sempre da pele "sobre escuro", nos dois temas da
   app. `.side-theme-btn` dá nome à classe partilhada por ambos (tema E logout) — nunca duplicada. */
.side-theme-btn{
  flex:1 1 0; min-width:0; display:flex; align-items:center; justify-content:center; gap:8px; padding:8px; border-radius:var(--radius-sm);
  background:transparent; border:1.5px solid var(--sidebar-border-strong); color:var(--sidebar-nav-text); cursor:pointer; font-size:12px; font-weight:600;
  font-family:inherit;
}
.side-theme-btn:hover{background:var(--sidebar-bg-raised); border-color:var(--sidebar-border-strong); color:var(--sidebar-text);}
/* Duas correções reais, a mesma raiz (especificidade CSS): o HTML destes botões também leva as
   classes genéricas `.btn.secondary` (para herdar padding/cursor/etc.), cujas regras — incluindo
   `.btn.secondary:hover{background:var(--bg-subtle); ...}`, que no tema CLARO resolve para um fundo
   quase branco — têm MAIS especificidade do que `.side-theme-btn`/`.side-theme-btn:hover` sozinhos.
   1) Em repouso: `.btn.secondary{color:var(--text-primary); border-color:var(--border-strong);}`
      ganhava a cor/contorno — em modo claro `--text-primary` é tinta quase-preta sobre o fundo
      SEMPRE escuro da sidebar, invisível (bug já corrigido antes, mantido aqui). 2) Ao passar o
      rato: `.btn.secondary:hover` ganhava também o FUNDO (não só a cor), pondo um fundo claro por
      trás de um texto claro — "fica branco, sumindo totalmente o texto" (bug relatado agora).
   Corrigido com um seletor de especificidade maior (3+ classes, imune à ordem do ficheiro) que
   define explicitamente background+border+color tanto em repouso como em `:hover` — nada genérico
   de `.btn.secondary` sobra por definir. Borda também trocada para `--sidebar-border-strong` (32%
   branco, bem mais visível do que os 9% de `--sidebar-border`, pensados só para linhas divisórias
   discretas) — pedido explícito ("a borda quase não se percebe... coloque em tons visíveis"). Este
   seletor aplica-se tanto ao botão de tema (`data-tema-toggle`) como ao "Sair" (`data-logout-btn`)
   por partilharem a mesma classe `.side-theme-btn`. */
.app-sidebar .side-footer .side-theme-btn{ background:transparent; color:var(--sidebar-nav-text); border-color:var(--sidebar-border-strong); }
.app-sidebar .side-footer .side-theme-btn:hover{ background:var(--sidebar-bg-raised); color:var(--sidebar-text); border-color:var(--sidebar-border-strong); }
/* Bug real corrigido: `.side-theme-btn span{display:none}` escondia TODOS os spans descendentes —
   incluindo o `.ic-wrap` que `icon()` (script.js) usa para embrulhar o próprio SVG do botão de tema
   (o "Sair" nunca teve este problema, o seu ícone é um `<svg>` cru, sem wrapper). Resultado: o botão
   de tema ficava sem nada visível (nem ícone, nem texto), encolhido a quase 0 — só o `<span>` de
   TEXTO deve desaparecer, nunca o `.ic-wrap`. Mesmo padrão já usado por `.side-mobile-icon-btn > span
   :not(.ic-wrap)`, agora replicado aqui. */
body.sidebar-collapsed .side-theme-btn > span:not(.ic-wrap){display:none;}
/* Tamanho explícito, igual ao do botão "Sair" ao lado (pedido explícito: "faça que ele fique do
   tamanho do botão de sair") — sem isto, `align-items:center` no pai (`.side-footer-actions`, agora em
   coluna) encolhe cada botão ao tamanho do seu próprio conteúdo, e um ícone sozinho (sem o texto,
   escondido acima) podia sair ligeiramente diferente de botão para botão. Um quadrado fixo elimina
   essa dependência — os dois (`data-tema-toggle`/`data-logout-btn`, ambos `.side-theme-btn`) passam a
   ter sempre exatamente o mesmo tamanho aqui, só quando recolhida (o estado expandido não é tocado). */
body.sidebar-collapsed .side-theme-btn{flex:0 0 auto; width:34px; height:34px; padding:0;}
.menu-view{display:none;}
.menu-view.active{display:block;}
/* Selo "Em breve" reaproveitado de .menu-card-disabled — os cartões do roadmap não são clicáveis. */
.roadmap-card-grid{display:grid; grid-template-columns:repeat(auto-fit, minmax(240px,1fr)); gap:16px;}
.about-hero{display:flex; align-items:center; gap:18px; padding:24px; margin-bottom:16px;}
.about-hero .brand-mark{width:52px; height:52px; border-radius:16px; flex-shrink:0; padding:8px;}
.about-hero .brand-mark img{width:100%; height:100%; object-fit:contain;}
.about-grid{display:grid; grid-template-columns:repeat(2,1fr); gap:16px;}
@media (max-width:760px){ .about-grid{grid-template-columns:1fr;} }
.info-row{display:flex; align-items:flex-start; gap:10px; padding:10px 0; border-bottom:1px solid var(--border); font-size:13px; color:var(--text-secondary); line-height:1.5;}
.info-row:last-child{border-bottom:none;}
.info-row .icon{flex-shrink:0; margin-top:1px; color:var(--accent);}
.legal-access{margin-top:16px; padding:20px 22px; display:flex; align-items:center; justify-content:space-between; gap:24px; background:var(--bg-surface); border:1px solid var(--border); border-radius:var(--radius-lg); box-shadow:var(--shadow-sm);}
.legal-access h2{font-size:17px; margin:0 0 5px;}
.legal-access p{margin:0; max-width:62ch; color:var(--text-secondary); font-size:13px; line-height:1.55;}
.legal-access-actions{display:flex; flex-wrap:wrap; gap:8px; flex-shrink:0;}
@media (max-width:760px){.legal-access{align-items:flex-start; flex-direction:column;}.legal-access-actions{width:100%;}.legal-access-actions .btn{flex:1; justify-content:center;}}
/* ---- Cabeçalho móvel da sidebar (<900px) — pedido explícito, substitui por completo o antigo
   tratamento (nav em linha, sempre visível, sem hambúrguer nenhum — ver bloco @media logo abaixo).
   Conceito: uma única faixa compacta, FIXA no topo (`.app-sidebar{position:sticky; top:0;}`, pedido
   explícito numa ronda seguinte — "fixar esse menu no topo, não rolar ele para baixo", revertendo a
   decisão anterior "nunca fixo"), com 2 variantes de conteúdo (só uma de cada vez, decidido por
   `atualizarSideMobileHeader()` em script.js a partir do item ativo de `#menuSideNav`):
     - Vista "Início" (a única exceção — "este será o único que não terá a caixa"): logótipo (mais
       pequeno do que no desktop, ver `.side-mobile-header .side-brand-full`) + [tema] + [hambúrguer].
     - Qualquer outra vista/ecrã: uma caixa de 2 linhas (nome do menu a negrito, "Olá, {nome}" por
       baixo, sem o resto da frase de boas-vindas do desktop) + [tema] + [hambúrguer] à direita.
   O antigo cabeçalho de cada ecrã (`.menu-topbar`/`.masthead` — título+"Olá"+idioma) fica redundante
   com este e é escondido por inteiro no mobile (pedido explícito, "não deve aparecer... porque o
   novo menu já faz isso") — ver a regra `.menu-topbar, .masthead{display:none;}` mais abaixo.
   O hambúrguer (`.side-mobile-icon-btn#btnSideMobileToggle`) abre `#menuSideNav` como um dropdown
   flutuante — os MESMOS `.side-item` de sempre (nunca duplicados, incluindo um último item extra só
   para mobile, "Sair" — `data-view="__logout"` — ver script.js/`fazerLogout`), reposicionados para
   uma lista vertical compacta enquanto `.app-sidebar` tem a classe `.mobile-nav-open`. O botão de
   tema (`[data-tema-toggle]`, mesmo elemento/lógica de sempre — `aplicarTemaUI()` já o preenche por
   seletor de atributo, não por id) vive à esquerda do hambúrguer, só ícone (a legenda de texto que
   `aplicarTemaUI` também escreve fica escondida aqui, ver `.side-mobile-icon-btn span`). */
.side-mobile-header{display:none;}
@media (max-width:900px){
  /* `position:sticky; top:0` (era `relative`) — pedido explícito para o cabeçalho móvel nunca rolar
     para fora do ecrã; `sticky` continua a servir de ponto de referência para o dropdown de
     `#menuSideNav` (`position:absolute` dentro dele), exatamente como `relative` já servia. */
  .app-sidebar{position:sticky; top:0; height:auto; width:auto; padding:8px 4px; border-right:none; border-bottom:1px solid var(--sidebar-border); z-index:var(--z-sticky);}
  /* Bug real corrigido (mantém-se válido com `sticky`): `.menu-topbar`/`.fecho-sticky-header` também
     usam `z-index:var(--z-sticky)` — com z-index empatado, a ordem do DOM desempata a favor deles
     (vêm depois no HTML), tornando o dropdown clicável mas invisível/inacessível ao toque. Corrigido
     subindo só `.app-sidebar` para acima de `--z-dropdown` enquanto o dropdown está mesmo aberto. */
  .app-sidebar.mobile-nav-open{z-index:calc(var(--z-dropdown) + 1);}
  .screen-with-sidebar, body.sidebar-collapsed .screen-with-sidebar{margin-left:0;}
  .sidebar-ear{display:none;}
  .side-brand{display:none;}
  /* O cabeçalho de cada ecrã (título+"Olá"+idioma) fica redundante com `.side-mobile-header` no
     mobile — escondido por inteiro; `.breadcrumb`/`.nav-tabs`/`#empresaAtivaBar` (elementos irmãos,
     não filhos de `.masthead`) continuam visíveis normalmente, nunca tocados por esta regra. */
  .menu-topbar, .masthead{display:none;}
  .side-mobile-header{
    display:flex; align-items:center; justify-content:space-between; gap:10px;
    /* Limite de 3px em cima e 3px em baixo (pedido explícito) — sem `border-bottom` (removido, outro
       pedido explícito: "a linha que está abaixo do logotipo não precisa aparecer") nem margem extra
       a seguir (nada mais no fluxo normal por baixo — o dropdown, quando aberto, é `position:
       absolute`, não depende deste espaço). */
    padding:3px 6px;
  }
  /* Logótipo maior — "aumentado... apenas 3px de limite superior/inferior" (pedido explícito, cresce
     a partir dos 40px de uma ronda anterior, já que o padding da faixa encolheu de 4/10px para 3/3px
     e sobra bastante mais espaço vertical). */
  .side-mobile-header .side-brand-full{height:44px; width:auto;}
  .side-mobile-header-text{min-width:0; flex:1;}
  .side-mobile-header-title{font-size:14.5px; font-weight:700; color:var(--sidebar-text); white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}
  .side-mobile-header-greeting{font-size:11.5px; color:var(--sidebar-text-muted); white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}
  .side-mobile-header-utility{display:flex; align-items:center; gap:8px; flex-shrink:0;}
  /* Botão quadrado só-ícone, partilhado pelo alternador de tema e pelo hambúrguer (mesma pele) —
     pedido explícito: "o botão de tema... deve apenas conter ícone e não o nome". `aplicarTemaUI()`
     continua a escrever um `<span>` com o rótulo de texto (é genérico, para qualquer `[data-tema-
     toggle]` da app) — escondido só aqui, nunca apagado do DOM (mesmo padrão já usado em `body.
     sidebar-collapsed .side-theme-btn span`). Tamanho subido para 44px (era 38px) — pedido explícito
     ("não se consegue identificar qual botão se trata... aumente o tamanho"), a acompanhar a altura
     do logótipo ao lado (`.side-mobile-header .side-brand-full`, 44px) sem precisar de alterar o
     padding do cabeçalho (`.side-mobile-header{padding:3px 6px;}`, já só 3px em cima/em baixo, como
     pedido — o botão passa a preencher quase toda a altura disponível dentro desse limite). */
  .side-mobile-icon-btn{
    flex-shrink:0; width:44px; height:44px; display:flex; align-items:center; justify-content:center;
    border-radius:var(--radius-sm); background:transparent; border:1.5px solid var(--sidebar-border-strong);
    color:var(--sidebar-nav-text); cursor:pointer; padding:0;
  }
  /* Bug real corrigido: `icon()` (script.js) devolve um `<span class="ic-wrap">` a embrulhar o SVG —
     é o ÚNICO filho destes botões (nunca têm texto visível, pedido explícito). A regra anterior
     (`.side-mobile-icon-btn span{display:none;}`, pensada só para esconder o `<span>` de RÓTULO DE
     TEXTO que `aplicarTemaUI()` também escreve, sem classe própria) escondia sem querer esse mesmo
     `.ic-wrap` — os ícones do tema e do hambúrguer nunca chegavam a aparecer, só a caixa vazia do
     botão. `:not(.ic-wrap)` escapa só o rótulo de texto, o ícone fica sempre visível. */
  .side-mobile-icon-btn > span:not(.ic-wrap){display:none;}
  .side-mobile-icon-btn svg{width:20px; height:20px;}
  .side-mobile-icon-btn:hover, .app-sidebar.mobile-nav-open #btnSideMobileToggle{
    background:var(--sidebar-bg-raised); border-color:var(--sidebar-accent); color:var(--sidebar-accent-strong);
  }
  /* `#menuSideNav` só existe visualmente quando aberto — ao contrário do desktop, nunca uma faixa
     sempre visível. Aberto: dropdown flutuante, ancorado logo abaixo da faixa (`top:100%` do próprio
     `.app-sidebar`, que só tem o cabeçalho como conteúdo em fluxo normal nesse momento — o próprio
     `.side-nav` sai do fluxo ao ficar `position:absolute`). */
  .side-nav{display:none;}
  .app-sidebar.mobile-nav-open .side-nav{
    display:flex; flex-direction:column; gap:2px;
    position:absolute; top:100%; left:4px; right:4px; margin:6px 0 0 0;
    background:var(--sidebar-bg-raised); border:1px solid var(--sidebar-border); border-radius:var(--radius);
    box-shadow:var(--shadow-md); padding:6px; max-height:min(70vh,420px); overflow:auto;
    z-index:calc(var(--z-sticky) + 2);
  }
  /* Dentro do dropdown, os `.side-item` deixam de ser "full-bleed"/crescer para fora do painel (não
     faz sentido numa caixa flutuante e pequena) — voltam a um botão de lista normal, cantos
     arredondados nos 4 lados. Especificidade (4 classes/seletores) já vence as regras de repouso/
     hover do desktop sem precisar de `!important`. */
  .app-sidebar.mobile-nav-open .side-nav .side-item{padding:12px 14px; border-radius:var(--radius-sm); margin-right:0;}
  .app-sidebar.mobile-nav-open .side-nav .side-item:hover{margin-right:0; padding-top:12px; padding-bottom:12px; border-radius:var(--radius-sm);}
  .app-sidebar.mobile-nav-open .side-nav .side-item.active:hover{margin-right:0; border-radius:var(--radius-sm);}
  .side-footer{display:none;}
}
/* "Sair" — item extra dentro de `#menuSideNav`, só para o dropdown móvel (pedido explícito: "o
   botão de sair deve vir como um menu, no final dos menus"; no desktop o Sair já vive no rodapé da
   sidebar, este item nunca aparece lá — `display:none` por omissão, só reativado dentro do dropdown
   móvel aberto, ver `@media` abaixo). Separador visual (`border-top`) para se distinguir das opções
   de navegação normais, já que é uma ação diferente (sair da conta, não trocar de vista).
   Bug real corrigido: a 1ª versão desta regra usava `#menuSideNav .side-item[...]` (com ID) — mais
   específico do que a regra de reativação abaixo (só classes), por isso o item NUNCA chegava a
   aparecer, nem dentro do dropdown móvel aberto. Corrigido tirando o ID daqui — `.side-nav` (classe)
   já identifica o mesmo elemento sem essa armadilha de especificidade. */
.side-nav .side-item[data-view="__logout"]{display:none;}
@media (max-width:900px){
  .app-sidebar.mobile-nav-open .side-nav .side-item[data-view="__logout"]{
    display:flex; margin-top:6px; padding-top:14px; border-top:1px solid var(--sidebar-border); border-radius:var(--radius-sm);
  }
}

.hidden{display:none !important;}
footer.note{text-align:left; color:var(--text-muted); font-size:11px; margin-top:26px; letter-spacing:.01em;}

/* ---------- Editor de fórmulas por linha (Notas às Contas) ---------- */
.formula-editor-wrap{width:100%; margin-top:8px; position:relative;}
.formula-cols-guide{display:flex; flex-wrap:wrap; gap:5px; margin-bottom:6px;}
.formula-col-chip{font-size:10.5px; padding:3px 9px; border-radius:var(--radius-pill); background:var(--bg-subtle); border:1px solid var(--border-strong); color:var(--text-muted); transition:background .12s, color .12s, border-color .12s;}
.formula-col-chip.active{background:var(--accent-2-tint); color:var(--accent-2); border-color:var(--accent-2); font-weight:700;}
.formula-col-chip.err{border-color:var(--danger); color:var(--danger);}
.formula-editor{min-height:40px; padding:9px 12px; border:1px solid var(--border-strong); border-radius:var(--radius-sm); background:var(--bg-surface); font-family:ui-monospace,'SFMono-Regular',Consolas,monospace; font-size:12.5px; line-height:1.6; white-space:pre-wrap; word-break:break-word; cursor:text; color:var(--text-primary);}
.formula-editor:focus{outline:none; border-color:var(--focus-ring); box-shadow:var(--glow-sm);}
.formula-editor:empty::before{content:attr(data-placeholder); color:var(--text-muted); font-style:italic;}
.tok-bal{color:var(--accent); font-weight:700;}
.tok-campo{color:var(--accent-2);}
.tok-sinal{color:var(--warning-strong);}
.tok-filtro{color:var(--warning);}
.tok-conta{color:var(--text-primary); font-weight:700;}
.tok-manual{color:var(--danger); font-weight:700; font-style:italic;}
.tok-personalizada{color:var(--success-strong); font-weight:700;}
.tok-sep{color:var(--text-muted); font-weight:400;}
.tok-sep.tok-slash{color:var(--accent); font-weight:700;}
.tok-error{text-decoration:wavy underline var(--danger); text-underline-offset:3px;}
.formula-sighelp{display:flex; flex-wrap:wrap; gap:4px 12px; margin-top:6px; padding:7px 10px; border-radius:var(--radius-sm); background:var(--bg-subtle); border:1px solid var(--border); font-size:11px; color:var(--text-muted);}
.formula-sighelp .param{display:inline-flex; align-items:center; gap:3px;}
.formula-sighelp .param.current{color:var(--accent); font-weight:700;}
.formula-sighelp .param.done{color:var(--accent-2);}
/* Sem borda — popover genuinamente flutuante, a sombra sozinha já define os limites (evita o padrão
   "ghost card" de borda + sombra larga ao mesmo tempo). */
.formula-autocomplete{position:absolute; z-index:var(--z-dropdown); margin-top:2px; background:var(--bg-surface); border-radius:var(--radius-sm); box-shadow:var(--shadow-md); max-height:190px; overflow:auto; min-width:200px;}
.formula-ac-item{padding:7px 12px; font-size:12.5px; cursor:pointer; color:var(--text-primary);}
.formula-ac-item.active{background:var(--accent-2-tint); color:var(--accent-2);}
.formula-warnings{margin-top:6px; font-size:11.5px; color:var(--danger); line-height:1.5;}
.formula-warnings:empty{display:none;}
.col1-toggle{display:flex; gap:8px; align-items:end; margin:8px 0;}
.col1-toggle select, .col1-toggle input{width:auto;}

/* ======================= CONCILIAÇÃO BANCÁRIA ======================= */
.conc-status-bar{display:flex; flex-wrap:wrap; border-top:1px solid var(--border);}
.conc-status-bar.hidden{display:none;}
.conc-filtros-row{display:flex; gap:14px; flex-wrap:wrap; margin-bottom:6px;}
.conc-filtros-row .field{flex:1; min-width:140px; margin-bottom:0;}
/* `top` é escrito em runtime (aplicarStickyConc, script.js) com a altura real do cabeçalho fixo —
   aqui só o essencial para a faixa ficar legível por cima do conteúdo que desliza por baixo dela. */
.conc-filtros-sticky{z-index:var(--z-sticky-sub); background:var(--bg-page); padding:10px 12px; margin:0 -12px 10px; border-radius:var(--radius-sm);}
.conc-cat-alert-link{cursor:pointer; text-decoration:underline; text-underline-offset:2px;}
.conc-cat-alert-link:hover{opacity:.82;}
.conc-origin-tag{font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:.02em; padding:2px 7px; border-radius:var(--radius-sm); background:var(--bg-subtle-strong); color:var(--text-muted); flex-shrink:0;}

/* Grelha partilhada por TODAS as Ferramentas (Conciliação Bancária e de IVA) — o painel lateral
   passou a ter largura FIXA, igual à da sidebar global (`--sidebar-width`, pedido explícito: "a
   largura ou width identica a nossa sidebar"), em vez de uma proporção (`fr`) do espaço disponível —
   por isso deixou de haver qualquer diferença entre módulos (a regra específica do IVA, que antes
   dava-lhe uma fatia diferente, foi removida — as duas telas usam agora exatamente esta única regra).
   O conteúdo principal (`1fr`) absorve sozinho todo o espaço que sobra. Espaço entre as duas colunas
   reduzido de 22px para 3px (pedido explícito — "muito espaço entre o painel informativo e o bloco à
   esquerda"; os blocos da coluna principal nunca tiveram margin-right nenhum, o espaço vinha só deste
   `gap` + a margin-left do painel, ver a seguir) — mesmo valor de 3px já usado no resto do painel.
   +15px pedidos explicitamente para o painel (`calc(...)`, não `--sidebar-width` diretamente — essa
   variável também define a largura da sidebar global de navegação, que não deve mudar); o `1fr` da
   coluna principal cede sozinho esses 15px, sem precisar de nenhuma regra própria do lado esquerdo. */
.conc-split-layout{display:grid; grid-template-columns:1fr calc(var(--sidebar-width) + 15px); gap:3px; align-items:start;}
.conc-split-layout > *{min-width:0;}
@media (max-width:980px){ .conc-split-layout{grid-template-columns:1fr;} }
/* margin/padding de 3px pedidos explicitamente para o painel em si (não os elementos lá dentro, ver
   `.conc-split-side .status-bar-item`/`.conc-side-box` abaixo) — padding só nas laterais (esquerda/
   direita). Margin-left removida (0, não 3px): o `gap` da grelha acima já separa as duas colunas —
   somar mais 3px aqui só devolveria o espaço em dobro que se acabou de tirar do `gap`. */
.conc-split-side{display:flex; flex-direction:column; gap:12px; margin:3px 3px 3px 0; padding:0 3px;}
/* min-width:0 — sem isto, um filho de flex herda min-width:auto por omissão (o seu conteúdo mais
   comprido/impartível vira um piso de largura que nunca encolhe) — mesmo "grid/flex blowout" já
   documentado noutros pontos desta app. Ficou ainda mais relevante agora que o painel tem largura
   fixa (igual à sidebar) em vez de crescer com o ecrã. Padding lateral de 3px pedido explicitamente
   (era 16px/20px, herdado da regra genérica `.status-bar-item`). */
.conc-split-side .status-bar-item{border:1px solid var(--border); border-radius:var(--radius-sm); background:var(--bg-surface); flex:none; min-width:0; padding-left:3px; padding-right:3px;}
/* Padding lateral de 3px pedido explicitamente (era 16px). */
.conc-side-box{border:1px solid var(--border); border-radius:var(--radius-sm); background:var(--bg-surface); padding:14px 3px;}
/* `.alert` genérico (styles.css, mais abaixo) reserva 40px de padding-esquerda para o ícone `::before`
   — dentro do painel informativo de 242px de largura útil, isso sozinho já criava a "muita distância"
   reportada entre o texto do alerta e a borda do painel (mais visível ainda em "Extratos &
   Configuração", onde o alerta de resumo é o único elemento visível ali). Mesmo padrão de 3px lateral
   já aplicado a `.status-bar-item`/`.conc-side-box` acima — o ícone não cabe nesta largura, por isso
   sai (`display:none`), o alerta passa a ser só texto, tal como os cartões de estatística ao lado. */
.conc-split-side .alert{padding:8px 3px; margin-bottom:0;}
.conc-split-side .alert::before{display:none;}

/* Tabelas duais (Banco/Contabilidade) de Conciliação, Classificação e Conciliados — ao contrário da
   regra genérica `table{width:auto;}` (pensada para as Notas, onde o conteúdo é normalmente curto),
   aqui o conteúdo deve preencher sempre toda a largura da coluna disponível; o scroll (vertical, quando
   há muitas linhas) continua a cargo de `.table-scroll{overflow:auto;}`, inalterado. Usada em QUALQUER
   tabela do módulo que precise de encher o espaço — com ou sem coluna de checkbox. */
.conc-table-fill table{width:100%; table-layout:auto;}
.conc-table-fill{max-height:480px;}
.taxas-cambio-ano th{background:var(--surface-2); color:var(--text); font-size:12px; font-weight:800; letter-spacing:.04em; text-align:left;}
/* Só as tabelas com checkbox (Manual/Classificação/Categorias do Conciliados) precisam de espremer a
   última coluna a 38px — aplicada à parte (`.conc-table-check`) para não estreitar por engano a última
   coluna de tabelas sem checkbox (ex.: "Método" em Grupos Conciliados, "Tipo" no preview do Exportar). */
.conc-table-fill.conc-table-check th:last-child, .conc-table-fill.conc-table-check td:last-child{width:38px; text-align:center;}

/* Conciliação de IVA costumava ter uma proporção própria (80/20, depois 85/15) — deixou de ser
   necessária: o painel lateral agora tem sempre largura FIXA igual à sidebar (ver `.conc-split-layout`
   acima), igual em qualquer Ferramenta, por isso a Conciliação Bancária e a de IVA já partilham a
   mesma regra sem overrides. */
/* Par de tabelas (Declaração/ECC na Conciliação de IVA; Banco/Contabilidade na Conciliação Manual
   bancária) que devem partilhar UMA ÚNICA barra de rolagem, com as linhas de cada lado já emparelhadas
   pela mesma posição (ver construirAlinhamentoManualIva/construirAlinhamentoManualConc) — pedido
   explícito para poder rolar a vista uma só vez e ver as duas tabelas avançarem juntas, em vez de cada
   uma ter o seu próprio scroll interno e desalinhar ao rolar só uma delas. As duas <table> ficam lado a
   lado dentro do MESMO `.table-scroll` (por isso só há um scrollbar vertical), cada uma dentro de um
   <div> flex item próprio — nunca `flex` diretamente no <table>: um <table> com `table-layout:auto`
   ignora `min-width:0` dentro de um flex container (quirk conhecido dos browsers, o algoritmo de
   sizing intrínseco da tabela não coopera com o encolhimento do flexbox), o que fazia a tabela com
   conteúdo mais largo (ex. a Descrição do ECC) empurrar a outra para um terço do espaço em vez de
   repartir a meio. Um <div> comum, sem essa sizing especial, encolhe/cresce corretamente — `flex:1 1 0`
   reparte o espaço a meio entre os dois, `min-width:0` evita que o conteúdo force overflow horizontal
   da página (só o próprio `.table-scroll`, que já tolera overflow-x, tal como qualquer outra pré-
   visualização densa da app). Sem colapso responsivo para 1 coluna — o alinhamento lado a lado é o
   próprio motivo de existir desta grelha, teria de desaparecer com ela. */
.tabelas-duplas-scroll{display:flex; gap:16px;}
.tabelas-duplas-scroll > div{flex:1 1 0; min-width:0;}
/* Linha "vazia" usada só para alinhar visualmente duas tabelas pela mesma posição (mesmo fornecedor/
   valor na mesma linha) — sem conteúdo nem checkbox, só ocupa a altura de uma linha normal para as duas
   tabelas não desalinharem uma da outra. Partilhada por Conciliação de IVA e Conciliação Bancária. */
.linha-vazia-alinhada td{color:transparent; user-select:none; background:var(--bg-subtle);}
/* Grupo conferido via "Forçar Ok" (fora da tolerância de ±1,99, confirmado à mão pelo técnico) — marcado
   a vermelho na pré-visualização de Conferidos, mesmos tokens já usados por .badge.bad. */
.iva-row-forcado td{background:var(--danger-tint); color:var(--danger-strong);}
/* Diferença entre os dois lados no resumo de seleção (Conciliação de IVA/Bancária) — negrito + vermelho,
   só para chamar a atenção do técnico e ajudá-lo a decidir se força a conciliação ou deixa para o
   relatório de não conciliados; nunca aparece quando a diferença é zero. Partilhada pelos dois módulos. */
.resumo-diferenca{font-weight:700; color:var(--danger-strong);}

/* Destaque de mapeamento (Extratos & Configuração): verde quando a coluna foi identificada com
   confiança (adivinhada por palavra-chave, aplicada de um modelo, ou já confirmada manualmente pelo
   utilizador); âmbar quando ainda é só um valor por omissão a confirmar — só se aplica a campos
   obrigatórios (opcionais deixados em "nenhuma" são uma escolha válida, não um alerta). */
.conc-field-ok select{border-color:var(--success-border); background:var(--success-tint);}
.conc-field-warn select{border-color:var(--warning-border); background:var(--warning-tint);}
/* Linha de conciliação manual desvanece rapidamente (~0.7s) em vez de desaparecer de repente — só opacity
   (nunca altura/margin: colapsar uma <tr> dentro de <table> é pouco fiável entre browsers); ao terminar
   a animação a linha já não existe nos dados, o próximo render fecha o espaço sozinho. */
@keyframes fc-fade-out{ from{opacity:1;} to{opacity:0;} }
.conc-row-fading{ animation:fc-fade-out .7s cubic-bezier(.16,1,.3,1) forwards; pointer-events:none; }
/* Classificação em Massa: caixa de filtro (40%) + caixa de aplicar/confirmar categoria (60%), lado a
   lado, dentro dos 70% principais do split — sobrepõe o display:flex de .conc-filtros-row. */
.conc-class-toolbar{display:grid; grid-template-columns:4fr 6fr; align-items:end;}
@media (max-width:760px){ .conc-class-toolbar{grid-template-columns:1fr;} }

/* Exportar: título/descrição à esquerda, botões de exportar ao topo-direita da mesma faixa — em vez de
   ficarem no fundo do cartão, como nos outros separadores que só têm um botão de ação. */
.conc-export-header{display:flex; justify-content:space-between; align-items:flex-start; gap:16px; flex-wrap:wrap;}

/* Selects Dia/Mês + input Ano do "Dados do Relatório" — um <input type="date"> nativo mostra a ordem
   dia/mês/ano segundo o locale do SO/browser (não controlável pela página), por isso os 2 campos de
   período usam este controlo próprio para garantir sempre dia → mês → ano, como pedido. */
.conc-date-dmy{display:flex; gap:6px; align-items:center;}
.conc-date-dmy select{width:auto; flex:0 0 auto;}
.conc-date-dmy input.conc-date-ano{width:4.5em; flex:0 0 auto;}

/* ======================= MODAL / DIALOG =======================
   Substitui os confirm()/prompt() nativos do browser (chrome cinzento fora do design system, sem
   marca nenhuma) por um diálogo consistente com o resto da app. Usa <dialog> nativo (escapa sempre
   a qualquer overflow:hidden/auto de um antepassado, ao contrário de um <div> position:absolute) —
   o backdrop é o próprio ::backdrop do elemento, sem precisar de um <div> extra a fazer de véu. Só
   abre/fecha via showModal()/close() (ver abrirDialog/confirmDialog em script.js); nunca com
   display/hidden manual, para o focus trap e o Esc nativos do <dialog> continuarem a funcionar. */
dialog.modal{
  border:none; border-radius:var(--radius-lg); padding:0; background:var(--bg-surface); color:var(--text-primary);
  box-shadow:var(--shadow-md); width:100%; max-width:420px; margin:auto;
}
dialog.modal::backdrop{background:rgba(11,11,12,.5);}
dialog.modal[open]{animation:fc-modal-in .16s cubic-bezier(.16,1,.3,1) both;}
@keyframes fc-modal-in{ from{opacity:0; transform:translateY(6px) scale(.98);} to{opacity:1; transform:none;} }
.modal-icon{width:38px; height:38px; border-radius:var(--radius); display:flex; align-items:center; justify-content:center; margin-bottom:14px;}
.modal-icon.danger{background:var(--danger-tint); color:var(--danger);}
.modal-icon.info{background:var(--accent-2-tint); color:var(--accent-2);}
.modal-body{padding:26px 26px 20px;}
.modal-title{font-size:16px; font-weight:700; margin:0 0 8px; color:var(--text-primary);}
.modal-text{font-size:13px; color:var(--text-secondary); line-height:1.6; margin:0;}
.modal-footer{display:flex; justify-content:flex-end; gap:10px; padding:16px 26px; background:var(--bg-subtle); border-radius:0 0 var(--radius-lg) var(--radius-lg);}
@media (prefers-reduced-motion: reduce){ dialog.modal[open]{animation:none;} }

/* ======================= TOAST =======================
   Substitui alert() nativo — não bloqueia a interação (ao contrário do alert() do browser) mas segue
   exatamente a mesma lógica de "avisar e devolver o controlo" que o código já tinha (return logo a
   seguir); some sozinho ao fim de alguns segundos, ou ao clicar. Pilha no canto inferior direito, sempre
   por cima de tudo (--z-toast), incluindo um modal aberto. */
#toastStack{
  position:fixed; z-index:var(--z-toast); display:flex; flex-direction:column; gap:10px; max-width:360px; pointer-events:none;
  right:max(20px, env(safe-area-inset-right)); bottom:max(20px, env(safe-area-inset-bottom));
}
.toast{position:relative; pointer-events:auto; display:flex; align-items:flex-start; gap:10px; padding:12px 14px; padding-right:34px; border-radius:var(--radius); background:var(--bg-surface); border:1px solid var(--border); box-shadow:var(--shadow-md); font-size:12.5px; line-height:1.5; color:var(--text-primary); cursor:default; white-space:pre-wrap;
  animation:fc-toast-in .22s cubic-bezier(.16,1,.3,1) both;}
.toast.leaving{animation:fc-toast-out .16s ease-in both;}
@keyframes fc-toast-in{ from{opacity:0; transform:translateY(8px);} to{opacity:1; transform:none;} }
@keyframes fc-toast-out{ from{opacity:1;} to{opacity:0; transform:translateY(4px);} }
.toast .icon{flex-shrink:0; margin-top:1px;}
.toast.error{border-color:var(--danger-border);}
.toast.error .icon{color:var(--danger);}
.toast.success{border-color:var(--success-border);}
.toast.success .icon{color:var(--success);}
.toast.info .icon{color:var(--accent-2);}
.toast-close{position:absolute; top:8px; right:8px; background:none; border:none; color:var(--text-muted); cursor:pointer; padding:3px; display:inline-flex; border-radius:var(--radius-sm);}
.toast-close:hover{background:var(--bg-subtle); color:var(--text-primary);}
@media (prefers-reduced-motion: reduce){ .toast{animation:none;} .toast.leaving{animation:none;} }

/* Spinner de carregamento — cobre o centro do ecrã enquanto um ficheiro grande está a ser lido/
   processado (ver iniciarCarregamento/terminarCarregamento, script.js); só chega a aparecer depois de
   300ms (agendado em JS), para nunca "piscar" em leituras rápidas. Mesmo z-index dos toasts — deve
   ficar visível por cima de tudo, incluindo um modal já aberto. */
.loading-overlay{position:fixed; inset:0; z-index:var(--z-toast); display:flex; align-items:center; justify-content:center; background:rgba(11,11,12,.18); pointer-events:none;}
.loading-spinner{width:36px; height:36px; border-radius:50%; border:4px solid var(--border-strong); border-top-color:var(--accent); animation:fc-spin .8s linear infinite;}
@keyframes fc-spin{ to{ transform:rotate(360deg); } }
@media (prefers-reduced-motion: reduce){ .loading-spinner{animation-duration:1.6s;} }

/* respeita utilizadores que pedem menos movimento */
@media (prefers-reduced-motion: reduce){
  *{ transition-duration:0.001ms !important; animation-duration:0.001ms !important; }
}

/* =========================================================================
   CENTRO DE RELATÓRIOS — editor visual de 3 painéis (ver centro-relatorios.editor.js)
   ========================================================================= */
.cr-editor-layout{display:flex; flex-direction:column; gap:14px;}
.cr-editor-toolbar-wrapper{display:flex; flex-direction:column;}
/* Pedido explícito: "nada de estar aí um bloco de configuração abaixo do outro para mantermos espaço
   visível suficiente" — nunca quebra para uma 2ª linha visual (flex-wrap:wrap deixava o nome/orientação/
   tamanho/margens empilharem-se em ecrãs mais estreitos); em vez disso, a própria barra ganha scroll
   horizontal próprio quando não há espaço, sem nunca "roubar" altura vertical ao resto do ecrã. */
.cr-editor-toolbar{display:flex; align-items:center; gap:10px; flex-wrap:nowrap; overflow-x:auto; padding:10px 14px; background:var(--bg-surface); border:1px solid var(--border); border-radius:var(--radius);}
/* Nome do template — 4,5cm fixos (pedido explícito), para sobrar espaço na linha 1 para orientação/
   tamanho/margens sem precisar de barra de rolagem. Seletor combinado `input.cr-editor-nome-input`
   (não só a classe sozinha) — a regra genérica `input[type=text]{width:100%}` (mesmo ficheiro, mais
   acima) tem a MESMA especificidade de um `input[type=X]` (elemento+atributo) e por isso vencia
   sempre uma classe sozinha (elemento+classe empata em especificidade com elemento+atributo; a
   ordem no ficheiro é que desempata — esta regra vem depois, por isso ganha). Sem isto, o `width`
   nunca chegava a aplicar-se e o campo crescia até quase preencher a barra toda. */
input.cr-editor-nome-input{width:4.5cm; flex:0 0 auto;}
/* Orientação/Tamanho do papel — a regra genérica `select{width:100%}` fazia estes dois <select>
   encolherem (flex-shrink) abaixo do texto da opção escolhida dentro da barra apertada, cortando
   "Retrato"/"A4" a meio; `width:auto` devolve o dimensionamento nativo do browser (sempre largo o
   bastante para a MAIOR opção da lista — nunca menos do que "Retrato" ou "A4"), `flex:0 0 auto`
   impede-o de voltar a ser espremido pelo layout flex da barra. */
.cr-editor-select-auto{width:auto; flex:0 0 auto;}
/* Lista de páginas (linha 2) — 3cm fixos, pedido explícito, para abrir espaço na linha. */
.cr-editor-paginas-select{width:3cm; flex:0 0 auto;}
/* Contexto e mês de referência: limites pedidos em cm convertidos para píxeis (96 dpi).
   O contexto longo não ocupa mais espaço que as ações da barra; o título completo continua no tooltip. */
.cr-editor-contexto-btn{width:151px; max-width:151px; min-width:0; overflow:hidden;}
.cr-editor-contexto-btn span{min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.cr-editor-mes-referencia-select{width:113px; min-width:113px; max-width:113px; flex:0 0 113px; overflow:hidden; text-overflow:ellipsis;}
/* Linha 2 (páginas/gravar/exportar) — nenhum botão/select pode encolher a ponto do seu próprio texto
   quebrar para uma 2ª linha (isso desalinhava a barra inteira verticalmente); preferível deixar a
   barra ganhar scroll horizontal (já suportado, ver .cr-editor-toolbar acima) a ter texto a quebrar. */
.cr-editor-toolbar-linha2 > *{flex-shrink:0; white-space:nowrap;}
.cr-autosave-status{font-size:12px; color:var(--text-muted); min-width:64px;}
/* Margens (cm) — pedido explícito, ver crCampoMargemCm/crRenderToolbar (centro-relatorios.editor.js);
   4 caixas pequenas, sem nada tão largo como um `<label>` genérico da app (mesma razão já documentada
   para `.switch`/`.skip-row label`, §2.13/§2.8 — um grupo de campos pequenos precisa de anular
   text-transform/margin da regra genérica `label{}`). */
.cr-margem-grupo{display:flex; align-items:center; gap:6px; padding:4px 8px; border:1px solid var(--border); border-radius:var(--radius-sm); background:var(--bg-page);}
.cr-margem-titulo{font-size:11px; color:var(--text-muted); text-transform:none; margin:0; white-space:nowrap;}
.cr-margem-campo{display:flex; align-items:center; gap:3px;}
.cr-margem-label{font-size:11px; color:var(--text-muted); text-transform:none; margin:0;}
.cr-margem-campo input{width:48px; padding:3px 4px; font-size:12px;}
.cr-editor-corpo{display:grid; grid-template-columns:220px 1fr 300px; gap:14px; align-items:start; min-height:0;}
@media (max-width:1100px){
  .cr-editor-corpo{grid-template-columns:1fr;}
  .cr-editor-biblioteca,.cr-editor-propriedades,.cr-editor-canvas{position:static; max-height:none; overflow:visible;}
}

/* Biblioteca de blocos — barra de rolagem própria (pedido explícito: "à medida que for colocando
   elementos... eu consiga rolar apenas a listagem dos blocos"), independente do resto da página, que
   pode crescer muito com um documento de várias páginas/blocos. `position:sticky` continua a manter
   a biblioteca visível ao rolar a página; o `max-height`+`overflow` novo garante que, mesmo assim, a
   PRÓPRIA lista nunca ultrapassa o espaço vertical disponível — ganha scroll interno em vez disso. */
.cr-editor-biblioteca{max-height:calc(100vh - 40px); overflow:auto;}
.cr-editor-biblioteca, .cr-editor-propriedades{background:var(--bg-surface); border:1px solid var(--border); border-radius:var(--radius); padding:14px; position:sticky; top:14px; max-height:calc(100vh - 28px); overflow:auto; box-sizing:border-box;}
.cr-editor-propriedades{overflow-x:hidden; overflow-y:scroll; scrollbar-gutter:stable;}
.cr-editor-biblioteca h3, .cr-editor-propriedades h3{margin:0 0 8px; font-size:13px; text-transform:uppercase; letter-spacing:.04em; color:var(--text-secondary);}
.cr-biblioteca-item{display:flex; align-items:center; gap:8px; padding:9px 10px; border:1px solid var(--border); border-radius:var(--radius-sm); margin-bottom:6px; cursor:grab; background:var(--bg-page); font-size:13px; color:var(--text-primary);}
.cr-biblioteca-item:hover{background:var(--bg-subtle); border-color:var(--border-strong);}
.cr-biblioteca-item:active{cursor:grabbing;}

.cr-editor-canvas{min-width:0; max-height:calc(100vh - 150px); overflow:auto; padding-right:4px;}
.cr-pagina-folha{background:var(--bg-surface); border:1px solid var(--border); border-radius:var(--radius); min-height:400px; margin:0 auto;}
/* Régua de largura de colunas — pedido explícito: "coloque acima de cada tabela ou quadro uma
   espécie de régua para eu definir a largura de cada coluna". Dois modelos, DUAS classes-modificador,
   sobre a mesma base `.cr-regua-largura`/`-seg`/`-handle`: (1) Centro de Relatórios
   (`crRenderReguaLargura`, .editor.js) — segmentos em PERCENTAGEM a somar sempre 100% (a exportação
   mede-se em fração de uma página/folha, largura fixa), com 2 puxadores extra nas extremidades
   (cr-regua-handle-borda) que repartem a diferença por todas as outras colunas (ver
   larguraEdgeRedistribuida, script.js); (2) Notas às Contas/Relatórios Mensais
   (`renderReguaLarguraNota`, script.js, `.cr-regua-largura-px`) — cada coluna com a sua PRÓPRIA
   largura em px, sem soma nenhuma obrigatória, um puxador na aresta direita de CADA coluna (incluindo
   a última) que só mexe nela própria — nunca nos vizinhos —, e a barra com scroll horizontal
   (overflow-x:auto) porque a soma pode ultrapassar a largura do cartão. */
.cr-regua-largura{display:flex; align-items:stretch; height:26px; margin-top:8px; border:1px solid var(--border); border-radius:var(--radius-sm); overflow:hidden;}
.cr-regua-largura-px{overflow-x:auto; overflow-y:hidden;}
.cr-regua-seg{display:flex; align-items:center; justify-content:center; min-width:0; padding:0 4px; background:var(--bg-subtle); font-size:10px; color:var(--text-muted);}
.cr-regua-seg span{overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.cr-regua-seg-editando{padding:1px 3px; background:var(--bg-surface);}
.cr-regua-largura-input{width:100%; min-width:0; height:20px; padding:1px 3px; font:inherit; text-align:center; color:var(--text-primary); border:1px solid var(--accent-strong); border-radius:3px; background:var(--bg-surface);}
.cr-regua-handle{width:6px; flex:none; background:var(--border-strong); cursor:col-resize;}
.cr-regua-handle:hover{background:var(--accent-2);}
.zoom-word-label{display:inline-flex; align-items:center; gap:5px; font-size:12px; font-weight:600; color:var(--text-secondary);}
.cr-canvas-vazio{text-align:center; color:var(--text-muted); font-size:13px;}
.cr-bloco-slot{height:10px; border-radius:var(--radius-sm); transition:background .12s;}
.cr-bloco-slot.cr-slot-ativo{background:var(--accent-tint); outline:2px dashed var(--accent-strong); outline-offset:-2px;}
/* Slot vazio (página sem nenhum bloco ainda) — o próprio slot que aceita o drop cresce e mostra o
   convite "Arrasta um bloco..." lá dentro, para o alvo visual e o alvo funcional serem a MESMA
   caixa (ver crRenderSlot em centro-relatorios.editor.js — antes eram 2 elementos diferentes, e só
   o menor/invisível dos dois aceitava o drop). */
.cr-bloco-slot-vazio{height:auto; min-height:140px; display:flex; align-items:center; justify-content:center; padding:40px 16px; border:1px dashed var(--border-strong);}
.cr-bloco-slot-vazio.cr-slot-ativo{border-style:dashed;}
.cr-bloco-item{border:1px solid var(--border); border-radius:var(--radius-sm); padding:10px 12px; margin:2px 0; cursor:grab; background:var(--bg-page);}
.cr-bloco-item:hover{border-color:var(--border-strong);}
.cr-bloco-item.cr-bloco-selecionado{border-color:var(--accent-strong); box-shadow:0 0 0 1px var(--accent-strong);}
.cr-bloco-item-cabecalho{display:flex; align-items:center; gap:8px; font-size:12.5px; font-weight:600; color:var(--text-secondary);}
.cr-bloco-item-label{flex:1;}
.cr-bloco-item-acoes{display:flex; gap:4px; margin-left:auto;}
.cr-bloco-item-acoes .icon-btn{width:26px; height:26px;}
.cr-bloco-item-preview{margin-top:6px; font-size:12.5px; color:var(--text-muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}

.cr-propriedades-tipo{font-weight:700; margin-bottom:10px; color:var(--text-primary);}

/* Preview (usado tanto no overlay de pré-visualização como, no futuro, dentro do próprio canvas) */
.cr-preview-overlay{position:fixed; inset:0; z-index:var(--z-modal); background:var(--bg-page); overflow:auto;}
.cr-preview-barra{position:sticky; top:0; z-index:1; display:flex; align-items:center; justify-content:space-between; gap:12px; padding:12px 20px; background:var(--bg-surface); border-bottom:1px solid var(--border); font-weight:600;}
/* Sem max-width fixo — a folha já traz a sua PRÓPRIA largura real (papel+margens do template, ver
   crDimensoesPaginaCss, centro-relatorios.render.js); centrado via flex, com scroll horizontal
   próprio (`.cr-preview-overlay{overflow:auto}` já existente) para papéis mais largos que o ecrã
   (ex. A3 paisagem) nunca ficarem cortados. */
.cr-preview-corpo{display:flex; flex-direction:column; align-items:center; margin:24px auto 60px; padding:0 16px;}
/* Pedido explícito: "deve aparecer a página seguinte uma de baixo da outra como no Word, com aquele
   espaço duns 14px a separar cada página" — cada página (crConstruirFolhaHtml) já é `min-height`, nunca
   corta conteúdo (cresce sozinha se precisar); a única mudança aqui é o espaço ENTRE páginas, 24px→14px. */
/* Separação entre páginas na pré-visualização — pedido explícito: 10px entre cada página (aplica-se
   a QUALQUER folha física resultante, não só entre páginas lógicas — ver
   crConstruirFolhasFisicasPagina, centro-relatorios.render.js). */
.cr-preview-folha{background:var(--bg-surface); border:1px solid var(--border); border-radius:var(--radius); margin-bottom:10px;}
.cr-preview-corpo-folha{min-width:0;}
.cr-preview-folha .cr-preview-corpo-folha{
  /* Guia visual da área realmente utilizável: as faixas de fora são as margens. */
  outline:1px dashed rgba(46,99,166,.34);
  outline-offset:-1px;
  background:linear-gradient(90deg,rgba(46,99,166,.035),transparent 14px,transparent calc(100% - 14px),rgba(46,99,166,.035));
}
.cr-preview-table tr.linha-negrito td{font-weight:700 !important;}
/* Posição/espaçamento entre blocos passou a ser SEMPRE por margem inline, por instância de bloco
   (ver `crMargensDoBloco`/`crAplicarMargemNode`, centro-relatorios.render.js — sempre vence qualquer
   margem declarada aqui, por maior especificidade do atributo `style`) — as classes abaixo já não
   declaram margem nenhuma, só tipografia/cor, para não sugerir um 2º mecanismo de espaçamento. */
.cr-preview-cabecalho, .cr-preview-rodape{font-size:11px; color:var(--text-muted);}
.cr-preview-titulo{margin:0;}
.cr-preview-titulo-nivel1{font-size:22px;}
.cr-preview-titulo-nivel2{font-size:18px;}
.cr-preview-titulo-nivel3{font-size:15px;}
.cr-preview-subtitulo{font-size:16px; margin:0;}
.cr-preview-texto{font-size:13.5px; line-height:1.15; white-space:pre-wrap; margin:0;}
.cr-preview-lista{margin:0; padding-left:22px; font-size:13.5px; line-height:1.7;}
.cr-preview-hr{border:none; border-top:1px solid var(--border-strong); margin:0;}
/* Índice — pedido explícito: "básta arrastar o elemento índice"; lista de entradas texto....página,
   indentada por nível (Título 1/2/3 + Subtítulo), com pontos-guia (leader dots) como um índice
   impresso clássico. */
.cr-preview-indice{margin:0;}
.cr-preview-indice h3{font-size:15px; margin:0 0 8px;}
.cr-preview-indice-tabela{width:100%; border-collapse:collapse; table-layout:auto;}
.cr-preview-indice-item{font-size:13px; line-height:1;}
.cr-preview-indice-texto{white-space:nowrap; overflow:hidden; text-overflow:ellipsis; padding:0; line-height:1; vertical-align:bottom;}
.cr-preview-indice-pontos{width:100%; min-width:14px; padding:0 6px; line-height:1; vertical-align:bottom; border-bottom:1px solid var(--border-strong);}
.cr-preview-indice-pagina{width:28px; padding:0; color:var(--text-muted); font-variant-numeric:tabular-nums; text-align:right; white-space:nowrap; line-height:1; vertical-align:bottom;}
.cr-grupo-canvas{border:1px dashed var(--accent-strong); background:color-mix(in srgb,var(--accent) 7%,var(--bg-surface));}
.cr-grupo-filhos{margin:8px 8px 8px 22px; padding-left:10px; border-left:2px solid var(--accent);}
.conteudo-editor-card{width:60%; box-sizing:border-box;}
@media (max-width:900px){.conteudo-editor-card{width:100%;}}
.cr-preview-quebra{display:flex; align-items:center; gap:6px; color:var(--text-muted); font-size:11px; text-transform:uppercase; letter-spacing:.05em; margin:0; padding-top:10px; border-top:2px dashed var(--border-strong);}
.cr-preview-semdados{padding:10px 12px; border:1px dashed var(--border-strong); border-radius:var(--radius-sm); color:var(--text-muted); font-size:12.5px;}
.cr-preview-bloco-tabela{margin:0;}
.cr-preview-bloco-tabela h3{font-size:13px; margin:0 0 6px;}
.cr-preview-table{width:100%; max-width:none; border-collapse:collapse; font-size:12.5px;}
/* Altura de linha — pedido explícito: "4px a mais para baixo ou cima em relação ao seu conteúdo,
   não pode ter mais espaço do que essa configuração" — só o padding vertical decide a altura. */
.cr-preview-table th, .cr-preview-table td{padding:4px 8px; border-bottom:1px solid var(--border);}
.cr-preview-table.sem-linhas-dados tbody td{border-bottom-color:transparent !important;}
/* Um só cabeçalho mantém a mesma altura visual das linhas de rodapé/total.
   Havendo cabeçalho de grupo, compactamos cada uma das duas linhas para o
   conjunto não ficar desproporcionalmente alto. */
.cr-preview-table th{padding-top:4px; padding-bottom:4px; text-align:left; background:var(--bg-subtle); font-weight:700;}
.cr-preview-table thead.cr-preview-thead-agrupado th{padding-top:3px; padding-bottom:3px;}
.cr-preview-table td.num, .cr-preview-table th.num{text-align:right; font-variant-numeric:tabular-nums;}
.word-simulacao-hover{position:fixed; z-index:9999; left:0 !important; top:0 !important; width:65vw !important; height:100vh; max-height:none; overflow:auto; padding:14px; background:var(--bg-surface); border-right:1px solid var(--border-strong); box-shadow:16px 0 36px rgba(0,0,0,.22); pointer-events:none;}
.word-simulacao-titulo{font-size:12px; font-weight:700; color:var(--text-secondary); margin-bottom:10px;}
.word-simulacao-folha{margin:0 auto; background:#fff; border:1px solid #d7d7d7; overflow:hidden; box-sizing:border-box;}
.word-simulacao-area{width:100%; overflow:hidden; outline:1px dashed rgba(46,99,166,.38); outline-offset:-1px; background:linear-gradient(90deg,rgba(46,99,166,.04),transparent 14px,transparent calc(100% - 14px),rgba(46,99,166,.04));}
.word-simulacao-conteudo{transform-origin:top left;}
.cr-preview-kpi{display:inline-block; min-width:170px; padding:12px 16px; border:1px solid var(--border); border-radius:var(--radius); margin:0;}
.cr-preview-kpi-rotulo{font-size:11px; color:var(--text-muted); text-transform:uppercase; letter-spacing:.04em;}
.cr-preview-kpi-valor{font-size:20px; font-weight:700; margin-top:4px;}
.cr-preview-grafico{margin:0; overflow:hidden;}
.cr-preview-grafico img{max-width:100%; object-fit:contain;}

/* padding aqui é a "moldura" interna da própria caixa de destaque (borda+fundo), não espaçamento
   entre blocos — mantido de propósito, distinto da margem (ver comentário acima). */
.cr-preview-caixa{padding:11px 14px; border-radius:var(--radius-sm); font-size:13px; line-height:1.55; margin:0; border:1px solid var(--border); border-left-width:4px; background:var(--bg-subtle); white-space:pre-wrap;}
.cr-preview-caixa.cr-tom-info{background:var(--accent-2-tint); border-color:var(--accent-2);}
.cr-preview-caixa.cr-tom-sucesso{background:var(--success-tint); border-color:var(--success-border); border-left-color:var(--success-strong);}
.cr-preview-caixa.cr-tom-aviso{background:var(--warning-tint); border-color:var(--warning-border); border-left-color:var(--warning-strong);}
.cr-preview-caixa.cr-tom-perigo{background:var(--danger-tint); border-color:var(--danger-border); border-left-color:var(--danger-strong);}

/* Múltiplas assinaturas — pedido explícito: "escolher o alinhamento da assinatura, para que fique
   no centro, esquerda e direita" — o grupo inteiro (1 ou várias) alinha-se pela escolha do
   utilizador (`cr-assinatura-align-*`), nunca mais um comportamento automático fixo (1=centro,
   2+=extremos). A "linha" já não é um `border-top`/`border-bottom` (CSS) — é texto literal
   (`.cr-preview-assinatura-linha`, ver crLinhaTextoAssinatura/crPintarBlocoHtmlConteudo), a mesma
   técnica usada no PDF/Word, para nunca poder "desaparecer" num dos 3 formatos. */
.cr-preview-assinatura{display:flex; gap:40px; flex-wrap:wrap; margin:0;}
.cr-preview-assinatura.cr-assinatura-align-esquerda{justify-content:flex-start;}
.cr-preview-assinatura.cr-assinatura-align-centro{justify-content:center;}
.cr-preview-assinatura.cr-assinatura-align-direita{justify-content:flex-end;}
.cr-preview-assinatura.cr-assinatura-align-justificado{justify-content:space-between; flex-wrap:nowrap;}
.cr-preview-assinatura-campo{min-width:160px; max-width:260px; text-align:center; font-size:11.5px;}
.cr-preview-assinatura-campo>div:first-child{color:var(--text-muted);}
.cr-preview-assinatura-linha{margin:0 0 0.3cm; white-space:nowrap; overflow:hidden;}
.cr-editor-propriedades .hint{display:none;}
/* Texto Divisórias — sempre centrado no meio da página por omissão (ver crPintarBlocoHtml,
   centro-relatorios.render.js — posiciona via top/left:50% + transform, relativo a `.cr-preview-folha`,
   que tem `position:relative` propositadamente para isto ancorar aqui, não à viewport inteira). */
.cr-preview-divisoria{white-space:nowrap; font-weight:600; letter-spacing:.06em;}
/* Linha em Colunas — pedido explícito: "colocar blocos na mesma linha... divididas na mesma
   proporção". Flexbox só na pré-visualização/canvas (nunca na exportação Word, que usa <table> —
   ver crExportarWord — o motor de HTML do Word não percebe display:flex). */
.cr-preview-linha-colunas{display:flex; gap:16px; align-items:flex-start;}
.cr-preview-linha-colunas-area{flex:1 1 0; min-width:0;}
/* "Elemento em linha" (div vs. span, ver crBlocoEmLinha/crAgruparEmLinhas, centro-relatorios.render.js)
   — 2+ blocos marcados para partilhar a mesma linha ficam lado a lado, dividindo a largura em partes
   iguais; um bloco sozinho (a maioria) nunca passa por este wrapper. */
.cr-preview-linha-simples{display:flex; gap:12px; align-items:flex-start;}
.cr-preview-linha-simples > *{flex:1 1 0; min-width:0;}

/* Autocomplete de variáveis ("{{#" no editor de propriedades) — mesmo padrão visual do
   .formula-autocomplete já usado no motor de fórmulas das Notas às Contas (dropdown flutuante,
   sombra + z-index de dropdown, sem borda — ver §2.13 do CLAUDE.md, "ghost card" evitado). */
.cr-var-autocomplete{position:absolute; left:0; right:0; top:100%; margin-top:2px; z-index:var(--z-dropdown); background:var(--bg-surface); border-radius:var(--radius-sm); box-shadow:var(--shadow-md); max-height:220px; overflow:auto;}
.cr-var-autocomplete-grupo{padding:6px 10px 2px; font-size:10.5px; font-weight:700; text-transform:uppercase; letter-spacing:.04em; color:var(--text-muted);}
.cr-var-autocomplete-item{display:flex; justify-content:space-between; gap:10px; padding:6px 10px; font-size:12.5px; cursor:pointer;}
.cr-var-autocomplete-item:hover, .cr-var-autocomplete-item:focus{background:var(--bg-subtle-strong);}
.cr-var-autocomplete-chave{font-family:monospace; color:var(--accent-strong); white-space:nowrap;}
.cr-var-autocomplete-label{color:var(--text-muted); text-align:right; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}

/* Exemplos clicáveis (Condição de Visibilidade) — pequenas pílulas que preenchem o campo com um
   ponto de partida, para quem "não sabe o que colocar" nunca precisar de escrever de cabeça. */
.cr-cond-exemplos{margin-top:6px; font-size:11.5px; color:var(--text-muted); display:flex; flex-wrap:wrap; align-items:center; gap:6px;}
.cr-chip-exemplo{font-family:monospace; font-size:11px; padding:2px 8px; border-radius:var(--radius-pill); border:1px solid var(--border); background:var(--bg-page); color:var(--text-secondary); cursor:pointer;}
.cr-chip-exemplo:hover{border-color:var(--accent-strong); color:var(--accent-strong);}

/* Painel "Estilo" partilhado (crCamposEstiloComuns) — Negrito/Itálico/Sublinhado, tamanho, cor do
   tema, deslocamento (setas), imagem de fundo — o MESMO painel para qualquer tipo de bloco. */
.cr-estilo-box{margin-top:16px; border-top:1px solid var(--border); padding-top:14px;}
.cr-estilo-titulo{display:flex; align-items:center; gap:6px; font-weight:700; font-size:12.5px; text-transform:uppercase; letter-spacing:.04em; color:var(--text-secondary); margin-bottom:10px;}
.cr-btn-nis{width:34px; height:30px; border-radius:var(--radius-sm); border:1px solid var(--border); background:var(--bg-page); color:var(--text-primary); font-size:14px; cursor:pointer;}
.cr-btn-nis:hover{border-color:var(--border-strong);}
.cr-btn-nis-ativo{background:var(--accent-2-tint); border-color:var(--accent-2); color:var(--accent-2);}
.cr-nudge-grid{display:flex; align-items:center; gap:6px; flex-wrap:wrap;}
.cr-nudge-grid .icon-btn{width:30px; height:30px;}
.cr-desloc-info{display:block; margin-top:6px; font-size:11.5px; color:var(--text-muted); font-family:monospace;}
