@font-face{font-family:"IBM Plex Sans";font-style:normal;font-weight:400;font-display:swap;src:url("../fonts/IBMPlexSans-Regular.5aaadb685d3c.woff2") format("woff2")}
@font-face{font-family:"IBM Plex Sans";font-style:normal;font-weight:500;font-display:swap;src:url("../fonts/IBMPlexSans-Medium.02ec16345450.woff2") format("woff2")}
@font-face{font-family:"IBM Plex Sans";font-style:normal;font-weight:600;font-display:swap;src:url("../fonts/IBMPlexSans-SemiBold.51d76d33ef85.woff2") format("woff2")}
/* Design system do SuperApp — "Fortaleza de pedra" (claro) + "Torre de comando" (escuro).
   Fonte única dos tokens: mudar aqui reveste todas as telas. */

:root {
  --canvas:        #F5F4F1;
  --surface-1:     #FBFAF8;
  --surface-2:     #FFFFFF;
  --border:        #DCD9D2;
  --border-strong: #C6C2B8;
  --text:          #23211D;
  --text-secondary:#56534C;
  --muted:         #8A867C;
  --primary:       #24406B;
  --primary-hover: #1C3355;
  /* o texto dos botões SECUNDÁRIOS (e das abas inativas, que herdam). No claro é o
     primary puro (10.4:1); no ESCURO o primary puro dá 4.02 sobre o surface-2 — abaixo
     do piso de 4.5 — então lá ele vira o primary-hover (5.1:1, medido em 28/08). */
  --sec-texto:     var(--primary);
  --on-primary:    #FFFFFF;
  --accent:        #9A6B34;
  --success:       #2E6B4F;
  --warning:       #B4791A;
  --danger:        #A33A2E;
  --radius:        10px;
  --font-sans:     "IBM Plex Sans", system-ui, -apple-system, sans-serif;
  /* interação */
  --ring:          rgba(36, 64, 107, .30);
  --shadow-1:      0 1px 2px rgba(24, 22, 18, .04), 0 2px 6px rgba(24, 22, 18, .05);
  --shadow-2:      0 4px 12px rgba(24, 22, 18, .08), 0 12px 28px rgba(24, 22, 18, .10);
  --dur:           .18s;
  --ease:          cubic-bezier(.2, .7, .25, 1);
  /* O SWITCH tem tempo proprio: o efeito de esticar nasce do DESENCONTRO entre a borda da
     frente e a de tras, e ele some se a duracao encolher para o `--dur` geral (.18s).
     Escolha do Tiago em 22/08, entre 5 animacoes. */
  --sw-dur:        190ms;
  --sw-atraso:     70ms;
  /* MOVIMENTO — os valores das duas animacoes da casa (envelope e arrasto).
     Sao TOKENS e nao literais porque cada um vive em MAIS DE UMA tela: enquanto
     fossem numeros repetidos, ajustar a cortina numa tela deixava as outras pra
     tras, calado. Norma e checklist no cerebro (design-system-painel, MOVIMENTO). */
  --mov-cortina:       .32s;                          /* abrir/fechar (.env, .rev) — .26s ate 28/08; Bernardo pediu 'um pouquinho mais lenta' */
  --mov-cortina-ease:  cubic-bezier(.4, 0, .2, 1);
  --mov-esmaece:       .2s;                           /* o conteudo aparecendo */
  --mov-esmaece-atraso:.04s;                          /* meio quadro depois da cortina */
  --mov-mola:          .4s;                           /* o encaixe ao pousar */
  --mov-mola-ease:     cubic-bezier(.34, 1.4, .64, 1);
  --mov-recebe:        .3s;                           /* o empurraozinho do alvo */
  --mov-carregado:     .4;                            /* opacidade do que saiu da mesa */
}

@media (prefers-color-scheme: dark) {
  :root {
    --canvas:        #14181D;
    --surface-1:     #1C222B;
    --surface-2:     #262D37;
    --border:        #313A46;
    --border-strong: #3E4A58;
    --text:          #E6EAF0;
    --text-secondary:#AEB8C4;
    --muted:         #93A0B0;
    --primary:       #4C8DD6;
    --primary-hover: #6AA0E0;
    --sec-texto:     var(--primary-hover);  /* primary puro daria 4.02 no surface-2 */
    --on-primary:    #0B0F14;
    --accent:        #2FA6A0;
    --success:       #3B9E6E;
    --warning:       #D0982E;
    --danger:        #D65B52;
    --ring:          rgba(76, 141, 214, .38);
    --shadow-1:      0 1px 2px rgba(0, 0, 0, .25), 0 2px 6px rgba(0, 0, 0, .30);
    --shadow-2:      0 4px 14px rgba(0, 0, 0, .40), 0 14px 32px rgba(0, 0, 0, .50);
  }
}

* { box-sizing: border-box; }
body {
  /* `dvh` (viewport dinâmico) acompanha a barra do navegador no mobile; o `vh` fica de
     reserva pra quem não tem `dvh`. Sem isso, o iOS mede 100vh com a barra ESCONDIDA e
     sobra um pedaço rolável embaixo — no Android/Chromium não acontece. */
  margin: 0; min-height: 100vh; min-height: 100dvh; background: var(--canvas); color: var(--text);
  font-family: var(--font-sans); font-size: 15px; line-height: 1.5;
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
  /* tira o flash cinza de toque do iOS (o Android não tem) — mesmo feedback nos dois */
  -webkit-tap-highlight-color: transparent;
}

/* foco acessível e consistente em tudo que é interativo */
:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 3px; }
a:focus-visible, button:focus-visible, .botao:focus-visible,
input:focus-visible, select:focus-visible, summary:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--ring); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; scroll-behavior: auto !important; }
}

/* slot de marca (usado na sidebar e na topbar mobile) */
.marca-monograma {
  width: 32px; height: 32px; border-radius: 8px; background: var(--primary);
  color: var(--on-primary); display: inline-flex; align-items: center; justify-content: center;
  font-size: 15px; font-weight: 600; flex: none;
}
.marca-logo { height: 32px; width: auto; }
.wordmark { font-size: 15px; font-weight: 600; letter-spacing: .2px; }

/* ===== shell: sidebar (desktop) + drawer (mobile) ===== */
/* topbar só aparece no mobile (esconde a sidebar atrás do ☰) */
.topbar-mobile {
  display: none; align-items: center; gap: 12px; position: sticky; top: 0; z-index: 20;
  padding: 10px 16px; background: var(--surface-2); border-bottom: 1px solid var(--border);
}

.sidebar {
  position: fixed; inset: 0 auto 0 0; width: 248px; z-index: 30;
  display: flex; flex-direction: column;
  background: var(--surface-2); border-right: 1px solid var(--border);
}
/* 🔴 25/08 — O MENU ROLAVA SEMPRE, e o número explica por quê: somando marca (64) + nav
   (825) + rodapé (169), a barra pedia **1.058px de viewport** pra não rolar. Nenhuma tela
   entrega isso — um monitor 1080p com o navegador maximizado dá ~950px. Ou seja, a barrinha
   de rolagem do menu não era "às vezes": era **sempre**, em toda página do app.
   ⚠️ E ela é PINTADA, não o overlay do sistema: o `* { scrollbar-width: thin }` lá embaixo
   (~l.1058) desenha uma barra de 10px em tudo que transborda. As duas coisas juntas é que
   produziam o que o Bernardo via.
   O ajuste devolve **156px** e leva a exigência pra ~900px, sem tirar item nenhum do menu:
   item de 39→33px, seção de 35→29, gap 2→1, e um pouco do topo e do rodapé.
   ⚠️ Isto NÃO some com a barra em tela baixa (um 13" dá ~750px) — lá ela continua, e é
   correto que continue: dezoito itens não cabem, e esconder a barra esconderia o resto. */
.sidebar-marca { display: flex; align-items: center; gap: 10px; padding: 14px 18px 10px; }
.sidebar-nav { display: flex; flex-direction: column; gap: 1px; padding: 6px 12px; overflow-y: auto; flex: 1; }
.sidebar-nav a {
  display: flex; align-items: center; padding: 6px 12px; border-radius: var(--radius);
  color: var(--text-secondary); text-decoration: none; font-size: 14px; font-weight: 500;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.sidebar-nav a:hover { background: var(--canvas); color: var(--text); }
.sidebar-nav a.ativo { background: color-mix(in srgb, var(--primary) 10%, transparent);
  color: var(--primary); font-weight: 600; box-shadow: inset 3px 0 0 var(--primary); }
.nav-secao { padding: 11px 12px 3px; font-size: 11px; letter-spacing: .07em;
  text-transform: uppercase; color: var(--muted); }

.sidebar-user { border-top: 1px solid var(--border); padding: 8px 12px; display: flex; flex-direction: column; gap: 2px; }
.sidebar-conta { display: flex; flex-direction: column; gap: 1px; padding: 8px 12px; border-radius: var(--radius);
  text-decoration: none; transition: background var(--dur) var(--ease); }
.sidebar-conta:hover { background: var(--canvas); }
.sidebar-conta-nome { font-size: 14px; font-weight: 600; color: var(--text); }
.sidebar-conta-sub { font-size: 12px; color: var(--muted); }
.sidebar-sair { padding: 8px 12px; border-radius: var(--radius); font-size: 13px; font-weight: 500;
  color: var(--text-secondary); text-decoration: none; transition: background var(--dur) var(--ease), color var(--dur) var(--ease); }
.sidebar-sair:hover { background: var(--canvas); color: var(--danger); }
/* ⬅️ Ícone e texto à ESQUERDA (Bernardo, 2026-08-04). O bloco base `button, .botao` traz
   `justify-content: center` (veio no #409, pra consertar o `<a class="botao">` do Histórico),
   e este botão é um `<button>` — herdava a centralização. Aqui o alinhamento acompanha os
   itens do menu logo acima, que são todos à esquerda. */
.sidebar-tema { display: flex; align-items: center; justify-content: flex-start; gap: 9px; width: 100%; padding: 8px 12px; border-radius: var(--radius);
  font-size: 13px; font-weight: 500; color: var(--text-secondary); background: none; border: 0; cursor: pointer;
  font-family: inherit; text-align: left; transition: background var(--dur) var(--ease), color var(--dur) var(--ease); }
.sidebar-tema:hover { background: var(--canvas); color: var(--text); }
.sidebar-tema .isvg { width: 17px; height: 17px; flex: none; }

.backdrop { position: fixed; inset: 0; z-index: 25; background: rgba(24, 22, 18, .38);
  -webkit-backdrop-filter: blur(1px); backdrop-filter: blur(1px); animation: fade var(--dur) var(--ease); }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }

/* conteúdo */
.conteudo { max-width: 520px; margin: 0 auto; padding: 32px 20px; }
.tem-sidebar .conteudo { margin-left: 248px; max-width: none; }
.tem-sidebar .conteudo > * { max-width: 760px; margin-left: auto; margin-right: auto; }
.conteudo--centro { min-height: 100vh; min-height: 100dvh; display: flex; align-items: center; justify-content: center; }
.tem-sidebar .conteudo--centro { min-height: calc(100vh - 64px); min-height: calc(100dvh - 64px); }

/* mobile: sidebar vira drawer off-canvas */
@media (max-width: 880px) {
  .topbar-mobile { display: flex; }
  .sidebar { transform: translateX(-100%); transition: transform var(--dur) var(--ease); box-shadow: var(--shadow-2); }
  .sidebar.aberto { transform: none; }
  /* 🔒 Drawer aberto TRANCA a página, igual ao popup. Só existe aqui dentro: o drawer é
     do mobile, e no desktop a sidebar é fixa e nunca "abre".
     Antes disto o JS ligava uma classe `drawer-aberto` cuja ÚNICA regra era
     `overflow: auto` (o valor padrão!) e no `@media` do DESKTOP — ou seja, **não havia
     regra base e o drawer nunca travou nada**, faz meses. A classe parecia mandar e não
     mandava. Foi apagada: quem já carrega o estado é o `.sidebar.aberto`. */
  body:has(.sidebar.aberto) { overflow: hidden; }
  .tem-sidebar .conteudo { margin-left: 0; }
  .conteudo { padding: 24px 16px; }
}
@media (min-width: 881px) {
  .backdrop { display: none; }
}

/* cartão */
.card { background: var(--surface-2); border: 1px solid var(--border); border-radius: 12px;
  padding: 32px; width: 100%; box-shadow: var(--shadow-1); }

/* tipografia */
h1 { font-size: 22px; font-weight: 600; letter-spacing: -.01em; margin: 0 0 4px; text-wrap: balance; }
.sub { margin: 0 0 20px; color: var(--muted); font-size: 14px; }
.foot { margin-top: 18px; font-size: 13px; color: var(--muted); }
a { color: var(--primary); text-underline-offset: 2px; transition: color var(--dur) var(--ease); }
a:hover { color: var(--primary-hover); }

/* formulários */
form { display: flex; flex-direction: column; gap: 12px; }
label { font-size: 13px; color: var(--text-secondary); font-weight: 500; }
input, select {
  height: 44px; padding: 0 14px; font-size: 16px; color: var(--text);
  background: var(--surface-1); border: 1px solid var(--border); border-radius: var(--radius);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), background var(--dur) var(--ease);
}
input::placeholder { color: var(--muted); }
/* o select era o único controle que não obedecia aos tokens: a seta era do navegador.
   `appearance:none` cala a nativa; o chevron vem do --chevron (que segue o tema). */
select {
  appearance: none; -webkit-appearance: none;
  padding-right: 38px;
  background-image: var(--chevron);
  background-repeat: no-repeat; background-position: right 13px center; background-size: 14px;
}
select[multiple] { background-image: none; padding-right: 8px; }
input:hover, select:hover { border-color: var(--border-strong); }
input:focus, select:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring); background: var(--surface-2); }

/* ============================================================
   DROPDOWN PRÓPRIO (dropdown.js) — a lista aberta desenhada por nós, no tema.
   O <select> nativo continua no DOM, só escondido (é o valor do form + fallback).
   ============================================================ */
.dd { position: relative; }
.dd > select {               /* o nativo: fora da vista, mas ainda no form */
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  opacity: 0; pointer-events: none; overflow: hidden; clip: rect(0 0 0 0);
}
/* o trigger imita o select nativo (mesma altura/cor/borda), com o chevron nosso */
.dd-trigger {
  display: flex; align-items: center; gap: 8px; width: 100%;
  height: 44px; padding: 0 12px 0 14px; font-size: 16px; font-family: inherit;
  color: var(--text); text-align: left; cursor: pointer;
  background: var(--surface-1); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: none;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), background var(--dur) var(--ease);
}
.dd-trigger .dd-val { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dd-trigger .dd-chevron { flex: none; color: var(--muted); transition: transform var(--dur) var(--ease); }
.dd-trigger:hover { border-color: var(--border-strong); background: var(--surface-1); box-shadow: none; transform: none; }
.dd-trigger:focus-visible { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring); background: var(--surface-2); }
.dd.aberta .dd-trigger { border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring); background: var(--surface-2); }
.dd.aberta .dd-chevron { transform: rotate(180deg); }
.dd-trigger:disabled { opacity: .55; cursor: not-allowed; }

/* a lista — o que o SO desenhava e não obedecia ao tema */
.dd-list {
  /* FIXED pra escapar do overflow:hidden do modal/painel (senao a lista era cortada dentro
     do popup). O JS (posicionar) dita left/top/width, ancorando no trigger no viewport. */
  display: none; position: fixed; z-index: 1000;
  overflow: hidden; padding: 6px;
  background: var(--surface-1); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-2);
}
.dd.aberta .dd-list { display: block; }
/* busca (dropdown com +5 opções) — fica fixa no topo; só as opções rolam */
.dd-busca { padding: 2px 2px 6px; }
.dd-busca-input {
  /* 16px pra o iOS não dar ZOOM ao focar o campo (só passa a mão em input <16px; no
     Android/Chromium não zooma) — mantém a mesma tela nos dois */
  width: 100%; box-sizing: border-box; padding: 8px 10px; font-size: 16px;
  color: var(--text); background: var(--surface-2);
  border: 1px solid var(--border); border-radius: 8px; outline: none;
}
.dd-busca-input::placeholder { color: var(--muted); }
.dd-busca-input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring); }
.dd-opcoes { max-height: 240px; overflow-y: auto; }
.dd-vazio { padding: 9px 11px; font-size: 14px; color: var(--muted); }
.dd-opt {
  padding: 9px 11px; font-size: 14.5px; color: var(--text); border-radius: 8px;
  cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dd-opt.foco { background: var(--surface-2); }                 /* teclado/hover */
.dd-opt.sel { color: var(--primary); font-weight: 600; }      /* o escolhido */
.dd-opt.sel.foco { background: color-mix(in srgb, var(--primary) 12%, var(--surface-2)); }
.dd-opt.off { color: var(--muted); cursor: not-allowed; }
@media (prefers-reduced-motion: reduce) { .dd-trigger, .dd-chevron { transition: none; } }
textarea { width: 100%; padding: 10px 14px; font-size: 16px; color: var(--text); font-family: inherit;
  background: var(--surface-1); border: 1px solid var(--border); border-radius: var(--radius); resize: vertical;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), background var(--dur) var(--ease); }
textarea::placeholder { color: var(--muted); }
textarea:hover { border-color: var(--border-strong); }
textarea:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring); background: var(--surface-2); }

/* checkbox e radio */
/* A checkbox era METADE nossa: `accent-color` pintava o marcado de azul, mas a caixa
   VAZIA continuava sendo a branca do sistema. Agora é nossa nos dois estados. Precisa
   zerar o que a regra genérica `input` põe (altura, padding, fundo), senão o
   `appearance:none` deixa tudo aparecer. */
input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  width: 18px; height: 18px; padding: 0; margin: 0; flex: none; cursor: pointer;
  background: var(--surface-2); border: 1.5px solid var(--border-strong); border-radius: 5px;
  box-shadow: none;
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
input[type="checkbox"]:hover { border-color: var(--primary); }
input[type="checkbox"]:checked {
  background-color: var(--primary); border-color: var(--primary);
  background-image: var(--tick); background-repeat: no-repeat;
  background-position: center; background-size: 12px;
}
input[type="radio"] { width: 16px; height: 16px; accent-color: var(--primary); flex: none; margin: 0; cursor: pointer; }

/* o ícone do seletor de data (Chromium): a cor vinha do TEXTO — aqui ele vira `--muted`,
   a MESMA do chevron do select. Os dois são a mesma coisa (a dica de que o campo abre
   algo), então têm que ter a mesma cor; era o único par fora do padrão.
   ⚠️ O Firefox desenha o dele e não deixa alcançar — lá o campo segue nativo. */
input[type="date"]::-webkit-calendar-picker-indicator {
  background-image: var(--calendario);
  background-repeat: no-repeat; background-position: center; background-size: 15px;
  width: 16px; height: 16px; padding: 0; margin: 0; opacity: 1; cursor: pointer;
  transition: opacity var(--dur) var(--ease);
}
input[type="date"]::-webkit-calendar-picker-indicator:hover { opacity: .65; }

/* seletor de cor (cadastro de Carreira: a cor do nível no organograma) — o nativo é
   minúsculo e desalinhado; damos tamanho de amostra clicável, na moldura do app */
input[type="color"].campo-cor {
  width: 64px; height: 38px; padding: 3px; cursor: pointer;
  border: 1px solid var(--border-strong); border-radius: var(--radius);
  background: var(--surface-2);
}
input[type="color"].campo-cor::-webkit-color-swatch-wrapper { padding: 0; }
input[type="color"].campo-cor::-webkit-color-swatch { border: none; border-radius: 4px; }
input[type="color"].campo-cor::-moz-color-swatch { border: none; border-radius: 4px; }

/* grupos de checkbox (M2M: unidades, departamentos) — <div id="id_..."> com <div><label><input></label></div> */
div[id^="id_"] { margin-top: 6px; padding: 6px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-1); max-height: 240px; overflow-y: auto;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 2px; }
div[id^="id_"] > div { margin: 0; }
div[id^="id_"] label { display: flex; align-items: center; gap: 8px; padding: 7px 9px; border-radius: 6px;
  font-weight: 400; font-size: 14px; color: var(--text); cursor: pointer; transition: background var(--dur) var(--ease); }
div[id^="id_"] label:hover { background: var(--canvas); }
/* 🔴 `display:inline-flex` no BASE (Bernardo, 2026-08-04). O bloco tinha `gap` e `height` mas
   NÃO tinha display — e `gap`/`height`/alinhamento **não valem em `display:inline`**. Em
   `<button>` passava batido (o navegador já centraliza o conteúdo); num `<a class="botao">`
   PURO, não: saía mais baixo, com o ícone colado no texto e fora do eixo. Só acontecia nos
   botões SEM variante — `--perigo` e `--ghost` já declaravam inline-flex por conta própria, e
   o "Histórico" da ficha era o único puro. Posto aqui, todo botão nasce alinhado e as variantes
   não precisam repetir. */
button, .botao {
  display: inline-flex; align-items: center; justify-content: center;
  height: 44px; padding: 0 18px; gap: 7px; border: none; border-radius: var(--radius);
  background: var(--primary); color: var(--on-primary); font-size: 15px; font-weight: 600;
  cursor: pointer; box-shadow: var(--shadow-1); font-family: inherit; text-decoration: none;
  transition: background var(--dur) var(--ease), transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
/* 🔴 O HOVER É POR CLASSE, NÃO POR ELEMENTO (Bernardo, 2026-08-04).
   Era `button:hover, .botao:hover` — seletor de ELEMENTO, que pegava TODO `<button>` da
   aplicação e impunha 4 propriedades (`background`, `color`, `box-shadow`, `transform`).
   Consequência: cada componente que é `<button>` mas não é botão primário tinha de DESLIGAR
   as quatro, uma por uma — e quem esquecia uma, herdava calado. A auditoria de 04/08 achou
   **5 casos de texto ilegível** (contraste 1.0–2.2, sendo 4.5 o mínimo): o dropdown perdia o
   texto no hover, o aviso também, o botão de tema, o "remover admin" e o subbotão read-only.
   Mais **9 componentes com o "pulo"** que o guia proíbe no subbotão.
   Agora só quem TEM a classe `.botao` recebe o tratamento de botão primário. Componente com
   estilo próprio não precisa mais desligar nada. */
.botao:hover { background: var(--primary-hover); color: var(--on-primary); box-shadow: var(--shadow-2); transform: translateY(-1px); }
.botao:active { transform: translateY(0); box-shadow: var(--shadow-1); }

/* avisos */
.erro { color: var(--danger); font-size: 14px; margin: 0 0 12px; }
.dev { background: var(--surface-1); border: 1px dashed var(--border-strong); border-radius: var(--radius);
  padding: 10px 12px; font-size: 13px; color: var(--muted); margin: 0 0 16px; }

/* checker: aviso de nível fora da faixa do cargo (só avisa, não bloqueia) */
/* TUDO laranja (--warning), não vermelho: é AVISO, não erro. O badge .ic-badge--alerta
   fica junto dos outros modificadores (.ic-badge--sup etc.), DEPOIS da base .ic-badge —
   senão a base sobrescreve a cor. */
/* banner logo abaixo da busca — colado nela (menos espaço em cima, mais embaixo) */
.us-toolbar:has(+ .aviso-checker) { margin-bottom: 6px; }
/* O aviso é um <button> (clicar filtra a lista). Como o `button` nu já nasce primário
   aqui, este bloco desfaz isso — sem ele o aviso vira um botão azul de 44px. */
.aviso-checker { display: flex; align-items: center; gap: 10px; margin: 0 0 18px -10px;
  font: inherit; font-size: 14px; color: var(--warning); text-align: left;
  width: auto; height: auto;   /* o `button` nu impõe 44px — aqui a altura é o conteúdo */
  background: transparent; border: 1px dashed transparent; border-radius: 10px;
  padding: 7px 10px; box-shadow: none; cursor: pointer; }
.aviso-checker:hover { background: color-mix(in srgb, var(--warning) 9%, transparent);
  border-color: color-mix(in srgb, var(--warning) 30%, transparent);
  box-shadow: none; transform: none; }
.aviso-checker:focus-visible { outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--warning) 32%, transparent); }
.aviso-checker.on { background: color-mix(in srgb, var(--warning) 13%, transparent);
  border-color: color-mix(in srgb, var(--warning) 42%, transparent); border-style: solid; }
.aviso-checker strong { font-weight: 600; }
/* o sinal de inconsistência DENTRO da linha da tabela, ANTES do nome. Na tabela não
   cabe a frase (em Cargos, 12 de 13 acendem — dobraria a altura da tela e mataria o
   que a tabela serve pra fazer). O ícone diz QUE tem, o `title` diz qual no hover, e o
   popup diz por extenso.
   🔴 É uma CAIXA (não o ícone pelado) e vem ANTES do nome — pedido do Bernardo
   (2026-07-16, no quadro): mesmo estilo do badge `.ic-badge--alerta`, tamanho de linha. */
/* 🔴 O marcador é um <button> desde 2026-08-04 (clicar abre o balão) — então precisa DESFAZER
   o `button` global (44px de altura, padding 18px, fundo `--primary` AZUL, sombra, e um hover
   que troca a cor e MOVE). Sem `padding:0`/`box-shadow:none`/`height` e o `:hover` próprio
   abaixo, o sinal viraria um botão azul grande. ⚠️ O `button:hover` global tem especificidade
   MAIOR que a classe nua — por isso o nosso hover é declarado explicitamente. */
.sinal-alerta { flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; padding: 0; border: none; box-shadow: none; border-radius: 6px;
  margin-right: 8px; font: inherit;
  background: color-mix(in srgb, var(--warning) 16%, var(--surface-2));
  color: var(--warning); cursor: pointer; transition: background var(--dur) var(--ease); }
.sinal-alerta:hover, .sinal-alerta[aria-expanded="true"] {
  background: color-mix(in srgb, var(--warning) 30%, var(--surface-2));
  color: var(--warning); box-shadow: none; transform: none; }
.sinal-alerta:focus-visible { outline: 2px solid var(--warning); outline-offset: 2px; }

/* O BALÃO com o motivo (Bernardo, 2026-08-04): no celular não há hover, então o `title`
   sozinho deixava o aviso mudo — dizia QUE havia problema e nunca QUAL.
   `position: fixed` pelo MESMO motivo do dropdown (ver l.216): a `.tabela-wrap` tem
   `overflow-x:auto` e cortaria um balão absoluto na borda. O `alerta.js` ancora no botão
   por `getBoundingClientRect`, como o dropdown faz. */
.sinal-balao { position: fixed; z-index: 60; max-width: min(320px, calc(100vw - 24px));
  background: var(--surface-2); color: var(--text); border: 1px solid var(--border);
  border-radius: 10px; box-shadow: var(--shadow-2); padding: 10px 12px;
  font-size: 13px; font-weight: 400; line-height: 1.45; text-align: left;
  white-space: normal; cursor: auto; }
.sinal-balao[hidden] { display: none; }
.sinal-balao b { display: block; color: var(--warning); font-size: 11px; letter-spacing: .04em;
  text-transform: uppercase; margin-bottom: 5px; }
.sinal-balao ul { margin: 0; padding-left: 15px; display: flex; flex-direction: column; gap: 4px; }
.sinal-balao li { margin: 0; }
/* a caixa do alerta + o nome numa linha só, centrados (Bernardo, 2026-07-17): o nome
   NÃO quebra e a caixa fica ANTES, colada e alinhada. É um `inline-flex` (não mexe no
   `<td>`, que segue célula de tabela — pôr `display:flex` no td bagunçaria o alinhamento
   com as outras colunas). Se o nome for longo demais, a `.tabela-wrap` (overflow-x) rola
   — melhor rolar do que quebrar. */
.cel-nome { display: inline-flex; align-items: center; max-width: 100%; white-space: nowrap; }
/* filtrado, a alça de arrastar (Níveis) sai de cena: não se reordena uma escada vendo
   só parte dela. A recusa de verdade está no `dragstart`; isto aqui é só o aviso visual. */
body.filtrando-alerta .drag { opacity: .35; cursor: not-allowed; }
/* aviso no RODAPÉ do card do suspeito — sem linha divisória */
.tcard-alerta { display: flex; align-items: center; gap: 9px; margin: 12px 0 0;
  font-size: 13px; color: var(--warning); line-height: 1.35; }

/* as inconsistências no TOPO do corpo do popup: o problema antes do remédio */
.incons { background: color-mix(in srgb, var(--warning) 9%, var(--surface-2));
  border: 1px solid color-mix(in srgb, var(--warning) 30%, var(--border));
  border-radius: 12px; padding: 12px 14px; margin: 0 0 18px; }
.incons-tit { display: flex; align-items: center; gap: 9px; font-size: 13.5px;
  font-weight: 600; color: var(--warning); margin-bottom: 8px; }
.incons-lista { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 6px; }
.incons-lista li { font-size: 13px; line-height: 1.5; color: var(--text-secondary); }

/* lista de itens (agentes, anotações) */
.linha { display: flex; align-items: center; gap: 12px; background: var(--surface-2);
  border: 1px solid var(--border); border-radius: 12px; padding: 14px; margin-bottom: 8px;
  box-shadow: var(--shadow-1); transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
.linha:hover { border-color: var(--border-strong); box-shadow: var(--shadow-2); }
.linha .nome { font-size: 15px; font-weight: 600; }
.linha .meta { font-size: 13px; color: var(--muted); }

/* semáforo de status */
.dot { width: 12px; height: 12px; border-radius: 50%; flex: none; }
.dot--verde { background: var(--success); }
.dot--vermelho { background: var(--danger); }
.dot--amarelo { background: var(--warning); }
.dot--cinza { background: var(--muted); }

/* botão ☰ da topbar mobile */
.menu-btn { background: transparent; color: var(--text); border: none; height: auto;
  padding: 4px 8px; font-size: 20px; line-height: 1; cursor: pointer; flex: none; border-radius: var(--radius);
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease); }
.menu-btn:hover { background: var(--canvas); color: var(--primary); }

/* selects multi (forms de gestão) */
select[multiple] { min-height: 132px; height: auto; padding: 8px; }
select[multiple] option { padding: 5px 8px; border-radius: 4px; }

/* tabela de gestão */
.tabela { width: 100%; border-collapse: collapse; font-size: 14px; background: var(--surface-2);
  border: 1px solid var(--border); border-radius: 12px; overflow: hidden; box-shadow: var(--shadow-1); }
.tabela th { text-align: left; color: var(--muted); font-weight: 600; font-size: 11px;
  text-transform: uppercase; letter-spacing: .04em; padding: 12px 14px;
  background: var(--surface-1); border-bottom: 1px solid var(--border); }
.tabela td { padding: 11px 12px; border-bottom: 1px solid var(--border); }
.tabela tr:last-child td { border-bottom: none; }
.tabela tbody tr { transition: background var(--dur) var(--ease); }
.tabela tr:hover td { background: var(--surface-1); }
/* Linha que abre alguma coisa se anuncia: sem o cursor, o alvo existe e ninguém descobre.
   Escopado em `.tabela--clicavel` para não prometer clique nas tabelas que não abrem nada. */
.tabela--clicavel tbody tr { cursor: pointer; }
.tabela a { text-decoration: none; font-weight: 500; }
/* 🔴 23/08: COLUNA DE NÚMERO ALINHA À DIREITA — e não alinhava.
   O extrato marcava `class="num"` nas colunas de dinheiro desde o primeiro dia, com a
   intenção clara de alinhar. Só que `.num` (l. ~560) faz apenas `tabular-nums`: não alinha
   NADA. E `.tabela th` acima força `text-align: left`, então nem o cabeçalho escapava.
   Marcação que declara a intenção certa e não tem regra por trás é letra morta — a coluna
   de dinheiro ficou à esquerda em produção sem ninguém notar.
   Fica aqui, no design system, porque a régua é da casa: número se lê pela direita, onde a
   vírgula de todas as linhas cai na mesma coluna. */
/* 🔴 `white-space: nowrap` NÃO é enfeite — e o número certo dele custou uma medição refeita.
   Medido em 25/08 no extrato: **a 1280px não quebra nada**; a **535px** (janela estreita,
   tablet) **4 de 6** células de dinheiro quebram em duas linhas — `R$` numa, `1.775,27` na
   outra. Com a regra, nenhuma quebra e a tabela ainda cabe sem rolar.

   ⚠️ A primeira versão deste comentário dizia "6 de 6 a 1280px". Era o INSTRUMENTO mentindo:
   eu contava célula com mais de 28px de altura, e a linha da tabela tem 44px por desenho.
   O detector certo é contar os retângulos de um `Range` sobre o texto. Defeito ANTIGO da
   tabela, exposto ao trocar o extrato para janela de datas. */
.tabela th.num, .tabela td.num { text-align: right; white-space: nowrap; }
.tabela td.acao { text-align: right; white-space: nowrap; width: 1%; }
.tabela td.acao a { font-weight: 500; font-size: 13px; }
.tabela td.acao a:hover { text-decoration: none; }

/* barra de título + ação */
.barra { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; gap: 12px; }
.botao--sec { background: var(--surface-2); color: var(--sec-texto); border: 1px solid var(--border);
  text-decoration: none; display: inline-flex; align-items: center; box-shadow: var(--shadow-1); }
/* ⬇️ `.botao--sec` TEM a classe `.botao`, então recebe o hover primário — e precisa desligar
   o "pulo" e a sombra, que o guia proíbe fora do botão primário (#52/#82). */
.botao--sec:hover { background: var(--surface-1); border-color: var(--border-strong); color: var(--primary-hover);
  box-shadow: none; transform: none; }
/* botão "Novo …": no mobile vira só o ícone "+" (o rótulo some da tela, mas fica pro leitor de tela) */
.botao--add { gap: 7px; justify-content: center; }
@media (max-width: 880px) {
  .botao--add { width: 44px; padding: 0; gap: 0; flex: none; }
  .botao--add .add-txt { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
}
.pill { display: inline-block; font-size: 12px; padding: 2px 10px; border-radius: 20px;
  background: var(--surface-1); color: var(--muted); border: 1px solid var(--border); font-weight: 500; }
.pill--on { color: var(--success); border-color: var(--success); background: color-mix(in srgb, var(--success) 8%, transparent); }


/* avisos (mensagens de sucesso/erro) */
.aviso { padding: 10px 14px; border-radius: var(--radius); font-size: 14px; margin: 0 0 16px;
  border: 1px solid var(--border); background: var(--surface-1); color: var(--text); }
.aviso--ok { border-color: var(--success); background: color-mix(in srgb, var(--success) 8%, transparent); }
.aviso--erro { border-color: var(--danger); background: color-mix(in srgb, var(--danger) 8%, transparent); }
.voltar { margin: 0 0 8px; font-size: 13px; }
.voltar a { text-decoration: none; }
.voltar a:hover { text-decoration: underline; }

/* perfil (só leitura) */
.perfil-dados { display: flex; flex-direction: column; gap: 1px; margin: 0 0 22px;
  background: var(--border); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; }
.perfil-dados > div { display: flex; justify-content: space-between; align-items: baseline; gap: 16px;
  padding: 13px 16px; background: var(--surface-2); }
.perfil-dados dt { font-size: 13px; color: var(--muted); font-weight: 500; }
.perfil-dados dd { margin: 0; font-size: 15px; font-weight: 500; color: var(--text);
  font-variant-numeric: tabular-nums; text-align: right; }
.perfil-acao { display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 16px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 12px;
  box-shadow: var(--shadow-1); }
.perfil-acao .nome { font-size: 15px; font-weight: 600; }
.perfil-acao .meta { font-size: 13px; color: var(--muted); margin-top: 2px; }
.perfil-acao .botao { flex: none; }

/* ===== painel — o cartão padrão da casa (o mesmo look da tela de perfil) ===== */
.painel { background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 12px; padding: 20px 22px; box-shadow: var(--shadow-1); }
.painel + .painel { margin-top: 16px; }

/* formulário dentro de painel: rótulo em cima, campo embaixo, respiro consistente */
.form-painel { max-width: 480px; }
.form-painel form { gap: 15px; }
.form-painel p { margin: 0; display: flex; flex-direction: column; gap: 6px; }
.form-painel p > label { font-size: 13px; color: var(--text-secondary); font-weight: 500; }
.form-painel .helptext { font-size: 12px; color: var(--muted); line-height: 1.4; }
.form-painel ul.errorlist { margin: 2px 0 0; padding: 0; list-style: none; color: var(--danger); font-size: 13px; }
/* campos booleanos (checkbox único): caixa + rótulo lado a lado, ajuda embaixo */
.form-painel p:has(> input[type="checkbox"]) { flex-flow: row wrap; align-items: center; gap: 4px 9px; }
.form-painel p:has(> input[type="checkbox"]) > input[type="checkbox"] { order: 1; }
.form-painel p:has(> input[type="checkbox"]) > label { order: 2; color: var(--text); font-weight: 400; }
.form-painel p:has(> input[type="checkbox"]) > .helptext { order: 3; flex-basis: 100%; }
.form-painel button[type="submit"] { align-self: flex-start; margin-top: 2px; }

/* ============================================================
   COMPONENTES DE PAINEL (reutilizáveis) — sala de controle,
   conexões e telas futuras. Aditivo: só consome os tokens da
   marca acima; estrutura fixa, cor/fonte vêm da marca.
   ============================================================ */
:root {
  --font-mono:  ui-monospace, "SF Mono", "Cascadia Code", "IBM Plex Mono", Menlo, Consolas, monospace;
  /* tintas de status derivam dos próprios tokens da marca -> adaptam por marca e por tema */
  --bg-verde:    color-mix(in srgb, var(--success) 14%, var(--surface-2));
  --bg-amarelo:  color-mix(in srgb, var(--warning) 16%, var(--surface-2));
  --bg-vermelho: color-mix(in srgb, var(--danger)  14%, var(--surface-2));
  --bg-cinza:    color-mix(in srgb, var(--muted)   12%, var(--surface-2));
  --bg-primary:  color-mix(in srgb, var(--primary) 12%, var(--surface-2));
  --hair:        color-mix(in srgb, var(--border)  55%, var(--surface-2));
}

/* ícone SVG (usa currentColor; some o emoji) */
.isvg { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; flex: none; }

/* utilitários numéricos */
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
.num  { font-variant-numeric: tabular-nums; }
.rotulo { font-size: 11.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); font-weight: 600; }

/* selo de status */
.selo { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600;
  padding: 3px 10px; border-radius: 999px; white-space: nowrap; }
.selo .ponto { width: 8px; height: 8px; border-radius: 50%; flex: none; background: currentColor; }
.selo--verde    { background: var(--bg-verde);    color: var(--success); }
.selo--amarelo  { background: var(--bg-amarelo);  color: var(--warning); }
.selo--vermelho { background: var(--bg-vermelho); color: var(--danger); }
.selo--cinza    { background: var(--bg-cinza);    color: var(--text-secondary); }

/* ── as MARCAS de uma movimentação (Movimentações, 28/08) ──────────────────────────────
   Quatro divisões de uma conta, e o vocabulário é do Tiago: RATEADA (entre centros de
   custo), COMPARTILHADA (entre categorias), PARCELADA (entre vencimentos/competências) e
   PARCIAL (uma parte baixada, outra aberta).

   🔑 UMA cor só, em quatro degraus. Régua do Tiago: sem verde nem vermelho (já dizem *pago*
   e *erro*), e o resto derivado da paleta, não escolhido a dedo. O `color-mix` com
   `--surface-2` é o mesmo idioma dos `--bg-*`; como `--surface-2`, `--text` e `--on-primary`
   viram com o tema, a rampa vira junto — clareia no claro, escurece no escuro, sem uma
   segunda tabela de cores para manter.

   Medido em 28/08, nos dois temas: separação entre degraus vizinhos de 58/60/162 (claro) e
   35/34/94 (escuro); contraste do texto de 12,59 a 5,57 — contra os 5,64 que o
   `.selo--cinza` já entrega. A ordem é por RARIDADE: quanto mais raro, mais forte o degrau
   (parcial 0,3% · rateada 2,8% · compartilhada 9,4% · parcelada 14,4%).

   ⚠️ Um `.selo--azul` sobre `--bg-primary` com texto `--primary` foi MEDIDO e reprovado:
   3,41 de contraste no escuro, abaixo do piso da própria casa. */
.selo--tom1 { background: color-mix(in srgb, var(--primary) 14%, var(--surface-2)); color: var(--text); }
.selo--tom2 { background: color-mix(in srgb, var(--primary) 32%, var(--surface-2)); color: var(--text); }
.selo--tom3 { background: color-mix(in srgb, var(--primary) 50%, var(--surface-2)); color: var(--text); }
.selo--tom4 { background: var(--primary); color: var(--on-primary); }

/* A marca vai em CAIXA ALTA e sem a bolinha (ordem do Tiago). O tamanho e o tracking são os
   que a casa já usa para caixa alta em `.tabela th`, `.rotulo` e `.sinal-balao b` — caixa
   alta sem tracking fica apertada, e isso já estava resolvido. */
.selo--marca { font-size: 11px; letter-spacing: .04em; text-transform: uppercase; gap: 0; }
.selo--marca:hover { filter: brightness(.96); }

/* Os selos de uma linha andam juntos e não empurram o texto ao lado. */
.selos { display: inline-flex; gap: 5px; vertical-align: middle; margin-left: 7px; }
/* No popup eles ficam centrados: ali não há texto ao lado para acompanhar. */
.selos--centro { display: flex; justify-content: center; margin: 0; }

/* ── duas linhas especiais de `.tabela`, e cada uma num CANAL diferente ────────────────
   🔴 As duas nasceram com fundo tingido e mediram **6 de distância** no tema claro —
   indistinguíveis. A linha "esta" volta ao idioma exato de `.dd-opt.sel` (cor e peso, sem
   fundo; a casa só tinge no `.sel.foco`, que é foco de teclado), e o fundo fica sendo canal
   exclusivo do total. */
.tabela tr.sel td { color: var(--primary); font-weight: 600; }
/* O tom do total sai de `--text` sobre `--surface-2`, então escurece no claro e clareia no
   escuro pela MESMA regra: 39 e 32 de distância do fundo da tabela. O `--canvas` media 38 no
   escuro mas só 20 no claro — o mesmo token daria destaques desiguais nos dois temas.
   Não usa `--surface-1`: esse é o fundo do `:hover` da `.tabela`. */
.tabela tr.tot td { border-top: 2px solid var(--border-strong); border-bottom: none;
                    background: color-mix(in srgb, var(--text) 10%, var(--surface-2));
                    font-weight: 600; padding-top: 13px; padding-bottom: 13px; }
.tabela tr.tot td.num { font-size: 15px; }
.tabela tr.tot:hover td { background: color-mix(in srgb, var(--text) 10%, var(--surface-2)); }

/* ⚠️ O `.num` da casa é `nowrap` — certo para dinheiro e data, errado para nome de
   fornecedor com CNPJ, que estoura os 412px úteis do popup. Dentro do corpo do modal o
   alinhamento à direita fica e a proibição de quebrar sai. */
.modal-corpo .tabela td.num { white-space: normal; }
.tabela td.num a { text-decoration: none; font-weight: 500; }
.tabela td.num a:hover { text-decoration: underline; }

/* grid de números (KPIs) */
.kpis { display: grid; grid-template-columns: repeat(var(--kpi-cols, 4), 1fr); gap: 1px;
  background: var(--hair); border: 1px solid var(--hair); border-radius: 10px; overflow: hidden; }
.kpi { background: var(--surface-2); padding: 12px 15px; }
.kpi .rotulo { margin-bottom: 6px; }
.kpi .v { font-size: 19px; font-weight: 640; letter-spacing: -.01em; }
.kpi .sub { font-size: 11.5px; color: var(--muted); margin-top: 3px; }
@media (max-width: 640px) { .kpis { grid-template-columns: repeat(2, 1fr); } }

/* verificações (checklist com ícone de status) */
.checklist { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 9px 20px; }
@media (max-width: 560px) { .checklist { grid-template-columns: 1fr; } }
.checklist li { display: flex; align-items: flex-start; gap: 9px; font-size: 14px; }
.check-ic { flex: none; margin-top: 1px; }
.check-ic--verde    { color: var(--success); }
.check-ic--vermelho { color: var(--danger); }
.check-ic--amarelo  { color: var(--warning); }
.checklist .k { font-weight: 500; }
.checklist .d { font-size: 12px; color: var(--text-secondary); margin-top: 1px; }
.checklist .d em { font-style: normal; color: var(--muted); }

/* linha do tempo de saúde (24h) */
.tl { display: flex; align-items: flex-end; gap: 3px; height: 24px; }
.tl i { flex: 1; min-width: 4px; height: 100%; border-radius: 2px; background: var(--bg-cinza); }
.tl i.verde { background: var(--success); } .tl i.amarelo { background: var(--warning); } .tl i.vermelho { background: var(--danger); }
.tl-legenda { display: flex; gap: 14px; margin-top: 8px; font-size: 11.5px; color: var(--muted); flex-wrap: wrap; }
.tl-legenda span { display: inline-flex; align-items: center; gap: 5px; }
.tl-legenda b { width: 9px; height: 9px; border-radius: 2px; display: inline-block; }
/* o rodapé da barra: legenda à esquerda, "Checado há X" à direita, numa linha só.
   O "Checado" morava no topo do cartão; desceu em 31/08 pra liberar o topo-direita
   pro saldo. Em tela estreita ele quebra pra baixo da legenda, sem espremer nada. */
.tl-rodape { display: flex; align-items: center; justify-content: space-between;
             gap: 14px; flex-wrap: wrap; margin-top: 8px; }
.tl-rodape .tl-legenda { margin-top: 0; }
/* valor de KPI que virou aviso — hoje só o saldo baixo. É o número que avisa, sem
   precisar de mais um selo na tela. */
.v--alerta { color: var(--warning); }

/* bandas internas do painel (separadas por fio) */
.banda { padding-top: 14px; margin-top: 14px; border-top: 1px solid var(--hair); }

/* ============================================================
   Seletor de tema manual (claro/escuro) + peças dos cadastros.
   [data-theme] vence o @media (o usuário escolhe; senão segue o SO).
   ============================================================ */
:root[data-theme="light"]{
  --canvas:#F5F4F1; --surface-1:#FBFAF8; --surface-2:#FFFFFF; --border:#DCD9D2; --border-strong:#C6C2B8;
  --text:#23211D; --text-secondary:#56534C; --muted:#8A867C; --primary:#24406B; --primary-hover:#1C3355;
  --sec-texto:var(--primary);
  --on-primary:#FFFFFF; --accent:#9A6B34; --success:#2E6B4F; --warning:#B4791A; --danger:#A33A2E;
  --ring:rgba(36,64,107,.30);
  --shadow-1:0 1px 2px rgba(24,22,18,.04),0 2px 6px rgba(24,22,18,.05);
  --shadow-2:0 4px 12px rgba(24,22,18,.08),0 12px 28px rgba(24,22,18,.10);
}
:root[data-theme="dark"]{
  --canvas:#14181D; --surface-1:#1C222B; --surface-2:#262D37; --border:#313A46; --border-strong:#3E4A58;
  --text:#E6EAF0; --text-secondary:#AEB8C4; --muted:#93A0B0; --primary:#4C8DD6; --primary-hover:#6AA0E0;
  --sec-texto:var(--primary-hover);
  --on-primary:#0B0F14; --accent:#2FA6A0; --success:#3B9E6E; --warning:#D0982E; --danger:#D65B52;
  --ring:rgba(76,141,214,.38);
  --shadow-1:0 1px 2px rgba(0,0,0,.25),0 2px 6px rgba(0,0,0,.30);
  --shadow-2:0 4px 14px rgba(0,0,0,.40),0 14px 32px rgba(0,0,0,.50);
}

/* ============================================================
   CONTROLES NATIVOS — o navegador precisa SABER o tema.
   Sem `color-scheme`, ele desenha as partes que são dele (a seta do select, a LISTA
   que abre, a caixa da checkbox, as barras de rolagem) sempre em CLARO — era o
   retângulo branco no meio do tema escuro. A lista aberta é a única peça que CSS
   nosso não alcança: só o `color-scheme` a conserta. Segue o [data-theme] (o botão
   do usuário), não só o @media — senão trocar o tema na mão não levava os nativos.
   O chevron e o tique são SVG: `var()` não funciona dentro do data-URI, então cada
   tema traz o seu.
   ============================================================ */
:root{
  color-scheme: light;
  --chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%238A867C" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>');
  --tick: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23FFFFFF" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>');
  --calendario: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%238A867C" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M16 3v4M8 3v4M3 11h18"/></svg>');
}
@media (prefers-color-scheme: dark){
  :root{
    color-scheme: dark;
    --chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%2393A0B0" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>');
    --tick: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%230B0F14" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>');
    --calendario: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%2393A0B0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M16 3v4M8 3v4M3 11h18"/></svg>');
  }
}
:root[data-theme="light"]{
  color-scheme: light;
  --chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%238A867C" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>');
  --tick: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23FFFFFF" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>');
  --calendario: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%238A867C" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M16 3v4M8 3v4M3 11h18"/></svg>');
}
:root[data-theme="dark"]{
  color-scheme: dark;
  --chevron: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%2393A0B0" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>');
  --tick: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%230B0F14" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>');
  --calendario: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%2393A0B0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M16 3v4M8 3v4M3 11h18"/></svg>');
}

/* ============================================================
   TROCA DE TEMA: 1s (Bernardo, 2026-08-04 — a medida escolhida)

   Três versões até chegar aqui, e o que cada uma ensinou:
     · antes do #195 — instantânea: seca demais;
     · #195 — **1s com `!important`** e o botão TRAVADO no intervalo: a tela ficava um
       segundo parada no meio do caminho, nem clara nem escura, e o clique não respondia.
       Foi revertida no mesmo dia (o Bernardo flagrou em captura de tela);
     · 0,2s — curta demais pro gosto dele;
     · agora — **1s**, mas SEM as duas coisas que estragaram o #195 (ver abaixo). A duração
       nunca foi o problema: o problema era a tela ficar TRAVADA durante ela.

   O que fica de fora, de propósito, porque foi o que causou o estrago:
     🔴 **sem `!important`** — cada componente tem a sua transição (a dos campos é 0,18s) e
        ela não pode ser atropelada; as duas são curtas, então convivem;
     🔴 **sem travar o botão** — clicar duas vezes seguidas tem que funcionar.

   A regra só vale enquanto o JS mantém `.trocando-tema` no <html> (1s, ver base.html):
   fora dela, hover e foco seguem instantâneos — senão a interface inteira fica lenta.
   Reduced-motion pula o fade. ============================================================ */
@media (prefers-reduced-motion: no-preference){
  html.trocando-tema,
  html.trocando-tema *,
  html.trocando-tema *::before,
  html.trocando-tema *::after{
    transition: background-color 1s ease, border-color 1s ease,
                color 1s ease, fill 1s ease, box-shadow 1s ease;
  }
}

/* seletor de tema — discreto, canto superior direito */
.tema-btn{ position:fixed; top:12px; right:14px; z-index:40; display:inline-flex; align-items:center; gap:7px;
  font-size:13px; color:var(--text-secondary); background:var(--surface-2); border:1px solid var(--border);
  border-radius:999px; padding:6px 12px; cursor:pointer; box-shadow:var(--shadow-1); font-family:inherit;
  transition:border-color var(--dur) var(--ease), color var(--dur) var(--ease); }
.tema-btn:hover{ border-color:var(--primary); color:var(--text); }
.tema-btn .isvg{ width:15px; height:15px; }
@media (max-width:880px){ .tema-btn{ top:9px; padding:7px; } .tema-btn .txt{ display:none; } }

/* cadastros — cabeçalho da lista */
.barra-tit{ display:flex; align-items:center; gap:11px; min-height:44px; }
/* o subtítulo não cola no título: mesma folga que as listas (.barra) já dão até o .sub */
.barra-tit + .sub { margin-top: 16px; }
/* título sem barra-tit (home "Olá", login, landing): mesma folga de 16px */
h1 + .sub { margin-top: 16px; }
/* cabeçalho (ícone + título) não cola no card do form: dá a mesma folga das listas */
.barra-tit + .painel { margin-top: 16px; }
.ic-badge{ width:34px; height:34px; border-radius:9px; flex:none; display:flex; align-items:center; justify-content:center;
  background:color-mix(in srgb, var(--primary) 12%, var(--surface-2)); color:var(--primary); }
.conta{ font-size:12px; color:var(--muted); background:var(--surface-1); border:1px solid var(--border);
  border-radius:999px; padding:2px 10px; font-variant-numeric:tabular-nums; }

/* cadastros — tabela com rolagem no mobile + ação em botão */
.tabela-wrap{ overflow-x:auto; border:1px solid var(--border); border-radius:12px; box-shadow:var(--shadow-1); }
.tabela-wrap .tabela{ border:none; border-radius:0; box-shadow:none; }
.acao-btn{ display:inline-flex; align-items:center; gap:6px; font-size:13px; font-weight:500; text-decoration:none; white-space:nowrap;
  height:auto; padding:6px 12px; border:1px solid var(--border); border-radius:var(--radius);
  color:var(--text); background:var(--surface-1); box-shadow:none; cursor:pointer;
  transition:border-color var(--dur) var(--ease), color var(--dur) var(--ease); }
.acao-btn:hover{ border-color:var(--primary); color:var(--primary); background:var(--surface-1); box-shadow:none; transform:none; text-decoration:none; }
/* variante read-only: destino sem acesso (botão inoperante, visual claro) */
.acao-btn--ro{ color:var(--muted); background:var(--surface-1); border:1px dashed var(--border-strong); cursor:not-allowed; opacity:.85; }
.acao-btn--ro:hover{ border-color:var(--border-strong); color:var(--muted); }
/* subbotão 2: variante TRACEJADA pra afford de "adicionar/inserir" (design-system-painel) */
.acao-btn--add{ border:1px dashed var(--border-strong); color:var(--primary); }
/* botão SÓ-ÍCONE: 30px quadradinho, ghost, hover danger/primário (design-system-painel) */
.item-ic{ all:unset; box-sizing:border-box; width:30px; height:30px; border-radius:8px; flex:none;
  display:inline-flex; align-items:center; justify-content:center; color:var(--muted); cursor:pointer;
  border:1px solid transparent; transition:background var(--dur) var(--ease), color var(--dur) var(--ease), border-color var(--dur) var(--ease); }
.item-ic .isvg{ width:15px; height:15px; }
/* Antes, o hover deste botão vinha do `button:hover` global (virava bloco azul cheio). Com o
   hover por classe ele ficaria SEM feedback nenhum — e o guia pede "ação clara no hover" pro
   botão só-ícone (#136). Este é o neutro; as variantes `--danger`/`--primary` seguem por cima. */
.item-ic:hover{ color:var(--text); background:var(--surface-1); border-color:var(--border); }
.item-ic:disabled{ opacity:.5; cursor:not-allowed; }
.item-ic--danger:hover{ color:var(--danger); background:color-mix(in srgb,var(--danger) 10%,transparent); border-color:color-mix(in srgb,var(--danger) 22%,var(--border)); }
.item-ic--primary:hover{ color:var(--primary); background:color-mix(in srgb,var(--primary) 10%,transparent); border-color:color-mix(in srgb,var(--primary) 22%,var(--border)); }
/* SPINNER de carregamento no botão que submete — PADRÃO do app (o modal.js liga `.carregando`
   ao submeter; o botão só-ícone `.item-ic` fica de fora). Anel girando via ::before, na cor do
   texto do botão (branco no primário). Opção 4 do mock de 10, escolhida pelo Tiago (2026-07-19). */
@keyframes botao-spin{ to{ transform:rotate(360deg); } }
button.carregando, .botao.carregando{ cursor:progress; display:inline-flex; align-items:center; justify-content:center; gap:8px; opacity:1; }
button.carregando::before, .botao.carregando::before{ content:""; width:14px; height:14px; flex:none; border-radius:50%;
  border:2px solid color-mix(in srgb, currentColor 32%, transparent); border-top-color:currentColor;
  animation:botao-spin .7s linear infinite; }
/* 🔴 Botão COM ÍCONE: o anel toma o LUGAR do ícone, não soma (Bernardo, 2026-08-19).
   O anel entra como `::before` — num botão só com texto ele fica à frente do rótulo e está
   certo. Num botão com ícone ele vira um SEGUNDO desenho, e a caixa cresce 14px + 8px de gap.
   No celular o `.botao--add` é um quadrado FIXO de 44px com `gap:0`: o anel somado estourava
   a caixa e empurrava o layout (foto do Bernardo, Fornecedores no Android).
   A regra antiga já excluía `.item-ic` — mas exclusão POR CLASSE não alcança este caso: o
   `.botao--add` tem rótulo no desktop e vira só-ícone por LARGURA DE TELA, e nenhuma classe
   muda junto. Trocar em vez de excluir também é melhor: o botão continua dando sinal de que
   está trabalhando, que numa sincronização de ~12s é o que a pessoa precisa ver.
   O ícone volta sozinho quando a página recarrega (o POST redireciona). */
/* `display:none`, não `visibility:hidden`: escondido mas NO FLUXO o ícone ainda gera o
   seu `gap`, e o botão com rótulo pulava 13px ao começar a girar. */
.botao.carregando:has(.isvg) .isvg{ display:none; }
/* `box-sizing:border-box` é o que faz o anel medir 16px de VERDADE: sem ele a borda de
   2px fica FORA e a caixa vira 20px — 4 dos 5px que o botão pulava. O 5º era o `gap`
   (8px do `.carregando` contra os 7px do botão), e 1px ninguém vê. */
button.carregando:has(.isvg)::before, .botao.carregando:has(.isvg)::before{
  box-sizing:border-box; width:16px; height:16px; }
/* mensagem de erro do write-back: INLINE no rodapé, à ESQUERDA — empurra o Salvar pro canto direito. */
.acoes-form .acao-erro{ margin-right:auto; font-size:13px; color:var(--danger); text-align:left;
  display:flex; align-items:center; gap:7px; }
.cod{ font-family:var(--font-mono); }
.marca-chip{ display:inline-flex; align-items:center; gap:7px; }
.marca-chip .sw{ width:11px; height:11px; border-radius:3px; flex:none; border:1px solid rgba(0,0,0,.12); }

/* cadastros — ações do formulário (Salvar + Cancelar) */
/* 🔴 A ação principal vai pro CANTO INFERIOR DIREITO — no popup E NA PÁGINA.
   (Bernardo, 2026-07-22: *"Salvar tem que ir para a direita, siga esse padrão"*.)

   ⚠️ Isto MUDA a norma de 2026-07-16 (#186), que mandava direita **só no popup** e
   esquerda na página cheia — o argumento de então era que na página o "Cancelar" é um
   link de volta e o par Salvar+Cancelar tinha que ler junto. O Bernardo viu as duas
   telas lado a lado e escolheu um alinhamento só, pra o botão estar sempre no mesmo
   lugar. Vale pra TODOS os formulários, não só o de usuário: meia mudança deixaria o
   app com dois padrões, que é pior que qualquer um dos dois.
   _(Histórico: no #184 a ação subiu pro cabeçalho e o rodapé foi apagado; ele viu no
   escuro e mandou voltar pro fim.)_ */
/* o bloco automático da ficha: muitos campos curtos, em grade que se ajusta */
.form-painel .ficha-resto{ display:grid; grid-template-columns:1fr 1fr; gap:15px; }
.form-painel .ficha-resto > p{ min-width:0; }
@media (max-width: 640px){ .form-painel .ficha-resto{ grid-template-columns:1fr; } }

/* topo da subpágina: Voltar à ESQUERDA, ação de PERIGO à DIREITA (Bernardo, 22/07).
   Ficaram juntos na 1ª versão; ele pediu separados — e faz sentido: colar o Desligar
   no Voltar põe a ação destrutiva no caminho do dedo de quem só queria sair da tela. */
.topo-acoes{ display:flex; align-items:center; gap:10px; margin:0 0 18px; }
.topo-acoes .botao--perigo{ margin-left:auto; }

.acoes-form{ display:flex; gap:10px; margin-top:22px; align-items:center;
  justify-content: flex-end; }
/* 🔴 No POPUP o Salvar GRUDA no rodapé (Bernardo, 2026-08-03) — sempre visível, sem rolar.
   Por quê: quem rola o `.modal-corpo` é o corpo, e o Salvar ia no fim do formulário; num
   cadastro alto (Cargos, Usuários) ele nascia FORA da área visível. Custou um caso real —
   o "Gerente Regional de Operações" ficou sem par no Tangerino porque o modal foi fechado
   no ✕ sem que o Salvar tivesse sido visto. Botão que não aparece é botão que não se clica.
   Ele CONTINUA no fim, canto inferior direito (a norma de 2026-07-16/22): o sticky muda
   só a VISIBILIDADE — não sobe pro cabeçalho, caminho já rejeitado no #184.
   As margens negativas LATERAIS esticam a faixa até as bordas do corpo, pro fundo cobrir o
   conteúdo que passa por baixo.

   🔴 25/08 — A MARGEM DE BAIXO ERA -24px E VIROU 0, e o motivo é o que importa: ela existia
   só pra cancelar o `padding-bottom: 24px` do `.modal-corpo`. Esse padding foi ZERADO no
   conserto do rodapé grudento (22/08, o bloco "2 · O RODAPÉ GRUDENTO NÃO CHEGAVA AO FIM"),
   e a compensação ficou pra trás — passou a descontar um padding que não existe mais.
   Consequência, MEDIDA em TODOS os 8 popups da casa: `scrollHeight` 24px maior que
   `clientHeight`, ou seja **barra de rolagem num popup que não precisa rolar** (o de editar
   grupo tinha 354px de altura com 765px de teto disponível).
   ⚠️ A profundidade visual do rodapé não depende dela: quem dá é o
   `.modal-corpo .acoes-form { padding-bottom: 24px }`, lá embaixo. */
.modal .acoes-form{ justify-content: flex-end;
  position: sticky; bottom: 0; z-index: 1;
  margin: 22px -22px 0; padding: 14px 22px 16px;
  background: var(--surface-2); border-top: 1px solid var(--border);
  border-radius: 0 0 12px 12px; }
.botao--ghost{ background:transparent; color:var(--text-secondary); border:1px solid var(--border); box-shadow:none;
  font-weight:500; text-decoration:none; display:inline-flex; align-items:center; }
.botao--ghost:hover{ background:var(--surface-1); color:var(--text); border-color:var(--border-strong); box-shadow:none; transform:none; }
.voltar-ic{ display:inline-flex; align-items:center; gap:5px; text-decoration:none; }

/* ============================================================
   Fluidez — polimento das interações (aditivo; mesmas cores).
   Segue o padrão da tela de Acessos: cartões reagem ao hover,
   controles trocam de estado com transição suave.
   ============================================================ */
html { scroll-behavior: smooth; scrollbar-gutter: stable; }

/* cartões de conteúdo/form: feedback suave no hover (sem deslocar, pra não distrair) */
.card, .painel { transition: box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease); }
.card:hover, .painel:hover { box-shadow: var(--shadow-2); }

/* itens de lista clicáveis: leve elevação */
.linha { transition: transform var(--dur) var(--ease), border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
.linha:hover { transform: translateY(-1px); }

/* cartões das salas de controle (agentes / conexões): só sombra no hover
   (não mexer na tarja de status = border-left colorido) */

/* tabelas num wrap: a moldura ganha leve profundidade no hover */
.tabela-wrap { transition: box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease); }
.tabela-wrap:hover { box-shadow: var(--shadow-2); }

/* controles pequenos: transição de estado consistente */
.selo, .pill, .conta, .ic-badge, .acao-btn, .cod, .marca-chip .sw, .perfil-acao {
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.perfil-acao:hover { box-shadow: var(--shadow-2); }

/* press dos botões um tico mais orgânico — por CLASSE, como o hover (ver a nota do
   `.botao:hover`): por elemento, todo `<button>` da aplicação encolhia ao ser clicado. */
.botao:active { transform: translateY(0) scale(.985); }

/* linhas da tabela: transição também na cor do texto do link ao passar */
.tabela tbody tr { transition: background var(--dur) var(--ease); }
.tabela a.nome { transition: color var(--dur) var(--ease); }
.tabela tr:hover a.nome { color: var(--primary); }

/* ============================================================
   Lista em CARTÕES — o padrão visual da aba de Acessos, agora
   reutilizável em todo o app (cada item = um cartão arredondado
   com cabeçalho + chips). Consome só os tokens da marca.
   ============================================================ */
.lista-cards { display: flex; flex-direction: column; gap: 12px; }
.item-card { background: var(--surface-2); border: 1px solid var(--border); border-radius: 12px;
  padding: 16px 18px; box-shadow: var(--shadow-1);
  transition: box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease); }
.item-card:hover { box-shadow: var(--shadow-2); border-color: var(--border-strong); }
.item-cab { display: flex; align-items: flex-start; gap: 14px; }
.item-tit { flex: 1; min-width: 0; }
.item-tit h3 { margin: 0; font-size: 16px; font-weight: 600; display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.item-tit .chave { font-size: 12px; color: var(--muted); font-family: var(--font-mono); font-weight: 500; }
.item-tit p { margin: 3px 0 0; font-size: 13px; color: var(--muted); }
.item-cab > .acao-btn, .item-cab > .botao { flex: none; }
.item-chips { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 13px; }
/* ⚠️ SEM consumidor no momento — e fica assim DE PROPÓSITO (decisão do Bernardo,
   28/08): componente DISPONÍVEL do design system, não código morto. Nasceu no #46;
   Contatos foi o único uso e saiu na reforma da página. É o selo compacto de
   rótulo+número (o `.rot` é o rotulinho caps). Quando usar e quando NÃO usar:
   Cérebro/projetos/design-system-painel.md, seção "chip-info". Quem for removê-lo
   um dia, remova a decisão junto — não a regra sozinha. */
.chip-info { font-size: 12.5px; color: var(--text-secondary); background: var(--surface-1);
  border: 1px solid var(--border); border-radius: 999px; padding: 4px 11px;
  display: inline-flex; align-items: center; gap: 7px; }
.chip-info .rot { color: var(--muted); font-weight: 600; font-size: 10px; letter-spacing: .05em; text-transform: uppercase; }
.item-vazio { text-align: center; color: var(--muted); padding: 30px; background: var(--surface-1);
  border: 1px dashed var(--border-strong); border-radius: 12px; }
/* callout explicativo (topo de tela) */
.callout { display: flex; gap: 10px; background: var(--surface-1); border: 1px solid var(--border);
  border-left: 3px solid var(--accent); border-radius: 10px; padding: 12px 15px;
  font-size: 13.5px; color: var(--text-secondary); margin: 0 0 16px; }
.callout b { color: var(--text); }

/* ícones na barra lateral (cor acompanha o item: normal/hover/ativo) */
.sidebar-nav a .isvg{ width:18px; height:18px; margin-right:11px; flex:none; }
.sidebar-conta{ flex-direction:row; align-items:center; gap:10px; }
.sidebar-conta-txt{ display:flex; flex-direction:column; gap:1px; min-width:0; }
.sidebar-conta .isvg{ color:var(--muted); flex:none; }
.sidebar-sair{ display:flex; align-items:center; gap:9px; }
.sidebar-sair .isvg{ width:17px; height:17px; flex:none; }

/* ===== login (entrada): cabecalho centralizado (chave grande) ===== */
.entrada{ text-align:center; }
.entrada .ic-badge{ width:48px; height:48px; border-radius:13px; margin:0 auto 12px; }
.entrada h1{ margin:0 0 4px; }
.entrada .sub{ margin:0 0 18px; }
.entrada form{ text-align:left; }
.entrada .foot{ margin-top:16px; }

/* voltar como botao fantasma (ghost) no topo das telas */
.botao--voltar{ display:inline-flex; align-items:center; gap:6px; padding:6px 12px; font-size:13px; font-weight:500; }
.topo-voltar{ margin:0 0 10px; }

/* --- seletor de subpágina (botões, no padrão .botao--sec; ativo = .on preenchido) --- */
.cx-seletor { display: flex; gap: 9px; margin: 0 0 16px; flex-wrap: wrap; }
.barra-tit + .cx-seletor { margin-top: 16px; }
.aba-btn { gap: 7px; }
.aba-btn.on { background: var(--primary); color: var(--on-primary); border-color: var(--primary); }
.aba-btn.on:hover { background: var(--primary-hover); border-color: var(--primary-hover); color: var(--on-primary);
  box-shadow: none; transform: none; }

/* --- cartão de conexão / backup (sala de controle) --- */
/* card de telemetria — o MESMO nas telas de Agentes e Conexoes (componente unico) */
.tcard + .tcard { margin-top: 14px; }
/* cabeçalho numa linha só: nome (trunca se for grande) à esquerda, ações à direita — no
   mobile os ícones ficam INLINE com o nome, não empilhados (Bernardo, 2026-07-27). Sem o
   `flex-wrap`, que jogava as ações pra baixo quando o nome não cabia. */
.tcard-top { display: flex; align-items: center; gap: 12px; }
.tcard-id { flex: 1; min-width: 0; }
.tcard-nome { font-size: 16px; font-weight: 600; letter-spacing: -.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tcard-sub { font-size: 12.5px; color: var(--muted); margin-top: 1px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tcard-dir { margin-left: auto; flex: none; display: flex; align-items: center; gap: 12px; }
.tcard-sig { font-size: 12px; color: var(--muted); white-space: nowrap; }
.tcard-kpis { margin-top: 14px; }
.tcard-banda-top { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 9px; }
.tcard-url { font-size: 11.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 60%; }
.tcard-erro { display: flex; align-items: flex-start; gap: 9px; font-size: 13px; color: var(--danger); }
.tcard-foot { display: flex; align-items: center; gap: 12px; margin-top: 14px; padding-top: 13px; border-top: 1px solid var(--border); flex-wrap: wrap; }
.tcard-foot-resumo { font-size: 13px; color: var(--text-secondary); }
.tcard-foot-resumo b { color: var(--text); font-weight: 600; }
.tcard-foot-btns { margin-left: auto; display: flex; gap: 8px; }
/* mobile: Desligar/Editar viram só ÍCONE e ficam INLINE (mesma linha), não empilhados
   (Bernardo, 2026-07-23). O rótulo fica no aria-label/title. */
@media (max-width: 520px) {
  .tcard-dir { flex-direction: row; align-items: center; gap: 7px; }
  .tcard-dir .acao-txt { display: none; }
  .tcard-dir .acao-btn { width: 36px; height: 36px; padding: 0; gap: 0; justify-content: center; }
  /* popup "Adicionar administrador": o "Tornar admin" vira só-ícone, igual aos dos cards */
  .adm-cand .acao-txt { display: none; }
  .adm-cand .acao-btn { width: 36px; height: 36px; padding: 0; gap: 0; justify-content: center; }
}
/* mobile: lista de pessoas MAIS LIMPA — esconde telefone, e-mail, nível [já no cabeçalho],
   equipe e cargo; ficam só CPF, unidade, departamento e setor (Bernardo, 2026-07-27 — trocou
   cargo por CPF). O detalhe completo abre na ficha. */
@media (max-width: 640px) {
  .tcard-kpis .kpi.hide-mobile { display: none; }
}

/* --- formulário em modal (dialog) --- */
/* 🔒 Popup aberto TRANCA a página. O `<dialog>` deixa a página inerte ao CLIQUE, mas
   NÃO ao scroll: rolar por cima do fundo escurecido movia o que estava atrás. (O
   `overscroll-behavior` do `.modal-corpo`, mais abaixo, resolve o OUTRO caminho — o
   scroll que vaza ao chegar no fim do corpo. São dois problemas distintos.)
   O `:has` alcança os 3 `<dialog>` de uma vez (`#modal-app`, `#filtro-dlg`,
   `#add-admin-dlg`) e qualquer um que venha depois — não depende de ninguém lembrar
   de ligar uma classe. O drawer usa a mesma ideia (`body:has(.sidebar.aberto)`, no
   @media do mobile) desde que a classe dele, que não travava nada, foi apagada.
   ⚠️ Isto depende do `scrollbar-gutter: stable`, que o `html` já tem lá em cima (~l.521):
   trancar o body some com a barra de rolagem, e sem a calha reservada a página inteira
   pularia pra direita ao abrir o popup. Não repeti a regra aqui — mas tirar a de lá
   traz o pulo pra cá. Um teste amarra as duas (`core/tests_scroll_popup.py`). */
body:has(dialog[open]) { overflow: hidden; }

.modal { border: none; padding: 0; background: transparent; color: var(--text);
  max-width: 460px; width: calc(100% - 32px);
  opacity: 0; transform: translateY(-6px) scale(.985);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease),
              overlay var(--dur) var(--ease) allow-discrete, display var(--dur) var(--ease) allow-discrete; }
.modal[open] { opacity: 1; transform: none; }
@starting-style { .modal[open] { opacity: 0; transform: translateY(-6px) scale(.985); } }
.modal::backdrop { background: rgba(0, 0, 0, .45); backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  opacity: 0; transition: opacity var(--dur) var(--ease),
              overlay var(--dur) var(--ease) allow-discrete, display var(--dur) var(--ease) allow-discrete; }
.modal[open]::backdrop { opacity: 1; }
@starting-style { .modal[open]::backdrop { opacity: 0; } }
.modal .painel { margin: 0; max-height: 85vh; display: flex; flex-direction: column; overflow: hidden; padding: 0; }
/* ⚠️ A FOLGA DE BAIXO é 20px de propósito, e os DOIS modais usam o MESMO `.modal-tit`.
   Por quê: o `h1` solto tem `margin: 0 0 4px`, e o `.modal-tit h1` zera. Enquanto o
   `_form_modal` tinha `<h1>` solto e o `_usuario_modal` tinha `.modal-tit`, os dois
   davam folgas DIFERENTES embaixo (20px × 16px) com o mesmo padding — e o de usuário
   parecia grudado. Pior: no `_form_modal` o BADGE (34px) manda na altura (o texto é
   menor), então o título flutua; no de usuário o TEXTO manda (h1+subtítulo passam do
   badge) e ele vira o teto e o piso da barra. Mesmo padding, resultados opostos.
   Consertado na RAIZ: um markup só (`.modal-tit`, subtítulo opcional) e a folga definida
   AQUI, num lugar só. MEDIDO no markup real que o servidor renderiza.

   O popup é um ESPELHO da página (princípio do #67/#74) — a régua vem DE LÁ.
   Os 32px do topo são os do `.conteudo { padding: 32px 20px }`, que é onde o
   `.barra-tit` vive NA PÁGINA — não o `.painel` (o cabeçalho fica FORA do painel lá).
   16px até o corpo = a folga que o #78 normatizou (`.barra-tit + *`).
   MEDIDO, não deduzido: com 32px o título fica a 33px do topo do card — igual à página —
   nos dois popups (com e sem subtítulo).
   ⚠️ `min-height: 0` de propósito: medido que o `min-height:44px` do #80 é LETRA MORTA
   aqui — o conteúdo do cabeçalho passa de 44px nos DOIS casos (82.8px com subtítulo,
   73px sem). O #157 apostou nele e só removeu 6px do topo. */
/* `align-items: flex-start` TIRA O BADGE DA EQUACAO. Com `center`, o badge (34px fixos)
   mandava na altura quando o texto era menor que ele (popup SEM subtitulo) — e ai o
   titulo flutuava, ganhando folga de graca. Com subtitulo, o texto passava do badge,
   preenchia a linha e o titulo virava o teto da barra: MESMO padding, resultado oposto.
   Era essa a diferenca que o Tiago via, e nenhum padding resolvia (o padding e comum aos
   dois). Com `flex-start`, a posicao do titulo NAO depende mais de ter subtitulo.
   MEDIDO: topo->titulo 32.0px e topo->badge 28.0px nos DOIS. */
/* 🔴 `flex: none` NAO E ENFEITE. O `.modal .painel` e `flex-direction: column` com
   `max-height: 85vh`, e o `.barra-tit` e um item flex: com o `flex-shrink: 1` padrao ele
   podia ser ESMAGADO pra caber o corpo — e o conteudo dele vazava POR CIMA do corpo (o
   subtitulo em cima do "Dados da pessoa"). MEDIDO: a barra precisava de 99px e tinha 78.
   O design system sempre disse "cabecalho FIXO + corpo rolavel" (#67/#74); ninguem tinha
   dito isso ao CSS.
   ⚠️ O `min-height: 0` era o que REMOVIA a protecao: em coluna flex, o padrao
   `min-height: auto` ja impede o item de encolher abaixo do conteudo. Por isso ele sai. */
.modal .barra-tit { padding: 32px 22px 20px; margin: 0; flex: none; align-items: flex-start; }
/* nudge optico: o badge centra na PRIMEIRA LINHA do titulo, nao no bloco inteiro */
.modal .barra-tit .ic-badge { margin-top: -4px; }
/* Com o Voltar no lugar do crachá (27/08), a linha volta a CENTRAR: o Voltar tem os
   44px do botão primário e o topo-alinhado deixava título e ✕ pendurados no alto —
   o -4px do crachá não existe pra ele. Mesmo idioma da exceção do subtítulo (:has). */
.modal .barra-tit:has(.botao--voltar) { align-items: center; }
/* `overscroll-behavior: contain` prende o scroll AQUI. Sem ele o valor e `auto` — o
   navegador CONTINUA rolando o ancestral quando este corpo chega ao fim, e a pagina
   andava por baixo do popup aberto. Vale pros 8 corpos de popup, que usam esta classe. */
.modal-corpo { overflow-y: auto; overscroll-behavior: contain; padding: 0 22px 24px; }
.modal-x { margin-left: auto; height: auto; width: auto; padding: 4px; background: transparent;
  color: var(--muted); border: none; box-shadow: none; cursor: pointer; border-radius: 8px; flex: none; }
.modal-x:hover { background: var(--canvas); color: var(--text); transform: none; box-shadow: none; }
/* cabeçalho de modal: título + subtítulo empilhados ao lado do badge */
.modal-tit { min-width: 0; flex: 1; }
.modal-tit h1 { margin: 0; line-height: 1.15; }
.modal-sub { font-size: 13px; color: var(--muted); margin-top: 2px; }
.modal .modal-x { align-self: flex-start; }
@media (prefers-reduced-motion: reduce) { .modal, .modal::backdrop { transition: none; } }

/* --- barra de rolagem: discreta e temática (todo o app, ambos os temas) --- */
* { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-button { display: none; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-corner { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border: 2px solid transparent;
  background-clip: padding-box; border-radius: 999px; }
::-webkit-scrollbar-thumb:hover { background: var(--muted); }

/* --- agentes: botão de erros no rodapé + conteúdo dos popups de uso/erros --- */
.acao-btn--erro { color: var(--danger); }
.acao-btn--erro:hover { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, var(--border)); background: color-mix(in srgb, var(--danger) 8%, transparent); }
/* Readmitir = o "perigo positivo": mesma forma da variante de perigo, cor de sucesso (verde). */
.acao-btn--sucesso { color: var(--success); }
.acao-btn--sucesso:hover { color: var(--success); border-color: color-mix(in srgb, var(--success) 40%, var(--border)); background: color-mix(in srgb, var(--success) 8%, transparent); }
/* botao SOLIDO de perigo: preenchido vermelho, foco do popup de confirmacao (design-system-painel) */
.botao--perigo { display: inline-flex; align-items: center; justify-content: center; background: var(--danger); }
.botao--perigo:hover { background: color-mix(in srgb, var(--danger) 86%, #000); }
/* Histórico de vínculo (ficha): os ciclos de admissão→desligamento e o tempo fora.
   O tempo SOBE — a ponta de CIMA da barra é o desligamento (ou "hoje"), a de BAIXO é a
   admissão. Só-leitura. Mock aprovado 2026-08-03. */
/* o grupo de ações do cabeçalho (Histórico + Desligar/Readmitir), ancorado à direita */
.barra-acoes { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.hv-lista { list-style: none; margin: 0; padding: 0; }
.hv-per { position: relative; padding: 0 0 0 30px; }
.hv-barra { position: absolute; left: 5px; top: 11px; bottom: 11px; width: 6px; border-radius: 99px;
  background: var(--border-strong); }
.hv-barra::before, .hv-barra::after { content: ""; position: absolute; left: 50%; translate: -50% 0;
  width: 14px; height: 14px; border-radius: 50%; background: var(--surface-2);
  border: 3px solid var(--border-strong); }
.hv-barra::before { top: -7px; }      /* ponta de cima = desligamento */
.hv-barra::after { bottom: -7px; }    /* ponta de baixo = admissão */
/* período ATUAL: a admissão (embaixo) é o ponto de partida; em cima o vínculo segue aberto */
.hv-atual .hv-barra { background: linear-gradient(color-mix(in srgb, var(--success) 25%, transparent), var(--success)); }
.hv-atual .hv-barra::after { border-color: var(--success); background: var(--success); }
.hv-atual .hv-barra::before { display: none; }
.hv-linha { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; min-height: 22px; }
.hv-dt { font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: .01em; }
.hv-dt.hv-hoje { color: var(--muted); font-weight: 400; }
.hv-linha .selo { margin-left: auto; }
.hv-meta { font-size: 12.5px; color: var(--muted); margin: 4px 0; }
.hv-sep { opacity: .45; margin: 0 4px; }
.hv-fora { position: relative; padding: 12px 0 12px 30px; }
.hv-fora::before { content: ""; position: absolute; left: 7px; top: 0; bottom: 0; width: 2px;
  background: repeating-linear-gradient(var(--border-strong) 0 3px, transparent 3px 8px); }
.hv-fora span { font-size: 12.5px; color: var(--muted); }
.hv-fora b { color: var(--text-secondary); font-weight: 600; }

.botao--sucesso { display: inline-flex; align-items: center; justify-content: center; background: var(--success); }
.botao--sucesso:hover { background: color-mix(in srgb, var(--success) 86%, #000); }
.uso-rank { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.uso-rank li { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-top: 1px solid var(--border); }
.uso-rank li:first-child { border-top: none; }
.uso-pos { width: 20px; text-align: right; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; flex: none; }
.uso-id { min-width: 0; }
.uso-nome { font-size: 14px; font-weight: 500; }
.uso-nome--off { color: var(--text-secondary); font-weight: 400; }
.uso-tag { font-size: 11.5px; color: var(--muted); font-weight: 400; }
.uso-ult { font-size: 12px; color: var(--muted); margin-top: 1px; }
.uso-msgs { margin-left: auto; font-size: 14px; font-weight: 600; }
.uso-vazio { color: var(--muted); font-size: 13px; padding: 6px 0; }
.erro-lista { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.erro-lista li { padding: 10px 0; border-top: 1px solid var(--border); }
.erro-lista li:first-child { border-top: none; }
.erro-lista .erro-cab { display: flex; align-items: baseline; gap: 8px; }
.erro-lista .erro-onde { font-size: 13px; font-weight: 600; }
.erro-lista .erro-quando { font-size: 12px; color: var(--muted); }
.erro-lista .erro-msg { font-size: 13px; color: var(--text-secondary); margin-top: 2px; }

/* verificacoes dentro do popup: 1 coluna (o modal e estreito) */
.modal .checklist { grid-template-columns: 1fr; }

/* ABAS da ficha (Bernardo, 2026-07-23) — SÓ VISUAL: a aba escondida é `hidden`, o input
   dela segue no form e é enviado. Trocar de aba não perde nada.
   Usa o MESMO seletor de subpágina de Conexões (design system): `.cx-seletor` +
   `.botao--sec.aba-btn.on`. São 6 abas, então aqui elas NÃO quebram linha — uma fila só,
   rola no eixo x se faltar largura (o "Ponto e facial" caía pra baixo). */
/* rótulos curtos (Identificação/Acesso/Pessoal/…) + ícone: as 6 pílulas cabem numa fila só.
   Mantém a FONTE padrão (15px) do design system; só apara padding/gap pra caber em 760px. */
.abas-wrap .cx-seletor { flex-wrap: nowrap; gap: 5px; overflow-x: auto; }
.abas-wrap .aba-btn { flex: none; padding-left: 15px; padding-right: 15px; }
/* o card agora vive DENTRO do .abas-wrap: o cap de 760px do `.conteudo > *` só vale pra
   filho direto, então o `.form-painel` caía pro seu max-width de 480 e ficava mais estreito
   que as abas. Aqui o card volta a ACOMPANHAR a largura da barra de abas. */
.abas-wrap .form-painel { max-width: none; }
/* HOVER REMOVIDO das abas (Bernardo, 2026-07-23): o hover fica IGUAL ao estado normal —
   mesmo fundo, mesma cor de texto, sem "pulo". Assim não existe efeito de hover que possa
   esconder a escrita. Inativa segue `.botao--sec` (fundo surface-2, texto primary); ativa
   segue `.on` (preenchida). */
.abas-wrap .aba-btn:hover { background: var(--surface-2); color: var(--sec-texto);
  border-color: var(--border); box-shadow: var(--shadow-1); transform: none; }
.abas-wrap .aba-btn.on, .abas-wrap .aba-btn.on:hover { background: var(--primary);
  color: var(--on-primary); border-color: var(--primary); }
/* MOBILE (Bernardo, 2026-07-23): as abas mantêm ÍCONE + TEXTO e ROLAM pro lado (o
   `.cx-seletor` já é `overflow-x: auto` + `nowrap`, então a fila estoura a largura e vira
   scroll horizontal). Só o Desligar vira ícone puro (quadradinho centrado, padrão do
   `.botao--add`). */
@media (max-width: 640px) {
  /* no mobile os botões do cabeçalho viram só o ícone */
  .barra-acoes .botao .botao-txt { display: none; }
  .barra-acoes .botao { width: 44px; padding: 0; gap: 0; justify-content: center; }
}
/* aba com erro de validação: pinga vermelho no canto, pra ninguém salvar sem ver o erro
   escondido. Dentro da pílula pra não ser cortado pelo overflow do seletor. */
.aba-btn.tem-erro { position: relative; }
.aba-btn.tem-erro::after { content: ""; position: absolute; top: 5px; right: 7px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--danger); }
/* espaçamento PADRÃO entre os campos da ficha (Bernardo, 2026-07-27): a aba vira coluna com
   `gap` único (o mesmo 15px dos grids), pra os blocos não ficarem colados/irregulares — antes
   a aba era `block` sem gap e cada bloco espaçava pela própria margem (0, 6, 2px… bagunçado). */
.aba-painel { display: flex; flex-direction: column; gap: 15px; }
.aba-painel[hidden] { display: none; }

/* grade genérica dos campos de ficha (documentos/pessoal/contrato) */
/* 🔴 `minmax(0, 1fr)`, nao `1fr`. Item de grid nasce com `min-width: auto`, e um
   `<input>` tem largura INTRINSECA (~225px): a coluna se recusa a encolher abaixo dela
   e a grade TRANSBORDA o container. Medido no popup da conta bancaria em 23/08: caixa
   de 398px, grade calculada em `225px 225px` + 14 de gap = 464px — 66px para fora, com
   os rotulos cortados e barra de rolagem horizontal. Com `minmax(0, …)` a coluna pode
   encolher, que e o que "metade e metade" sempre quis dizer.
   ⚠️ `<select>` tem largura intrinseca menor e CABIA — por isso a segunda grade da
   mesma tela parecia certa. Defeito que aparece num lugar so quase nunca esta num
   lugar so. */
.form-painel .form-grade { display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 15px; }
.form-painel .form-grade > p { min-width: 0; margin: 0; display: flex;
  flex-direction: column; gap: 6px; }
.form-painel .form-grade > p.campo-bool { flex-flow: row wrap; align-items: center; gap: 4px 9px; }
@media (max-width: 640px) { .form-painel .form-grade { grid-template-columns: 1fr; } }

/* PROTÓTIPO cargo × equipe (Bernardo, 2026-07-23) — nudge + escotilha + aviso + motivo.
   Divergência é AVISO (laranja --warning), não erro (norma do app: aviso ≠ erro). */
.cargo-campo { display: flex; flex-direction: column; gap: 6px; }
.cargo-escotilha { align-self: flex-start; font-size: 12px; color: var(--primary);
  text-decoration: none; cursor: pointer; }
.cargo-escotilha:hover { text-decoration: underline; }
.cargo-diverge { align-self: flex-start; display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; line-height: 1.35; padding: 5px 9px; border-radius: 8px; color: var(--warning);
  background: color-mix(in srgb, var(--warning) 12%, var(--surface-2));
  border: 1px solid color-mix(in srgb, var(--warning) 32%, var(--border)); }
.cargo-motivo { display: flex; flex-direction: column; gap: 6px; }
.cargo-motivo-lbl { font-size: 12px; color: var(--text-secondary); }
/* divergência NOVA sem motivo: o rótulo cobra (o JS acende ao tentar salvar sem escolher) */
.cargo-motivo--exige .cargo-motivo-lbl { color: var(--warning); font-weight: 600; }
.cargo-motivo--exige .cargo-motivo-lbl::after { content: " — obrigatório"; }
.cargo-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.cargo-chip { display: inline-flex; align-items: center; font-size: 12px; cursor: pointer; padding: 5px 10px;
  border-radius: 8px; background: transparent; border: 1px solid var(--border-strong); color: var(--text); }
.cargo-chip input { position: absolute; width: 0; height: 0; opacity: 0; margin: 0; }
.cargo-chip:hover { background: var(--surface-1); }
.cargo-chip:has(input:checked) { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.cargo-chip:has(input:focus-visible) { outline: 2px solid var(--primary); outline-offset: 2px; }
/* o `display:flex/inline-flex` acima ATROPELA o atributo `hidden` (perde pro UA); o
   seletor de atributo tem especificidade maior e devolve o esconder ao JS. */
.cargo-diverge[hidden], .cargo-motivo[hidden] { display: none; }

/* ============ O CADEADO ============ (Bernardo, 2026-07-23 / foto; unificado em 2026-08-05)
   Um QUADRADO no fim da barra do campo: `[ select que cresce ][ cadeado ]`.
   A ESTRUTURA é comum aos dois usos (cargo × setor e equipe × setor) — só a COR difere, e
   difere de propósito (ver adiante). O comportamento mora em static/js/cadeado.js. */
.cargo-linha, .vinculo-linha { display: flex; gap: 8px; align-items: stretch; }
/* o select ou o dropdown customizado (`.dd`, que o dropdown.js põe por cima) cresce; o
   cadeado fica quadrado ao lado */
.cargo-linha > select, .cargo-linha > .dd,
.vinculo-linha > select, .vinculo-linha > .dd { flex: 1; min-width: 0; }
.cargo-cadeado, .vinculo-cadeado { flex: none; width: 42px; align-self: stretch; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius);
  color: var(--muted); cursor: pointer; box-shadow: none; }
.cargo-cadeado:hover, .vinculo-cadeado:hover {
  background: var(--surface-1); box-shadow: none; transform: none; }
.cargo-cadeado:disabled, .vinculo-cadeado:disabled { cursor: default; opacity: .6; }
.cargo-cadeado:disabled:hover, .vinculo-cadeado:disabled:hover { background: var(--surface-2); }
.cargo-cadeado .isvg, .vinculo-cadeado .isvg { width: 17px; height: 17px; }
/* TRANCADO congela a interação — no <select> E no gatilho que o dropdown desenha por cima.
   Só o select ficava esmaecido e a lista seguia abrindo: o cadeado virava enfeite (os dois
   já tiveram esse defeito). O <select> segue no form e é enviado no Salvar. */
.cargo-campo select.travado, .cargo-campo .dd-trigger.travado,
.vinculo-campo select.travado, .vinculo-campo .dd-trigger.travado {
  pointer-events: none; opacity: .6; }
/* 🚧 gate de permissão: quando ele passar a barrar, o cadeado FICA VISÍVEL e trancado — o
   que some é a possibilidade de quebrar a restrição, não o aviso de que ela existe. */
.cargo-cadeado.sem-permissao, .vinculo-cadeado.sem-permissao { opacity: .45; }

/* --- a COR: a mesma peça, dois significados opostos, de propósito ---
   No CARGO o cadeado só EXISTE quando há divergência: ele é o alerta → âmbar quando ativo.
   No par EQUIPE × SETOR a restrição é o estado NORMAL de toda ficha; âmbar ali seria um
   alarme tocando sempre, que é o mesmo que alarme nenhum → neutro quando trancado, âmbar
   só quando alguém DESTRAVA de propósito. Atrito proporcional à consequência. */
.cargo-cadeado:not(:disabled) { color: var(--warning); border-color: color-mix(in srgb,var(--warning) 40%,var(--border)); }
.cargo-cadeado:not(:disabled):hover { color: var(--warning); background: color-mix(in srgb,var(--warning) 9%,var(--surface-2)); }
.cargo-cadeado.trancado { color: var(--warning); border-color: color-mix(in srgb,var(--warning) 55%,var(--border));
  background: color-mix(in srgb,var(--warning) 13%,var(--surface-2)); }

/* ---- EQUIPE × SETOR: o cadeado como sinal de RESTRIÇÃO (Bernardo, 2026-08-05) ----
   Mesma peça do cadeado do cargo, semântica INVERTIDA de propósito.

   No cargo, o cadeado só existe quando há divergência — por isso é âmbar: ele É o alerta.
   Aqui a restrição é o estado NORMAL (o setor define a equipe; a equipe filtra os setores),
   e pintar de âmbar o cadastro inteiro viraria um alarme que toca sempre — que é o mesmo
   que alarme nenhum. Então: TRANCADO = neutro (está como deveria); DESTRAVADO = âmbar,
   porque aí alguém saiu do padrão de propósito, e é isso que merece ser visto.
   Atrito proporcional à consequência: a cor aparece no estado incomum, não no comum. */
/* trancado = a restrição está valendo: neutro, discreto */
.vinculo-cadeado.trancado { color: var(--text-secondary);
  border-color: var(--border); background: var(--surface-1); }
/* destravado E clicável = a restrição foi quebrada à mão: é o que precisa saltar */
.vinculo-cadeado:not(:disabled):not(.trancado) { color: var(--warning);
  border-color: color-mix(in srgb, var(--warning) 45%, var(--border));
  background: color-mix(in srgb, var(--warning) 10%, var(--surface-2)); }
.vinculo-cadeado:not(:disabled):not(.trancado):hover {
  background: color-mix(in srgb, var(--warning) 16%, var(--surface-2)); }
/* a nota embaixo do campo: diz em UMA frase por que o campo está como está */
.vinculo-nota { font-size: 12px; color: var(--text-secondary); line-height: 1.5; }
.vinculo-nota[hidden] { display: none; }
/* destravado, a nota acompanha a cor do cadeado — os dois sinais andam juntos */
.vinculo-campo:has(.vinculo-cadeado:not(:disabled):not(.trancado)) .vinculo-nota {
  color: var(--warning); }
/* SETOR FORASTEIRO: o que veio do banco pertencendo a outra equipe. Fica na lista e é
   MARCADO — apagá-lo em silêncio era desfazer uma escolha deliberada com atrito zero. */
.vinculo-forasteiro .vinculo-nota { color: var(--warning); }
.vinculo-forasteiro .vinculo-linha > select,
.vinculo-forasteiro .vinculo-linha > .dd .dd-trigger {
  border-color: color-mix(in srgb, var(--warning) 45%, var(--border)); }

/* marcador de divergência cargo × setor na LISTA de pessoas (Bernardo, 2026-07-23): de
   relance, quem tem o cargo de equipe diferente da do setor. Sem motivo = âmbar (pede
   atenção); com motivo = neutro (é de propósito, já sabido). */
.tag-diverge { display: inline-block; margin-left: 6px; font-size: 11px; line-height: 1.6;
  padding: 0 7px; border-radius: 999px; vertical-align: middle; white-space: nowrap;
  color: var(--warning); background: color-mix(in srgb, var(--warning) 14%, var(--surface-2));
  border: 1px solid color-mix(in srgb, var(--warning) 32%, var(--border)); }
.tag-diverge--ok { color: var(--muted); background: var(--surface-1); border-color: var(--border); }

/* --- switch segmentado (.seg): binario ou N-opcoes; ativo = tinta primaria solida --- */
.seg{ display:inline-flex; background:var(--surface-1); border:1px solid var(--border); border-radius:10px; padding:4px; gap:4px; }
.seg--full{ display:flex; }
.seg button{ all:unset; box-sizing:border-box; display:inline-flex; align-items:center; justify-content:center; gap:7px; font-size:13px; font-weight:600; color:var(--muted); padding:8px 16px; border-radius:7px; cursor:pointer; white-space:nowrap; transition:background var(--dur) var(--ease), color var(--dur) var(--ease); }
.seg--full button{ flex:1; }
.seg button:hover{ color:var(--text-secondary); }
.seg button.on{ background:color-mix(in srgb, var(--primary) 12%, var(--surface-2)); color:var(--primary); }
.seg button .isvg{ flex:none; }
/* --- switch booleano (.switch): knob liga/desliga, para campos on/off (ex.: Ativo) --- */
.switch{ all:unset; box-sizing:border-box; width:46px; height:26px; border-radius:999px; background:var(--surface-1); border:1px solid var(--border-strong); position:relative; cursor:pointer; flex:none; transition:background var(--dur) var(--ease), border-color var(--dur) var(--ease); }
/* 🥇 A ANIMAÇÃO DO SWITCH — "esticar" (escolha do Tiago, 22/08, entre 5 opções).
   É o squash & stretch clássico: a bolinha se alonga no trajeto e volta a ser redonda ao
   parar. O peso do movimento vem daí, não de uma curva exagerada.

   🔴 O truque é ancorar por `left` E `right` (sem `width`) e DESENCONTRAR os tempos: a borda
   da FRENTE parte na hora, a de TRÁS sai com `--sw-atraso` de atraso. No caminho de volta as
   funções se invertem — por isso são duas regras de `transition`, uma em cada estado, e não
   uma só. Estica de propósito nos dois sentidos.

   ⚠️ Não troque por `:active`: aquilo estica enquanto o botão está PRESSIONADO, não durante o
   percurso — e no teclado ou num clique rápido não estica nada. */
.switch::after{ content:""; position:absolute; top:2px; left:2px; right:22px; height:20px;
  border-radius:999px; background:var(--muted); box-shadow:0 1px 2px rgba(0,0,0,.2);
  transition:left var(--sw-dur) var(--ease),
             right var(--sw-dur) var(--ease) var(--sw-atraso),
             background var(--dur) var(--ease); }

.switch[aria-checked="true"]{ background:var(--primary); border-color:var(--primary); }
.switch[aria-checked="true"]::after{ left:22px; right:2px; background:#fff;
  transition:left var(--sw-dur) var(--ease) var(--sw-atraso),
             right var(--sw-dur) var(--ease),
             background var(--dur) var(--ease); }

/* formulário agrupado (ex.: cadastro de usuário no modal) */
.form-sec { font-size: 11.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted);
  font-weight: 600; padding-bottom: 7px; border-bottom: 1px solid var(--border); margin-top: 4px; }

/* CAMPOS LADO A LADO (Bernardo, 2026-07-22) — peça nova, de propósito.
   Campo curto (CPF, telefone, data) ocupava a linha inteira: 714px medidos pra mostrar
   14 caracteres. Isso empurrava a ficha da pessoa pra 2.898px de altura.
   `--cols` muda a proporção quando um dos dois é maior (endereço 2fr + país 1fr).
   Só para campos CURTOS — texto longo pareado fica ilegível.
   No CELULAR volta a empilhar: em 375px duas colunas dariam ~160px cada. */
.form-painel .form-linha { display: grid; grid-template-columns: var(--cols, 1fr 1fr);
  gap: 15px; align-items: start; }
.form-painel .form-linha > p { min-width: 0; }   /* senão o campo estoura a coluna */
@media (max-width: 640px) { .form-painel .form-linha { grid-template-columns: 1fr; } }

/* BLOCO RECOLHÍVEL — pro que é só consulta (o espelho do Tangerino).
   São 10 campos travados; abertos, ocupavam metade da rolagem sem nenhuma ação possível. */
.form-bloco > summary { cursor: pointer; list-style: none; display: flex; align-items: center; gap: 8px; }
.form-bloco > summary::-webkit-details-marker { display: none; }
.form-bloco > summary .form-sec { flex: 1; margin: 0; }
.form-bloco .chev { transition: transform .15s ease; color: var(--muted); flex: none; }
.form-bloco[open] .chev { transform: rotate(90deg); }
.form-bloco .form-bloco-corpo { display: flex; flex-direction: column; gap: 15px; padding-top: 15px; }
@media (prefers-reduced-motion: reduce) { .form-bloco .chev { transition: none; } }

/* campo de marcar (agora <div>, não <p>): coluna flex com o mesmo ritmo interno de 6px que o
   `.form-painel p` dava. O box de checkboxes (`div[id^="id_"]`) traz um margin-top:6px próprio
   (linha ~285); dentro do campo-chks o gap já separa, então zera pra não somar 6+6. */
.form-painel .campo-chks { display: flex; flex-direction: column; gap: 6px; }
.form-painel .campo-chks div[id^="id_"] { margin-top: 0; }
.form-painel .campo-chks ul { list-style: none; margin: 0; padding: 0; display: grid;
  grid-template-columns: 1fr 1fr; gap: 8px 16px; }
.form-painel .campo-chks li label { display: flex; align-items: center; gap: 8px; font-size: 14px;
  color: var(--text); font-weight: 400; }
/* Cabeçalho do campo de marcar: o rótulo e o "Selecionar todas" na MESMA linha.
   O `.form-painel p` é coluna, então o atalho caía sozinho numa linha entre o rótulo e
   as caixas — órfão, e longe do que ele comanda (Bernardo, 2026-07-22). */
.campo-chks .campo-cab { display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; }
.campo-chks .campo-cab > label:first-child { margin: 0; }
.chk-todas { display: inline-flex; align-items: center; gap: 8px; font-size: 13px;
  font-weight: 600; color: var(--primary); cursor: pointer; }
.erro-campo { font-size: 12px; color: var(--danger); }
.dica { font-size: 12px; color: var(--muted); margin: 5px 0 0; }
.tang-chip { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; color: var(--text-secondary);
  background: var(--surface-1); border: 1px solid var(--border); border-radius: 8px; padding: 6px 11px; }
.tang-chip b { color: var(--primary); font-variant-numeric: tabular-nums; font-weight: 600; }
.tang-nao { color: var(--warning); }
@media (max-width: 480px) { .form-painel .campo-chks ul { grid-template-columns: 1fr; } }

/* usuários — badge de papel + ficha em grade (estrutura do card de agente) */
.ic-badge--sup { background: color-mix(in srgb, var(--warning) 16%, var(--surface-2)); color: var(--warning); }
.ic-badge--alerta { background: color-mix(in srgb, var(--warning) 16%, var(--surface-2)); color: var(--warning); }
.ic-badge--usr { background: var(--surface-1); color: var(--muted); border: 1px solid var(--border); }
.ic-badge--sm { width: 30px; height: 30px; border-radius: 8px; }
.tcard-sub.papel-sup { color: var(--warning); font-weight: 600; }
.tcard-sub.papel-adm { color: var(--primary); font-weight: 600; }
.lista-usuarios .tcard + .tcard { margin-top: 14px; }
.ficha-kpis .rotulo { display: flex; align-items: center; gap: 5px; }
.ficha-kpis .v { font-size: 14px; font-weight: 500; }
.ficha-kpis .v.vazio { color: var(--muted); font-weight: 400; }
.campo-prov { font-size: 10px; font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--muted);
  background: var(--surface-1); border: 1px dashed var(--border-strong); border-radius: 4px; padding: 0 5px; }
.tcard--inativo { opacity: .55; }

/* usuários — busca + filtro */
.us-toolbar { display: flex; gap: 10px; align-items: center; margin: 0 0 14px; }
.us-busca { flex: 1; display: flex; align-items: center; gap: 9px; height: 44px; border: 1px solid var(--border-strong);
  border-radius: var(--radius); background: var(--surface-1); padding: 0 14px; }
.us-busca:focus-within { border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring); background: var(--surface-2); }
.us-busca .isvg { color: var(--muted); flex: none; }
.us-busca input { border: none; background: transparent; outline: none; box-shadow: none; flex: 1; height: 100%; padding: 0; font-size: 16px; color: var(--text); font-family: inherit; -webkit-appearance: none; appearance: none; }
.us-busca input:focus, .us-busca input:focus-visible { outline: none; box-shadow: none; }
.us-filtrar { gap: 7px; }
.us-filtrar .cnt { background: var(--primary); color: var(--on-primary); border-radius: 999px; font-size: 11px; padding: 1px 7px; }
/* no mobile o Filtrar vira só ícone (.botao--add); o contador vira SELO no canto, pra não
   alargar o botão de 44px (Bernardo, 2026-07-27) */
@media (max-width: 880px) {
  .us-filtrar.botao--add { position: relative; }
  .us-filtrar.botao--add .cnt { position: absolute; top: -5px; right: -5px; min-width: 16px;
    padding: 0 4px; line-height: 16px; text-align: center; box-sizing: border-box; }
}
.filtro-grp { margin-bottom: 16px; }
.filtro-lab { font-size: 12px; color: var(--text-secondary); font-weight: 600; margin-bottom: 8px; }
.filtro-chips { display: flex; flex-wrap: wrap; gap: 7px; }
.fchip { font-size: 12.5px; border: 1px solid var(--border); border-radius: 999px; padding: 5px 12px; color: var(--text-secondary);
  background: var(--surface-2); cursor: pointer; box-shadow: none; font-weight: 500; }
.fchip:hover { border-color: var(--border-strong); transform: none; }
.fchip.on { background: color-mix(in srgb, var(--primary) 12%, var(--surface-2)); color: var(--primary); border-color: color-mix(in srgb, var(--primary) 35%, var(--border)); }
.us-sem { color: var(--muted); font-size: 14px; padding: 18px 2px; }

/* administradores */
.barra-acoes { display: flex; gap: 10px; align-items: center; }
.adm-acts { display: flex; gap: 8px; align-items: center; }
.adm-acts form { margin: 0; }
.adm-acts .botao { height: 34px; padding: 0 12px; font-size: 13px; }
.adm-remover { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 35%, var(--border)); }
.adm-remover:hover { color: var(--danger); border-color: var(--danger); }
.adm-voce { font-size: 12.5px; color: var(--muted); }
.adm-cands { display: flex; flex-direction: column; margin-top: 4px; }
/* linha do candidato: nome à ESQUERDA (quebra alinhada à esquerda — o <button> de antes
   centralizava o texto por padrão) + botão "Tornar admin" à direita (Bernardo, 2026-07-27) */
.adm-cand { display: flex; flex-direction: row; align-items: center; justify-content: space-between; gap: 12px;
  margin: 0; padding: 10px 4px; border-top: 1px solid var(--border); }
.adm-cand:first-child { border-top: none; }
.adm-cand-nome { flex: 1; min-width: 0; text-align: left; font-size: 14.5px; color: var(--text); line-height: 1.35; }
.adm-cand > .acao-btn { flex: none; }

/* Campo com erro fica destacado em PERIGO — o form já mostra `.erro-campo` ao lado; aqui a
   borda/anel do input viram vermelhos (mesmo desenho do foco, na cor --danger). `:has(> ...)`
   pega só o input direto do <p> (grupos de checkbox aninhados ficam de fora, de propósito). */
.form-painel p:has(> .erro-campo) > input,
.form-painel p:has(> .erro-campo) > select {
  border-color: var(--danger);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 20%, transparent);
  background: var(--surface-2);
}

/* ═══ ÁRVORE DE CATEGORIAS (cadastros › Categorias) ═══════════════════════════════
   Família › grupo › subgrupo › categoria, por RECUO. Layout escolhido pelo Tiago entre
   oito mocks (2026-08-04).

   Três réguas que vieram da reprovação de dois mocks:
   · TABELAR — divisor em toda linha e altura uniforme, como a `.tabela`;
   · recuo CONTÍNUO — passo de 18px, e TODA linha tem a calha da seta (na categoria
     ela é invisível). Sem a calha, o texto da categoria VOLTAVA 3px e o degrau
     quebrava. MEDIDO: 36 / 54 / 72 / 90 a partir da borda do cartão;
   · SEM caixa alta — os níveis se separam por peso e cor, não por gritaria. */
.cat-fam { border: 1px solid var(--border); border-radius: 12px; background: var(--surface-2);
  box-shadow: var(--shadow-1); margin-bottom: 12px; overflow: hidden; }
.cat-fam--alerta { border-color: color-mix(in srgb, var(--warning) 55%, var(--border)); }
.cat-fam--alerta > .cat-n1 { background: color-mix(in srgb, var(--warning) 8%, transparent); }
.cat-grp, .cat-sub { display: block; }
.cat-fam summary { list-style: none; cursor: pointer; }
.cat-fam summary::-webkit-details-marker { display: none; }

.cat-n1, .cat-n2, .cat-n3, .cat-n4 { display: flex; align-items: center; gap: 8px;
  height: 38px; font-size: 13.5px; border-bottom: 1px solid var(--border); }
.cat-n1 { height: 44px; font-size: 14.5px; font-weight: 650; padding: 0 14px; border-bottom: none; }
.cat-fam[open] > .cat-n1 { border-bottom: 1px solid var(--border); }
.cat-n2 { padding: 0 14px 0 32px; font-weight: 600; color: var(--text); }
.cat-n3 { padding: 0 14px 0 50px; font-weight: 500; color: var(--text-secondary); }
.cat-n4 { padding: 0 14px 0 68px; color: var(--text); }
.cat-n1:hover, .cat-n2:hover, .cat-n3:hover, .cat-n4:hover { background: var(--surface-1); }
/* o divisor da ÚLTIMA linha some sem `:last-child`: o -1px é comido pelo overflow:hidden
   do cartão. A 1ª versão usava `.cat-n4:last-child` e apagava o divisor de QUASE TODA
   categoria quando os subgrupos viraram <details> aninhados. */
.cat-ramo { margin-bottom: -1px; }

.cat-seta { color: var(--muted); flex: none;
  transition: transform var(--dur) var(--ease); }
details[open] > summary > .cat-seta { transform: rotate(90deg); }
.cat-n4 .cat-seta { visibility: hidden; }   /* a calha fica; a seta some */
.cat-nome { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cat-dir { margin-left: auto; display: flex; align-items: center; gap: 6px; flex: none; }
.cat-n2 > .conta, .cat-n3 > .conta { margin-left: 6px; }

.cat-selo { font-size: 10.5px; padding: 1px 7px; border-radius: 20px;
  border: 1px solid var(--border); color: var(--text-secondary); white-space: nowrap; }
.cat-selo--red { color: var(--danger); border-color: var(--danger); }

/* O VAZIO OCUPA ESPAÇO — de propósito. Sem isto, abrir um nó sem filhos gira a seta e
   não muda 1px: fechado o cartão tem 44px, aberto tem 44px (o -1px do `.cat-ramo` é
   comido pelo `overflow:hidden`). Pra quem está olhando, o clique não fez nada.
   O recuo aqui é o do TEXTO do nível (54 / 72 / 90), não o do container: estas linhas
   não têm a calha da seta, então o padding já é a posição final. */
.cat-vazio { display: flex; align-items: center; height: 38px; font-size: 13px;
  font-style: italic; color: var(--muted); border-bottom: 1px solid var(--border); }
.cat-vazio--2 { padding: 0 14px 0 54px; }
.cat-vazio--3 { padding: 0 14px 0 72px; }
.cat-vazio--4 { padding: 0 14px 0 90px; }
/* nada na página inteira / nada na busca — mesma forma do `{% empty %}` das tabelas */
.cat-nada { padding: 22px; text-align: center; color: var(--muted); }

/* ═══ ABRIR E FECHAR, ANIMADO (o envelope) ═════════════════════════════════
   `<details>` nao anima sozinho: o navegador liga e desliga o conteudo de uma vez. O
   envelope e um grid que vai de `0fr` a `1fr` — o navegador interpola a altura SOZINHO,
   sem ninguem medir nada em JS, e funciona ANINHADO: abrir um subgrupo faz o grupo e a
   familia crescerem junto, na mesma transicao. Medido no mock: subgrupo 0→152px levou o
   grupo de 76→228 e a familia de 265→417, e fechar devolveu os valores exatos.

   O envelope TEM que ser filho direto do <details> (`details[open] > .env`). Ja quebrou
   uma vez com um `.cat-ramo` por fora: a familia ficava `open` e invisivel ao mesmo tempo.

   Escolha do Tiago entre cinco (2026-08-06): CORTINA + ESMAECER. A altura desenrola e o
   conteudo entra esmaecendo junto — sem o esmaecer, as linhas aparecem cortadas ao meio
   no meio do movimento. */
.env { display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows var(--mov-cortina) var(--mov-cortina-ease); }
details[open] > .env { grid-template-rows: 1fr; }
/* 🔴 28/08 — o Chrome moderno passou a esconder o conteúdo do <details> FECHADO com
   `content-visibility: hidden` (pseudo-elemento ::details-content). O .env lá dentro
   deixou de ter estilo "antes", e a cortina parou de interpolar: abria num PULO, nas
   três telas do envelope — Categorias inclusive, a dona do padrão. Medido no extrato
   (28/08): clique real abria 0→280px em <50ms, ZERO transitionrun; com esta regra, a
   transição volta a disparar. Quem esconde o fechado é o 0fr da cortina, como sempre
   foi. A regra fica SOZINHA de propósito: navegador que não conhece o pseudo-elemento
   descarta a regra — e os antigos nem precisam dela. */
details::details-content { content-visibility: visible; }
/* …e o conteúdo fechado-porém-renderizado NÃO pode ser focável por teclado nem vazar
   no movimento-reduzido: `visibility` esconde DEPOIS que a cortina fecha (o atraso é
   a duração dela) e volta na hora ao abrir. */
.env-in { overflow: hidden; min-height: 0; opacity: 0; visibility: hidden;
  transition: opacity var(--mov-esmaece) var(--mov-esmaece-atraso) ease,
              visibility 0s var(--mov-cortina); }
details[open] > .env > .env-in { opacity: 1; visibility: visible;
  transition-delay: var(--mov-esmaece-atraso), 0s; }

/* 🔴 filtrando, a animacao SAI. A busca abre e fecha dezenas de nos por tecla digitada —
   animar tudo isso engasga e ainda atrasa o resultado que a pessoa esta esperando ver. */
#arvore-cat.filtrando .env,
#arvore-cat.filtrando .env-in,
#arvore-cat.sem-anim .env,
#arvore-cat.sem-anim .env-in { transition: none; }

@media (prefers-reduced-motion: reduce) {
  .env, .env-in { transition: none; }
  .env-in { opacity: 1; }
}

/* ═══ ARRASTAR CATEGORIA (E + D + C, escolha do Tiago) ═════════════════════
   A alca ocupa os mesmos 13px da setinha invisivel que ela substitui — sem isso o texto
   da categoria andaria e o degrau 36/54/72/90 quebrava.

   O gesto NAO usa o arrasto nativo do HTML5, e isso e obrigatorio, nao gosto: durante o
   arrasto a arvore RECOLHE as categorias, e mexer no elemento que esta sendo arrastado
   cancela a sessao de arrasto do navegador. Custou dois consertos falhos pra descobrir.
   Ver `static/js/arvore-cat.js`. */
.cat-grip { flex: none; width: 13px; display: flex; align-items: center; justify-content: center;
  color: var(--muted); cursor: grab; opacity: 0; transition: opacity var(--dur) var(--ease); }
.cat-n4:hover .cat-grip, .cat-n4:focus-within .cat-grip { opacity: 1; }
.cat-grip:active { cursor: grabbing; }
[data-carregando] .cat-grip { opacity: 0; }
.cat-n4 { transition: opacity .14s, transform .14s, background .14s; }
[data-carregando] .cat-n4 { user-select: none; -webkit-user-select: none; }
/* 🔴 enquanto arrasta, NADA na pagina seleciona. So a linha nao basta: o ponteiro passeia
   por cima do resto e a selecao vai junto, pintando a tela de azul. O impedimento de
   verdade e o `preventDefault()` no pointerdown; isto aqui e o cinto de seguranca. */
body.cat-arrastando { user-select: none; -webkit-user-select: none; cursor: grabbing; }
.cat-n4[data-pk] { touch-action: none; }

/* E — a linha encolhe ao ser pega, e salta pra dentro ao cair */
.cat-n4.arrastando { opacity: var(--mov-carregado); transform: scale(.975); background: var(--surface-1); }
.cat-n4.encaixou { animation: cat-encaixa var(--mov-mola) var(--mov-mola-ease); }
@keyframes cat-encaixa {
  0%   { transform: scale(.9) translateX(-12px);
         background: color-mix(in srgb, var(--primary) 22%, transparent) }
  62%  { transform: scale(1.015) translateX(0) }
  100% { transform: scale(1); background: transparent } }

/* E — o alvo da um empurraozinho ao receber */
.cat-sub.alvo > .cat-n3 { background: color-mix(in srgb, var(--primary) 13%, transparent);
  box-shadow: inset 0 0 0 2px var(--primary); animation: cat-recebe var(--mov-recebe) var(--ease); }
@keyframes cat-recebe { 0% { transform: translateX(0) } 38% { transform: translateX(5px) }
  100% { transform: translateX(0) } }
.cat-sub.alvo--nao > .cat-n3 { background: color-mix(in srgb, var(--danger) 8%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--danger) 45%, transparent); }

/* C — a etiqueta que segue o cursor: diz o QUE voce carrega e PRA ONDE vai */
#cat-pill { position: fixed; z-index: 90; pointer-events: none; display: none;
  align-items: center; gap: 9px; max-width: 320px; padding: 9px 13px; border-radius: 11px;
  font-size: 13px; font-weight: 600; background: var(--surface-2); color: var(--text);
  border: 1px solid var(--border); box-shadow: var(--shadow-2);
  transition: border-color .12s; }
#cat-pill.on { display: flex; }
#cat-pill.ok { border-color: var(--primary); }
#cat-pill.nao { border-color: var(--danger); }
#cat-pill .sinal { flex: none; width: 18px; height: 18px; border-radius: 50%; display: flex;
  align-items: center; justify-content: center; font-size: 11px; font-weight: 700;
  background: var(--muted); color: var(--canvas); transition: background .12s; }
#cat-pill.ok .sinal { background: var(--primary); }
#cat-pill.nao .sinal { background: var(--danger); }
#cat-pill .nome { display: block; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; max-width: 260px; }
#cat-pill .destino { display: block; font-weight: 500; color: var(--muted);
  font-size: 11.5px; margin-top: 1px; }

@media (prefers-reduced-motion: reduce) {
  .cat-n4, .cat-n4.encaixou, .cat-sub.alvo > .cat-n3 { animation: none; transition: none; }
}

/* o aviso de "movida" / "nao deu". Nome PROPRIO (`#cat-toast`) e nao `.salvo-tag`: aquela
   e definida dentro do <style> da pagina de Niveis, e reusar o nome faria duas definicoes
   do mesmo seletor viverem em arquivos diferentes — ja quebrou producao uma vez. */
#cat-toast { position: fixed; bottom: 22px; left: 50%; transform: translateX(-50%) translateY(20px);
  background: var(--text); color: var(--canvas); padding: 9px 16px; border-radius: 999px;
  font-size: 13px; font-weight: 600; opacity: 0; transition: opacity .25s, transform .25s;
  z-index: 95; box-shadow: var(--shadow-2); }
#cat-toast.on { opacity: 1; transform: translateX(-50%) translateY(0); }
#cat-toast.ruim { background: var(--danger); color: #fff; }

/* ═══ O SELETOR DO "NOVO" ═══════════════════════════════════════════════════
   Nome proprio (`cat-esc-*`) e nao `.esc-*`: o tokens.css e global, e classe generica
   colide entre telas — ja quebrou producao uma vez. */
.cat-esc { display: flex; flex-direction: column; gap: 8px; }
.cat-esc-item { display: flex; align-items: flex-start; gap: 11px; text-align: left;
  padding: 13px 14px; border: 1px solid var(--border); border-radius: 11px;
  background: var(--surface-1); color: var(--text); text-decoration: none;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease); }
.cat-esc-item:hover { background: var(--surface-2); border-color: var(--border-strong, var(--primary)); }
.cat-esc-item .ic-badge { margin-top: 1px; }
.cat-esc-tit { display: block; font-size: 14px; font-weight: 650; }
.cat-esc-sub { display: block; margin-top: 2px; font-size: 12.5px; line-height: 1.45;
  color: var(--text-secondary); }

/* as acoes de um no (editar / excluir), a direita da linha — so no hover, pra nao poluir
   uma arvore de 134 linhas com 100 botoes sempre acesos */
.cat-acoes { margin-left: auto; display: flex; align-items: center; gap: 2px; flex: none;
  opacity: 0; transition: opacity var(--dur) var(--ease); }
.cat-n1:hover .cat-acoes, .cat-n2:hover .cat-acoes, .cat-n3:hover .cat-acoes,
.cat-acoes:focus-within { opacity: 1; }
.cat-acao { display: flex; align-items: center; justify-content: center; width: 26px; height: 26px;
  border-radius: 7px; color: var(--muted); background: transparent; border: none;
  text-decoration: none; }
.cat-acao:hover { background: var(--canvas); color: var(--text); }
.cat-acao--perigo:hover { background: color-mix(in srgb, var(--danger) 14%, transparent);
  color: var(--danger); }
[data-carregando] .cat-acoes { opacity: 0; }

/* ═══ ARRASTAR NA CARREIRA (reordenar a escada de níveis) ═════════════════════
   Nome próprio (`carr-*`) e escopo por `#niveis-body`, nunca `.vaga`/`.faixa`/`.carta`
   soltas: o tokens.css é global e classe genérica colide entre telas — já quebrou
   produção uma vez.

   Três peças, cada uma respondendo a uma pergunta: a CARTA na mão (o que eu movo), a VAGA
   aberta (para onde, e com que número) e a FAIXA + os números renumerando (o que isso faz
   com o resto da escada). Mock aprovado pelo Tiago em 2026-08-10. */

/* a linha INTEIRA é a alça — a alça só aponta onde. Amarrar o gesto à célula da alça deixa
   um alvo de 31px numa linha de 839, e o instinto de todo mundo é agarrar pelo NOME, onde
   não acontecia nada (medido em Chrome). */
#niveis-body tr[data-pk] { cursor: grab; }
#niveis-body tr[data-pk]:active { cursor: grabbing; }
#niveis-body tr[data-pk] a { cursor: pointer; }

/* 🔴 `touch-action` NÃO SE APLICA A `table-row` — a spec exclui linha, grupo de linha e
   coluna. Declarado no <tr> ele computa `none` e não vale nada: o alvo real do toque é a
   <td>, que segue `auto`, e o navegador entende o arrasto como ROLAGEM —
   `pointerdown · pointermove · pointermove · pointercancel`, o gesto morre no 2º movimento
   e no celular a tela fica INUSÁVEL. Vai nas CÉLULAS. (Em Categorias a mesma declaração
   funciona no elemento da linha porque lá ele é um `div`.) */
#niveis-body tr[data-pk] > td { touch-action: none; }

/* a alça fica VISÍVEL em repouso — exceção deliberada ao `0→1` de Categorias: aqui ela tem
   COLUNA PRÓPRIA (invisível vira coluna vazia inexplicada) e no celular não existe hover,
   então `opacity:0` a esconderia pra sempre. */
#niveis-body .grip { opacity: .4; transition: opacity var(--dur) var(--ease); }
#niveis-body tr:hover .grip, #niveis-body tr:focus-within .grip { opacity: 1; }

/* a página inteira para de selecionar durante o gesto: a seleção nasce no ponteiro e
   acompanha ele pela tela toda, não só pela linha. */
body.carr-arrastando { user-select: none; -webkit-user-select: none; }

/* a FAIXA que anda um degrau — vem ANTES da vaga, que precisa ganhar dela */
#niveis-body tr.carr-faixa td,
#niveis-body tr.carr-faixa:hover td { background: color-mix(in srgb, var(--primary) 5%, transparent); }

/* a VAGA: o buraco do tamanho exato da linha, com trilhos em cima e embaixo.
   🔴 `td > *` só alcança FILHO-ELEMENTO — por isso TODO conteúdo de célula vai embrulhado
   no template. Texto solto na <td> ficaria em opacidade 1 e a linha esmaeceria pela
   metade, lendo como linha apagada em vez de buraco. */
#niveis-body tr.carr-vaga td,
#niveis-body tr.carr-vaga:hover td {
  background: color-mix(in srgb, var(--primary) 9%, transparent);
  box-shadow: inset 0 2px 0 var(--primary), inset 0 -2px 0 var(--primary); }
#niveis-body tr.carr-vaga td > * { opacity: .42; }   /* a vaga: um tom acima do carregado, de proposito */
#niveis-body tr.carr-vaga .ordem-num { opacity: 1; color: var(--primary); font-weight: 700; }

/* o ENCAIXE ao pousar: mola curta, a mesma de `cat-encaixa` */
#niveis-body tr.carr-encaixou td { animation: carr-encaixa var(--mov-mola) var(--mov-mola-ease); }
@keyframes carr-encaixa {
  0%   { background: color-mix(in srgb, var(--primary) 22%, transparent) }
  62%  { background: color-mix(in srgb, var(--primary) 10%, transparent) }
  100% { background: transparent } }

/* o NÚMERO que muda durante o gesto */
#niveis-body .ordem-num { display: inline-block; min-width: 14px; }
#niveis-body .ordem-num.mudou { animation: carr-num var(--mov-recebe) var(--ease); }
@keyframes carr-num {
  0%   { transform: translateY(-4px); opacity: .25; color: var(--primary) }
  100% { transform: none; opacity: 1 } }

/* a CARTA na mão: a própria linha, erguida da mesa */
#carr-carta {
  position: fixed; z-index: 90; pointer-events: none; display: none;
  align-items: center; gap: 10px; max-width: 400px; padding: 9px 13px; border-radius: 11px;
  font-size: 14px; background: var(--surface-2); color: var(--text);
  border: 1px solid var(--border-strong); box-shadow: var(--shadow-2);
  transform-origin: 0 0; transform: rotate(-1.4deg) scale(1.02); }
#carr-carta.on { display: flex; animation: carr-ergue .16s var(--ease); }
@keyframes carr-ergue {
  from { transform: rotate(0deg) scale(.99); box-shadow: var(--shadow-1); opacity: .55 }
  to   { transform: rotate(-1.4deg) scale(1.02); box-shadow: var(--shadow-2); opacity: 1 } }
#carr-carta .carr-nome { font-weight: 600; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; max-width: 170px; }
#carr-carta .carr-sep { width: 1px; align-self: stretch; background: var(--border); flex: none; }
#carr-carta .carr-dest { display: flex; align-items: center; gap: 7px; }
#carr-carta .carr-sinal { flex: none; width: 18px; height: 18px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; font-size: 11px;
  font-weight: 700; background: var(--primary); color: var(--on-primary);
  transition: background .12s; }
#carr-carta.parada .carr-sinal { background: var(--muted); }
#carr-carta .carr-vira { display: block; font-size: 12.5px; font-weight: 600;
  color: var(--primary); line-height: 1.25; }
#carr-carta.parada .carr-vira { color: var(--muted); }
#carr-carta .carr-entre { display: block; font-size: 11.5px; font-weight: 500;
  color: var(--muted); line-height: 1.3; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; max-width: 210px; }

@media (prefers-reduced-motion: reduce) {
  #niveis-body tr.carr-encaixou td, #niveis-body .ordem-num.mudou, #carr-carta.on {
    animation: none; }
  #niveis-body .grip { transition: none; }
}
/* ═══ REVELAÇÃO CONDICIONAL — o envelope onde NÃO há <details> ════════════════
   Mesma cortina do `.env`, aberta por classe: um aviso que aparece quando o campo diverge,
   uma nota que explica o que a mecânica acabou de fazer. Antes esses blocos entravam com
   `hidden` e o formulário PULAVA.

   🔴 A `visibility` NÃO É ENFEITE. Com só `overflow:hidden`, o conteúdo fechado continua
   FOCÁVEL — no `cargo-motivo` são rádios: a pessoa dá Tab e o foco cai dentro de um bloco de
   altura zero, invisível. `visibility:hidden` tira do foco; o atraso de .26s ao FECHAR deixa
   a cortina descer antes de sumir, e o `0s` ao abrir traz de volta na hora. */
.rev { display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows var(--mov-cortina) var(--mov-cortina-ease); }
.rev > .rev-in { overflow: hidden; min-height: 0; opacity: 0; visibility: hidden;
  transition: opacity var(--mov-esmaece) var(--mov-esmaece-atraso) ease,
              visibility 0s var(--mov-cortina); }
.rev.aberto { grid-template-rows: 1fr; }
.rev.aberto > .rev-in { opacity: 1; visibility: visible;
  transition: opacity var(--mov-esmaece) var(--mov-esmaece-atraso) ease, visibility 0s 0s; }
@media (prefers-reduced-motion: reduce) {
  .rev, .rev > .rev-in { transition: none; }
}

/* 🔴 O `.rev` dentro de um campo de formulário precisa HERDAR o lugar que o conteúdo tinha.
   O `.cargo-diverge` declara `align-self: flex-start` (o pai é flex em coluna): embrulhado,
   o `align-self` passaria a valer pro filho errado e o aviso ESTICARIA a largura toda. */
.rev--campo { align-self: flex-start; }

/* ── Escolha com CONSEQUÊNCIA à vista ─────────────────────────────────────────────────
   Um radio desenhado como cartão, com o efeito da escolha embaixo do rótulo. Nasceu na
   ficha de banco (2026-08-20): marcar "distribuição" ARMA a R06, e quem marca precisa ler
   isso ali — não descobrir depois que travou o fechamento do dia. Um `select` esconde o que
   cada opção FAZ; a pessoa escolhe um rótulo, não uma consequência.
   O `input` é NATIVO e fica só visualmente escondido — o valor chega ao POST sozinho, sem
   hidden e sem JS. É a régua do "marcação sem JS é defeito mudo". */
.opc-lista { display: grid; gap: 8px; }
.opc-tipo input { position: absolute; opacity: 0; pointer-events: none; }
.opc-cx { display: block; border: 1px solid var(--border-strong); border-radius: 10px;
          padding: 10px 12px; cursor: pointer; }
.opc-tipo input:checked + .opc-cx { border-color: var(--primary);
          box-shadow: inset 0 0 0 1px var(--primary); }
.opc-tipo input:focus-visible + .opc-cx { outline: 2px solid var(--primary); outline-offset: 2px; }
.opc-top { display: flex; align-items: center; gap: 8px; font-size: 13.5px; }
.opc-efeito { display: block; font-size: 11.5px; color: var(--text-secondary); margin-top: 3px; }

/* ── Campo que NÃO se edita, e diz por quê ────────────────────────────────────────────
   Não é um input desabilitado: input desabilitado parece campo que alguém pode reabrir.
   Este é texto com cadeado e a razão escrita — nasceu para o saldo de abertura da conta
   bancária, que ninguém altera pelo SuperApp (decisão do Bernardo, 2026-08-20). */
.campo-travado { display: flex; gap: 10px; align-items: flex-start; margin-top: 12px;
                 border: 1px solid var(--border-strong); border-radius: 10px; padding: 10px 12px; }
.campo-travado .ic-badge { flex: none; }
.trava-lin { display: flex; gap: 9px; align-items: baseline; flex-wrap: wrap; }
.trava-rot { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.trava-val { font-size: 16px; font-weight: 600; }
.trava-em { font-size: 11.5px; color: var(--muted); }
.trava-ex { display: block; font-size: 11.5px; color: var(--text-secondary); margin-top: 5px;
            line-height: 1.5; }


/* ══════════════════════════════════════════════════════════════════════════════════
   2026-08-22 — quatro regras aprovadas pelo Tiago (mock a mock). O porquê de cada uma
   está em `projetos/design-system-painel.md`, no cérebro, que é a fonte normativa.
   ══════════════════════════════════════════════════════════════════════════════════ */

/* 1 · O BOTÃO DESABILITADO — não existia.
   Sem isto um botão inoperante fica com a cara de ativo e só não responde, que é pior que
   não existir. A régua não foi inventada: é a mesma de `.dd-trigger:disabled` (.55),
   `.item-ic:disabled` (.5) e `.tcard--inativo` (.55). */
.botao:disabled, .botao[disabled], .botao[aria-disabled="true"] {
  opacity: .55; cursor: not-allowed; }
.botao:disabled:hover, .botao[disabled]:hover, .botao[aria-disabled="true"]:hover {
  filter: none; }
/* ⚠️ `<a>` não tem `disabled`: um link "apagado" continua clicável. Quando o
   desabilitado é um link, use `<span class="botao" aria-disabled="true">` — sem href,
   sem clique, e o mesmo desenho. */

/* 2 · O RODAPÉ GRUDENTO NÃO CHEGAVA AO FIM — e isso valia para TODOS os popups.
   `.acoes-form` é `sticky; bottom: 0` dentro do `.modal-corpo`, que tinha
   `padding-bottom: 24px`. Sticky gruda na borda da caixa de PADDING, ou seja 24px acima do
   fim real — e o conteúdo passava por baixo naquela faixa. Medido em 22/08: folga de 24px;
   depois deste conserto, 0.
   ⚠️ Não conserte com `bottom: -24px`: amarra o rodapé ao padding do pai por um número
   mágico e volta a quebrar calado no dia em que o padding mudar. */
.modal-corpo { padding-bottom: 0; }
.modal-corpo .acoes-form { padding-top: 16px; padding-bottom: 24px; border-top: none; }
/* 🔴 25/08 — E O ZERO ACIMA VALE PRA TODOS, MAS A DEVOLUÇÃO SÓ VALIA PRA QUEM TEM RODAPÉ.
   O `padding-bottom: 0` foi posto pro rodapé GRUDENTO alcançar o fim do cartão, e a
   profundidade voltou pelo padding do próprio `.acoes-form`. **Popup SEM rodapé grudento
   não tem `.acoes-form` nenhum** — e ficou com o último elemento colado na borda.
   Medido em 25/08 no "Novo plano de contas": folga de **1px** abaixo do último cartão.
   São NOVE corpos nessa situação (os 3 modais de agentes, a ficha de banco, a escolha do
   plano de contas, os colaboradores da escala, o histórico do usuário, acessos e
   administradores) — todos assim desde 22/08, e ninguém tinha olhado.
   ⚠️ O `:not(:has(...))` é de propósito: amarra a devolução à AUSÊNCIA do rodapé, em vez de
   listar quais popups têm direito. Lista de exceções envelhece quando nasce o décimo. */
.modal-corpo:not(:has(.acoes-form)) { padding-bottom: 24px; }

/* 3 · O BRASÃO DO POPUP COM SUBTÍTULO centra no BLOCO, não na primeira linha.
   ⚠️ Isto NÃO reabre o `center` global que o #160 reprovou: lá o caso era título curto e SEM
   subtítulo, em que o badge (34px fixos) mandava na altura e o texto flutuava. Com subtítulo
   o texto pesa para baixo e o badge de 34px sobre uma linha de 25px lê como alto. */
.modal-card .barra-tit:has(.modal-sub) { align-items: center; }
.modal-card .barra-tit:has(.modal-sub) .ic-badge { margin-top: 0; }

/* 4 · O SWITCH GANHOU O MOTOR QUE NUNCA TEVE.
   🔴 O `.switch` estava aqui desde sempre e **nenhum template o usava** — porque ele é um
   `<button role="switch" aria-checked>` e **não havia uma linha de JS** que o virasse.
   Componente morto: colar o markup entregava um controle inerte, e nenhum teste veria
   (Django não roda JavaScript). O motor entrou em `static/js/switch.js`, no mesmo idioma de
   `ligarCargos`/`ligarVinculos`/`ligarCeps`, e o `modal.js` o religa ao trocar o HTML.
   O CSS abaixo é só o acabamento que faltava; a pílula em si já existia mais acima. */
.switch:disabled { opacity: .55; cursor: not-allowed; }
.switch:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }


/* A linha do PERÍODO do extrato: mês, ano e os três números que aquele mês soma — tudo numa
   linha só. O número mora ao lado do controle que o altera (design system, 22/08). */
/* 🔴 `flex-direction: row` EXPLÍCITO — a linha do período é um `<form>` (para o mês e o
   ano submeterem no `change`), e a casa tem um `form { flex-direction: column }`
   global. Sem esta linha, cada campo cai numa fileira, centrado, e os números se
   separam do controle que os altera. Foi o que aconteceu em produção, 23/08:
   medido `flex-direction: column` com os cinco filhos em `top` 159/217/275/329/382.
   ⚠️ `.barra` num `<form>` sempre vai precisar disto — a classe não vence o seletor
   de elemento por especificidade em todos os casos, e aqui não vencia. */
.extrato-periodo { flex-direction: row; justify-content: flex-start; align-items: center;
  gap: 10px; flex-wrap: wrap; row-gap: 14px; }
/* Os números vão para a DIREITA (pedido do Tiago, 23/08): o `margin-left: auto` no
   primeiro deles empurra o trio inteiro, e o seletor fica encostado à esquerda.
   ⚠️ `auto` no PRIMEIRO, não `justify-content: space-between` na barra: com
   `space-between` os três números se espalhariam entre si quando a linha sobrasse. */
/* 🔴 Classe explícita, NÃO `:first-of-type`. O `dropdown.js` injeta um `<div class="dd">`
   em volta do `<select>`, e ele vira o primeiro `div` da linha — o `margin-left: auto`
   caía nele e afastava o seletor de mês da esquerda (medido: 172px de recuo).
   Seletor posicional quebra quando JS injeta elemento no meio. */
.extrato-somas { display: flex; align-items: center; gap: 24px; margin-left: auto; }
/* ♻️ 25/08 — o seletor de MÊS+ANO virou DE/ATÉ (pedido do Bernardo). Saíram com ele duas
   regras que não "quebraram": ficaram SEM ALVO. Uma era a largura do campo de ano; a outra,
   a largura mínima do gatilho que o `dropdown.js` constrói para o `<select>` de mês — o
   gatilho encolhia até caber "Agosto" e cortava "Setem…", "Nove…", "Deze…" (medido em 23/08).
   Ficam registradas aqui porque, no dia em que voltar um `<select>` estreito numa barra, o
   problema volta com ele. */
.campo-data { display: flex; align-items: center; gap: 8px; }
.campo-data > .rotulo { margin: 0; }
.campo-data input { width: 152px; }
/* 27/08: no EXTRATO as três somas dividem a linha com as datas (o Saldo inicial desceu
   pra lista) — e o miolo tem 760px. Na folga original (input 152 + gap 24) o conjunto
   media 764px e quebrava a linha por 4px. A régua justa vale SÓ aqui: Movimentações
   usa a mesma barra com DUAS somas e segue na folga. Medido: 148px é o mínimo que
   mostra "01/08/2026" inteiro sem o ícone morder o ano. */
.extrato-periodo--justo .campo-data input { width: 148px; }
.extrato-periodo--justo .extrato-somas { gap: 12px; }

/* ═══ O EXTRATO POR DIA — colapsado, com o `<details>` da casa ═══════════════════════════
   A MESMA peça de Categorias: `<details>` + `.env` (cortina + esmaecer, escolha do Tiago em
   06/08), **zero JS**. O envelope tem que ser filho direto do `<details>`.

   📐 Uma superfície só: o `.dias-wrap` é a caixa (borda + raio 12px, igual à `.tabela-wrap`),
   e as tabelas de dentro perdem a borda delas — senão é card dentro de card. */
.dias-wrap { border: 1px solid var(--border); border-radius: 12px; overflow: hidden;
  background: var(--surface-2); box-shadow: var(--shadow-1); }
.dia + .dia { border-top: 1px solid var(--border); }
.dia-cab { display: flex; align-items: center; gap: 10px; min-height: 46px; padding: 0 14px;
  cursor: pointer; list-style: none; font-size: 13.5px; }
.dia-cab::-webkit-details-marker { display: none; }
.dia-cab:hover { background: var(--surface-1); }
.dia[open] > .dia-cab { border-bottom: 1px solid var(--border); }
.dia-seta { color: var(--muted); flex: none; transition: transform var(--dur) var(--ease); }
details[open] > .dia-cab > .dia-seta { transform: rotate(-90deg); }
.dia-data { font-weight: 650; flex: none; }
.dia-quantos { color: var(--muted); font-size: 12.5px; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* o saldo do dia é o que a pessoa veio ver: nunca encolhe nem quebra */
/* ♻️ 27/08 (3ª rodada): morreram `.dia-saldos`, `--um`, `.sal-moeda`, `.sal-num`,
   `.dia-ate` e as regras de `.dia .tabela` — a lista virou UMA régua de 6 colunas e as
   tabelas de dentro do dia viraram linhas `.mov`. Registrado pra ninguém ressuscitar
   regra sem alvo junto com código antigo. */

/* A régua: [moeda|número] × Entradas · Saídas · Saldo, larguras FIXAS (moeda 4ch,
   números 9/9/12ch) — com `auto`, cada linha mediria o próprio "R$" e a coluna
   dançaria entre linhas. ⚠️ O `ch` é medido na fonte do CONTAINER: o `.dia-trio` leva
   `mono` SEMPRE, até no cabeçalho de rótulos (sem isso a grade dele saiu 34px mais
   estreita, medido no mock). */
.dia-trio { display: grid; grid-template-columns: 4ch 9ch 4ch 9ch 4ch 12ch; column-gap: 6px;
  margin-left: auto; align-items: baseline; font-size: 13px; flex: none; }
.dia-trio > * { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.dia-trio .c-e-m { grid-column: 1; }   .dia-trio .c-e-n { grid-column: 2; }
.dia-trio .c-s-m { grid-column: 3; margin-left: 16px; }   .dia-trio .c-s-n { grid-column: 4; }
.dia-trio .c-sal-m { grid-column: 5; margin-left: 16px; } .dia-trio .c-sal-n { grid-column: 6; }

/* Negativo é VERMELHO (27/08). O desenho anterior escrevia `var(--erro)` no template —
   um token que NUNCA existiu: o navegador ignorava calado e nada ficava vermelho. */
.neg { color: var(--danger); }

/* O cabeçalho das colunas — um rótulo por PAR (nth-child aqui é seguro: bloco fixo,
   sem JS injetando elemento no meio). Os rótulos voltam pra fonte da casa. */
.extrato-cab { display: flex; align-items: center; min-height: 36px; padding: 0 14px;
  background: var(--surface-1); border-bottom: 1px solid var(--border); }
.extrato-cab .rotulo { margin: 0; font-family: "IBM Plex Sans", system-ui, sans-serif; }
.extrato-cab .dia-trio > span:nth-child(1) { grid-column: 1 / 3; }
.extrato-cab .dia-trio > span:nth-child(2) { grid-column: 3 / 5; margin-left: 16px; }
.extrato-cab .dia-trio > span:nth-child(3) { grid-column: 5 / 7; margin-left: 16px; }

/* a linha-âncora: mesma anatomia do dia, sem seta e sem clique */
.dia--ancora .dia-cab { cursor: default; background: var(--surface-1); }
.dia--ancora .dia-quantos { color: var(--muted); }
.dia--ancora .vaga-seta { width: 13px; flex: none; }

/* a linha de movimento (dentro do dia aberto e no dia único) */
.mov { display: flex; align-items: center; min-height: 40px; padding: 0 14px;
  border-top: 1px solid var(--border); background: var(--surface); font-size: 13.5px; }
.mov-desc { overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  margin-right: 12px; }
.env-in .mov:first-child { border-top: none; }

/* O dia expande PRA CIMA (27/08): os movimentos desdobram ACIMA da linha do dia, e a
   linha do dia — com o fechamento — fica embaixo deles, fazendo ela mesma o papel de
   rodapé. No DOM o <summary> segue PRIMEIRO (exigência do <details>); o visual inverte
   com `column-reverse`. A cortina (.env 0fr→1fr) é a MESMA do Plano de contas e segue
   funcionando: quem anima é o envelope, não a ordem visual. */
details.dia { display: flex; flex-direction: column-reverse; }
details.dia[open] > summary { border-top: 1px solid var(--border);
  background: var(--surface-1); }

/* mobile: some a contagem de movimentos (o saldo é o que importa) e o dia ganha a linha */
@media (max-width: 520px) {
  .dia-quantos { display: none; }
  /* …menos na âncora (27/08): "2 movimentos" é dispensável, "Saldo inicial" é a
     identidade da linha — sem ele sobraria uma data com um número sem nome. */
  .dia--ancora .dia-quantos { display: inline; }
  .campo-data input { width: 100%; }
  .campo-data { flex: 1 1 140px; }
  /* 🔴 Os números viraram QUATRO em 25/08 (entrou o saldo inicial) e deixaram de caber numa
     linha: medido a 390px, o último terminava 15px FORA do conteúdo e a página inteira
     passava a rolar na horizontal. Quatro numa linha é desenho de desktop; no celular eles
     viram grade 2×2, que é o mesmo conteúdo sem empurrar nada para fora. */
  .extrato-somas { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 18px;
    margin-left: 0; width: 100%; }
  /* ♻️ 27/08: no extrato viraram TRÊS (o saldo inicial desceu pra lista) — a grade fica:
     três numa linha ainda não cabem a 390px. E a variante justa devolve aqui o que
     apertou no desktop, senão a especificidade dela venceria estas duas regras. */
  .extrato-periodo--justo .campo-data input { width: 100%; }
  .extrato-periodo--justo .extrato-somas { gap: 12px 18px; }
  /* A régua de 6 colunas não cabe em 375px. No celular ela vira DUAS: a linha de dia
     (e a âncora) mostra só o SALDO; a de movimento, só o VALOR — cada uma remapeada
     pras colunas 1-2. O cabeçalho fica só com o rótulo Saldo. */
  .dia-trio { grid-template-columns: 4ch 12ch; }
  .dia-cab .c-e-m, .dia-cab .c-e-n, .dia-cab .c-s-m, .dia-cab .c-s-n { display: none; }
  .dia-cab .c-sal-m { grid-column: 1; margin-left: 0; }
  .dia-cab .c-sal-n { grid-column: 2; }
  .mov .c-sal-m, .mov .c-sal-n { display: none; }
  .mov .c-e-m, .mov .c-s-m { grid-column: 1; margin-left: 0; }
  .mov .c-e-n, .mov .c-s-n { grid-column: 2; }
  .extrato-cab .dia-trio > span:nth-child(1),
  .extrato-cab .dia-trio > span:nth-child(2) { display: none; }
  .extrato-cab .dia-trio > span:nth-child(3) { grid-column: 1 / 3; margin-left: 0; }
}

/* ── as marcas do livro de movimentações ─────────────────────────────────────────────
   Delta de DUAS regras. Todo o resto reusa `.selo--marca`, `.selo--tom1..4` e
   `.selo--vermelho`, que já existem.

   🔴 A REGRA DOS SELOS É INEGOCIÁVEL (Tiago, 31/08): todo selo é a MESMA cápsula, variando só
   o tom. Tentei dar borda a um e transformar outro em texto — os dois foram reprovados. Se uma
   marca nova não couber nos quatro degraus, o que muda é o AGRUPAMENTO, nunca a forma.

   🔑 O tom agrupa por NATUREZA, e o texto do selo é que identifica a marca:
     tom1 contexto (caixa · recorrente) · tom2 tempo (borderô · parcelado)
     tom3 espaço (compartilhada · rateada) · tom4 estado (parcial) · vermelho alarme (vencida) */

/* a marca que fala da DATA desce sob ela, em vez de disputar espaço com a descrição */
.sob-data { display: block; margin-top: 4px; }

/* o secundário de uma linha de popup: quem, e quando o dinheiro entra de fato.
   ⚠️ Existe porque o popup tem 460px e quatro colunas não cabem — `.modal-corpo .tabela td.num`
   deixa o valor QUEBRAR em duas linhas quando aperta. Duas colunas, e o resto desce. */
.quem { display: block; color: var(--muted); font-size: 12px; margin-top: 2px; }

/* ── primeiro acesso por SMS (01/09/2026) ───────────────────────────────────── */
/* o campo do codigo: digito grande e espacado, que e' como se le codigo */
.entrada .codigo { text-align: center; font-size: 24px; letter-spacing: .32em;
                   padding-left: .32em; }
/* o reenviar mora FORA do form do codigo, abaixo dele, ocupando a largura toda */
.entrada .reenviar { width: 100%; margin-top: 10px; }
