/* Paleta baseada no apontamentos-v2 (assets/css/app.css) — mesmos tokens,
   adaptados pra esta sidebar. "Padrão" é o único tema claro; Escuro/Cinza/
   Azul são variantes escuras, diferenciadas pela cor de marca dominante. */
html[data-theme="padrao"] {
  /* --color-surface era #ffffff puro — branco "estourado" cansa a vista em
     telas cheias de cards (pedido do Adriano, 03/08/2026). Suavizado pra um
     branco levemente acinzentado; --color-bg escurecido um pouco junto, pra
     manter a mesma diferença visual entre fundo da página e card. */
  --color-bg: #eef1f6;
  --color-surface: #fafbfc;
  --color-border: #d7dee7;
  --color-text: #1f2733;
  --color-text-muted: #6b7686;
  --color-brand: #ff6700;
  --color-brand-dark: #e05a00;
  --color-brand-soft: rgba(255, 103, 0, .12);
  --color-sidebar-bg: #16202e;
  --color-sidebar-text: #c7d0dc;
  --color-sidebar-hover: #22303f;
  --color-sidebar-active: #ff6700;
  --shadow-sm: 0 1px 2px rgba(16, 24, 40, .06);
  --shadow-md: 0 4px 12px rgba(16, 24, 40, .08);
  --radius: .6rem;
  /* Semáforo de status — mesmos valores do v1 (index.html --ok/--warn/--danger/
     --blue), fixos entre temas (verde/âmbar/vermelho/azul não mudam com a marca).
     EXCEÇÃO: --color-ok escurecido SÓ neste tema (claro) — o tom original
     #10b981 dá só ~2,55:1 de contraste contra fundo branco (abaixo do
     mínimo de acessibilidade, 4,5:1), achado do Adriano comparando texto
     verde em "Trimestre a trimestre" (14/08/2026). Nos 3 temas escuros
     esse mesmo verde já tem contraste alto contra fundo escuro, não
     precisou mudar lá. #047857 dá ~5,6:1 contra branco — MESMO tom já
     vetado em `.app-ticket-sla-badge.ok` (abaixo no arquivo), reaproveitado
     aqui em vez de inventar um verde novo (#0d7a52, usado numa 1ª
     tentativa, foi descartado só por consistência). */
  --color-ok: #047857;
  --color-warn: #f59e0b;
  --color-danger: #f43f5e;
  --color-info: #4f8ef7;
  /* "5ª cor" sem status/semáforo formal — usada pra categorias auxiliares
     que não são nem ok/warn/danger/info (ex.: "sem SLA cadastrado" em SLA
     & Tempos, "sem atendente" em Em Espera). Extraído de `#a78bfa`
     hardcoded em 2 telas (06/08/2026, auditoria de padrões) — mesmo valor
     de sempre, só virou token pra não ficar solto em `style=""`. */
  --color-roxo: #a78bfa;
  /* Acento do Comparativo (hero/linha de tendência) — cor de IDENTIDADE da
     tela, não de status (mesma lógica do --color-brand não ser status):
     porta do --teal do command-center-vercel. Tom mais escuro no tema claro
     por contraste, mesma diferenciação que o v1 já fazia. */
  --color-accent: #0d9488;
  /* Heatmap (Mapa de Calor) — 5 rodadas no mesmo dia (06/08/2026): base
     própria → `--color-brand`; ajuste de base; semáforo verde→amarelo→
     vermelho (achado: "não me agrada"); e por fim, o Adriano pediu de
     volta o AZUL original ("difícil [de gostar], vamos resgatar os tons
     de azul originais?") — `--color-heat-max` volta a ser `--color-info`
     (idêntico/fixo nos 4 temas). Só a BASE (`--color-heat-min`) continua
     própria do tema Padrão: um azul-ardósia bem escuro (não preto puro,
     não cinza neutro) — fica na MESMA família de matiz do azul do topo
     (sem "enlamear" o meio da escala, problema da 2ª rodada) e ainda
     assim escuro o bastante pra ler como "frio" contra a página clara.
     A escala em si (log, não linear — ver `corCelula()`) continua, essa
     parte não tinha problema, só a cor. */
  --color-heat-min: #1e293b;
  --color-heat-max: var(--color-info);
  /* Texto do botão contra `--color-brand` sólido: branco dá só ~2,9:1 de
     contraste (abaixo do WCAG AA), mas texto escuro — tecnicamente mais
     legível — ficou feio na prática (09/08/2026, o Adriano testou e não
     gostou). Prevalece o visual esperado da marca (branco); ver token em
     uso em `.btn-primary`/`.btn-outline-primary`. */
  --color-brand-contrast: #fff;
  /* Hero por STATUS (BH × Analista — ponta/meio do gradiente A→B→A, ver
     op_bh_analista.php `$corHero`), separado do hero por MARCA acima.
     ÚNICO tema que precisava de ajuste de verdade (Adriano, 09/08/2026,
     confirmado depois de eu ter mexido nos 4 por engano) — meio (B) mais
     ESCURO/saturado que as pontas (A), misturado contra `--color-surface`
     (não "transparent" — mistura num fundo quase branco não daria conta
     de saturar o bastante). Valores subiram 2x na mesma sessão até ficar
     bom (14%/32% → 16%/38%). */
  --color-hero-status-a: 16%;
  --color-hero-status-b: 38%;
  --color-hero-status-base: var(--color-surface);
}

html[data-theme="escuro"] {
  --color-bg: #0a0a0b;
  --color-surface: #18181b;
  --color-border: #2c2c30;
  --color-text: #f4f4f5;
  --color-text-muted: #9a9aa1;
  /* Laranja dessaturado (mesmo matiz ~25°) — 1ª tentativa (saturação
     100%→68%, #da7f3e) foi longe demais, ficou "apagado" (09/08/2026,
     2ª rodada). Meio-termo: 100%→82%, ainda nitidamente menos "neon" que o
     original (#ff7a1a) sem perder vivacidade. Afeta botões, destaque da
     sidebar e qualquer tinta que use --color-brand neste tema — trocar só
     nos botões deixaria a marca inconsistente entre os elementos. */
  --color-brand: #e97420;
  --color-brand-dark: #c35c13;
  --color-brand-soft: rgba(233, 116, 32, .18);
  --color-sidebar-bg: #050506;
  --color-sidebar-text: #9a9aa1;
  --color-sidebar-hover: #1c1c1f;
  --color-sidebar-active: var(--color-brand);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow-md: 0 4px 16px rgba(0, 0, 0, .5);
  --radius: .6rem;
  --color-ok: #10b981;
  --color-warn: #f59e0b;
  --color-danger: #f43f5e;
  --color-info: #4f8ef7;
  --color-roxo: #a78bfa;
  --color-accent: #00d4a8;
  /* Heatmap — base é o próprio `--color-bg` do tema (dark themes já são
     escuros o bastante pra servir de base "fria" sem precisar de token
     próprio), topo é `--color-info` (azul, ORIGINAL — voltou depois de 2
     tentativas alternativas no mesmo dia, ver comentário no tema Padrão
     acima). */
  --color-heat-min: var(--color-bg);
  --color-heat-max: var(--color-info);
  /* Branco tem só ~2,6:1 de contraste contra este laranja (pior tema pra
     isso) — texto escuro resolveria o contraste (~8:1) mas ficou feio na
     prática (09/08/2026, testado e reprovado pelo Adriano). Mantido branco,
     mesma decisão do tema Padrão. */
  --color-brand-contrast: #fff;
  /* Hero por status — fórmula ORIGINAL (nunca reclamada neste tema; a
     inversão A/B + mistura contra surface é exclusiva do tema Padrão, ver
     comentário lá — 09/08/2026, corrigido depois de eu ter mexido nos 4
     temas por engano). */
  --color-hero-status-a: 22%;
  --color-hero-status-b: 6%;
  --color-hero-status-base: transparent;
}

html[data-theme="azul"] {
  --color-bg: #0a1628;
  --color-surface: #0f2036;
  --color-border: #1c3a5e;
  --color-text: #dce7f5;
  --color-text-muted: #7d97b8;
  --color-brand: #3b82f6;
  --color-brand-dark: #2563eb;
  --color-brand-soft: rgba(59, 130, 246, .18);
  --color-sidebar-bg: #060f1d;
  --color-sidebar-text: #7d97b8;
  --color-sidebar-hover: #13233b;
  --color-sidebar-active: #3b82f6;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow-md: 0 4px 16px rgba(0, 0, 0, .5);
  --radius: .6rem;
  --color-ok: #10b981;
  --color-warn: #f59e0b;
  --color-danger: #f43f5e;
  --color-info: #4f8ef7;
  --color-roxo: #a78bfa;
  --color-accent: #00d4a8;
  --color-heat-min: var(--color-bg);
  --color-heat-max: var(--color-info);
  --color-brand-contrast: #fff;
  --color-hero-status-a: 22%;
  --color-hero-status-b: 6%;
  --color-hero-status-base: transparent;
}

html[data-theme="cinza"] {
  --color-bg: #232326;
  --color-surface: #2c2c30;
  --color-border: #3a3a3f;
  --color-text: #e4e4e7;
  --color-text-muted: #9a9aa2;
  --color-brand: #0d9488;
  --color-brand-dark: #0f766e;
  --color-brand-soft: rgba(13, 148, 136, .18);
  --color-sidebar-bg: #1a1a1c;
  --color-sidebar-text: #9a9aa2;
  --color-sidebar-hover: #313136;
  --color-sidebar-active: #0d9488;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow-md: 0 4px 16px rgba(0, 0, 0, .5);
  --radius: .6rem;
  --color-ok: #10b981;
  --color-warn: #f59e0b;
  --color-danger: #f43f5e;
  --color-info: #4f8ef7;
  --color-roxo: #a78bfa;
  --color-accent: #00d4a8;
  --color-heat-min: var(--color-bg);
  --color-heat-max: var(--color-info);
  --color-brand-contrast: #fff;
  --color-hero-status-a: 22%;
  --color-hero-status-b: 6%;
  --color-hero-status-base: transparent;
}

/* Badges/alertas "subtle" do Bootstrap (`bg-*-subtle`/`border-*-subtle`,
   usados em TODO badge arredondado do app — `rounded-pill bg-danger-
   subtle text-danger-emphasis border border-danger-subtle` etc.) vêm
   com fundo/borda fixos do próprio Bootstrap nos temas escuros
   (`--bs-danger-bg-subtle:#2c0b0e` etc.) — mais saturados/"fortes" que o
   resto do app, que usa tons bem mais discretos (`color-mix` a 6-12%
   contra `--color-surface`, ver `.app-bh-det-cell` etc.). Achado do
   Adriano (14/08/2026): "dá pra ler bem isso é fato, mas eles parecem
   ter uma cor muito forte em cima do tema". Sobrescreve só FUNDO/BORDA
   (não o texto — `text-*-emphasis`, que já está bom, legível) usando os
   MESMOS tokens `--color-*`/`color-mix` já usados no resto do app, nos
   3 temas escuros de uma vez (não hardcoded por tema, já reflete a cor
   de marca/semáforo de cada tema automaticamente). Efeito é GLOBAL —
   todo badge/alerta "subtle" do sistema, não só Contratos BH. */
html[data-bs-theme="dark"] {
  --bs-danger-bg-subtle: color-mix(in srgb, var(--color-danger) 12%, var(--color-surface));
  --bs-danger-border-subtle: color-mix(in srgb, var(--color-danger) 30%, var(--color-surface));
  --bs-warning-bg-subtle: color-mix(in srgb, var(--color-warn) 12%, var(--color-surface));
  --bs-warning-border-subtle: color-mix(in srgb, var(--color-warn) 30%, var(--color-surface));
  --bs-success-bg-subtle: color-mix(in srgb, var(--color-ok) 12%, var(--color-surface));
  --bs-success-border-subtle: color-mix(in srgb, var(--color-ok) 30%, var(--color-surface));
  --bs-secondary-bg-subtle: color-mix(in srgb, var(--color-text) 8%, var(--color-surface));
  --bs-secondary-border-subtle: color-mix(in srgb, var(--color-text) 20%, var(--color-surface));
  --bs-info-bg-subtle: color-mix(in srgb, var(--color-info) 12%, var(--color-surface));
  --bs-info-border-subtle: color-mix(in srgb, var(--color-info) 30%, var(--color-surface));
}

/* Densidade escala o rem inteiro do app — todo componente Bootstrap/próprio
   que usa rem/em acompanha automaticamente, sem precisar de ajuste por tela.
   Mesma escala (em px absolutos, não % do padrão do navegador) já validada
   no apontamentos-v2. */
html[data-densidade="pequena"] {
  font-size: 12px;
}

html[data-densidade="media"] {
  font-size: 13px;
}

html[data-densidade="grande"] {
  font-size: 15px;
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
}

/* ---------- Botão primário segue a cor de marca do tema ativo ---------- */
.btn-primary {
  /* Texto do botão: branco cru (padrão do Bootstrap) contra o laranja da
     marca dava só ~2,6-2,9:1 de contraste nos temas Padrão/Escuro — abaixo
     do mínimo de legibilidade (WCAG AA pede 4,5:1). `--color-brand-contrast`
     escolhe por tema (escuro/claro) o que realmente lê bem contra a cor de
     marca daquele tema (09/08/2026, achado do Adriano: "botões ruim de
     ler"). Azul/Cinza mantêm branco — já liam bem. */
  --bs-btn-color: var(--color-brand-contrast);
  --bs-btn-bg: var(--color-brand);
  --bs-btn-border-color: var(--color-brand);
  --bs-btn-hover-color: var(--color-brand-contrast);
  --bs-btn-hover-bg: var(--color-brand-dark);
  --bs-btn-hover-border-color: var(--color-brand-dark);
  --bs-btn-active-color: var(--color-brand-contrast);
  --bs-btn-active-bg: var(--color-brand-dark);
  --bs-btn-active-border-color: var(--color-brand-dark);
  --bs-btn-disabled-color: var(--color-brand-contrast);
  --bs-btn-disabled-bg: var(--color-brand);
  --bs-btn-disabled-border-color: var(--color-brand);
}

/* Idem pro outline-primary (usado nos botões toggle de dia da semana em
   Tarefas Agendadas) — sem isso ele fica no azul cru do Bootstrap, que
   não existe em nenhum tema do app (achado real do Adriano). Preenchido
   (hover/active) tem o MESMO problema de contraste do .btn-primary acima —
   mesmo fix, mesmo motivo. */
.btn-outline-primary {
  --bs-btn-color: var(--color-brand);
  --bs-btn-border-color: var(--color-brand);
  --bs-btn-hover-color: var(--color-brand-contrast);
  --bs-btn-hover-bg: var(--color-brand);
  --bs-btn-hover-border-color: var(--color-brand);
  --bs-btn-active-color: var(--color-brand-contrast);
  --bs-btn-active-bg: var(--color-brand);
  --bs-btn-active-border-color: var(--color-brand);
  --bs-btn-disabled-color: var(--color-brand);
  --bs-btn-disabled-border-color: var(--color-brand);
}

/* Botões-toggle baseados em `.btn-check` (checkbox/radio escondido + label
   estilo `.btn` — usado nos dias da semana de Tarefas Agendadas e nos
   meses de Comparativo Mensal) não reagem ao mouse: o próprio Bootstrap
   tem uma regra (`.btn-check+.btn:hover`) que IGNORA as variáveis de hover
   normais e reseta pro estilo BASE (sem hover) — "nada muda" ao passar o
   mouse (achado real do Adriano, 17/08/2026). Sobrescrito aqui com
   especificidade maior que a do Bootstrap, cobrindo os 2 estados:
   desmarcado ganha o preenchimento normal de hover (mesmas variáveis
   `--bs-btn-hover-*` já configuradas por variante); marcado (já
   preenchido/ativo) ganha um leve brilho, pra não some a pista visual de
   "já selecionado" mas ainda assim reagir ao mouse. */
.btn-check:not(:checked) + .btn:hover {
  color: var(--bs-btn-hover-color);
  background-color: var(--bs-btn-hover-bg);
  border-color: var(--bs-btn-hover-border-color);
}
.btn-check:checked + .btn:hover {
  filter: brightness(1.15);
}

/* ---------- Campos de formulário (o dark-mode "cru" do Bootstrap usa um
   cinza genérico sem relação com a cor do tema ativo). Mesmo padrão do
   apontamentos-v2: fundo = --color-bg (não --color-surface) — o contraste
   vem de SEMPRE colocar o campo dentro de um `.card-panel` (--color-surface),
   nunca solto direto em cima da página (que também é --color-bg — por
   isso "sumia" antes). Ver `.card-panel` mais abaixo. ---------- */
.form-control,
.form-select {
  background-color: var(--color-bg);
  border-color: var(--color-border);
  color: var(--color-text);
}

.form-control:focus,
.form-select:focus {
  background-color: var(--color-bg);
  border-color: var(--color-brand);
  color: var(--color-text);
  box-shadow: 0 0 0 .2rem var(--color-brand-soft);
}

.form-control::placeholder {
  color: var(--color-text-muted);
  opacity: .8;
}

.form-label {
  color: var(--color-text);
}

/* Anel de foco do botão de fechar (X) do modal — o padrão do Bootstrap é um
   azul fixo, sem relação com nenhum dos 4 temas. */
.btn-close:focus {
  box-shadow: 0 0 0 .2rem var(--color-brand-soft);
}

/* Checkbox/switch maior e de tamanho consistente — `1em` do Bootstrap varia
   conforme o font-size do elemento mais próximo (ex.: menor em `<th>` que
   em `<td>`); `rem` fixa relativo à raiz/densidade, sempre igual. */
.form-check-input {
  width: 1.15rem;
  height: 1.15rem;
  background-color: var(--color-bg);
  border-color: var(--color-border);
}

.form-check-input:checked {
  background-color: var(--color-brand);
  border-color: var(--color-brand);
}

.form-check-input:focus {
  border-color: var(--color-brand);
  box-shadow: 0 0 0 .2rem var(--color-brand-soft);
}

/* Alinhamento vertical checkbox/texto — o padrão do Bootstrap usa `float`
   + margem negativa (`margin-left:-1.5em`) pra posicionar o input, uma
   conta que só bate certinho no tamanho DEFAULT do Bootstrap; como
   aumentamos o checkbox pra 1.15rem acima, sobra ~1px de desalinhamento
   vertical entre caixa e texto. `flex` centraliza sempre, não importa o
   tamanho — usado em toda checklist do app (recursos, clientes, filtro
   de coluna etc.), então vale corrigir uma vez só aqui. */
.form-check {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding-left: 0;
}

.form-check .form-check-input {
  float: none;
  margin: 0;
}

/* ---------- Componentes do Bootstrap que têm paleta escura FIXA, sem
   relação nenhuma com o tema ativo — sem isso, qualquer tema escuro que
   não seja um cinza neutro (ex.: Azul) mostra esses componentes com um
   cinza genérico do Bootstrap, destoando do resto da tela. ---------- */

.btn-outline-secondary {
  --bs-btn-color: var(--color-text-muted);
  --bs-btn-bg: color-mix(in srgb, var(--color-text) 6%, var(--color-surface));
  --bs-btn-border-color: var(--color-border);
  --bs-btn-hover-color: var(--color-text);
  --bs-btn-hover-bg: color-mix(in srgb, var(--color-text) 12%, var(--color-surface));
  --bs-btn-hover-border-color: var(--color-border);
  --bs-btn-active-color: var(--color-text);
  --bs-btn-active-bg: color-mix(in srgb, var(--color-text) 16%, var(--color-surface));
  --bs-btn-active-border-color: var(--color-border);
  --bs-btn-disabled-color: var(--color-text-muted);
  --bs-btn-disabled-bg: transparent;
  --bs-btn-disabled-border-color: var(--color-border);
}

.btn-secondary {
  --bs-btn-bg: color-mix(in srgb, var(--color-text) 10%, var(--color-surface));
  --bs-btn-border-color: var(--color-border);
  --bs-btn-color: var(--color-text);
  --bs-btn-hover-bg: color-mix(in srgb, var(--color-text) 16%, var(--color-surface));
  --bs-btn-hover-border-color: var(--color-border);
  --bs-btn-hover-color: var(--color-text);
  --bs-btn-active-bg: color-mix(in srgb, var(--color-text) 20%, var(--color-surface));
  --bs-btn-active-border-color: var(--color-border);
  --bs-btn-active-color: var(--color-text);
}

.dropdown-menu {
  --bs-dropdown-color: var(--color-text);
  --bs-dropdown-bg: var(--color-surface);
  --bs-dropdown-border-color: var(--color-border);
  --bs-dropdown-link-color: var(--color-text);
  --bs-dropdown-link-hover-color: var(--color-text);
  --bs-dropdown-link-hover-bg: color-mix(in srgb, var(--color-text) 8%, var(--color-surface));
  --bs-dropdown-link-active-bg: var(--color-brand);
  --bs-dropdown-header-color: var(--color-text-muted);
  --bs-dropdown-divider-bg: var(--color-border);
  box-shadow: var(--shadow-md);
}

/* Botão do filtro de fila (sidebar) usa `.form-select` só pela aparência
   (mesma seta nativa dos outros campos do filtro — Período/Cliente, que
   são <select> reais) + `.dropdown-toggle` só pelo comportamento (abre um
   dropdown, não navega). Sem isso, sobravam 2 setas — a nativa do
   .form-select E o caret triangular que o Bootstrap desenha em todo
   .dropdown-toggle — pedido do Adriano, 05/08/2026: "ficou sem simetria
   com os outros campos". Esconde só o caret do Bootstrap aqui.
*/
.app-fila-toggle::after {
  display: none;
}

/* Itens do checklist de fila (dentro do dropdown acima) — texto simples,
   sem caixa/borda; só destaca no hover; quando marcado ganha fundo cheio
   (cor da marca) — CADA item com seu próprio raio de borda e separado do
   vizinho pelo `gap` do container (não é 1 bloco contínuo quando vários
   seguidos estão marcados). Pedido do Adriano, 05/08/2026, comparando com
   o print real do vercel ("no vercel era assim e era ótimo"). O checkbox
   real fica funcionalmente presente (semântica de formulário/teclado
   intactas) mas visualmente escondido — o `<label>` é o que o usuário vê
   e clica. Ícone de check ao lado do texto REMOVIDO (10/08/2026, achado
   do Adriano vendo o piloto de filtro horizontal: "o fundo colorido já
   deixa claro o que tá marcado, o check é redundante").
*/
.app-fila-checkbox {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
.app-fila-item {
  padding: .35rem .6rem;
  border-radius: 6px;
  cursor: pointer;
  color: var(--color-text-muted);
  font-size: .8rem;
  /* NÃO leva `white-space:nowrap` aqui — o item é `d-flex` (Bootstrap,
     no HTML), então "sem quebra" sozinho só empurrava a largura do
     dropdown inteiro, criando SCROLL HORIZONTAL num nome mais longo
     (achado do Adriano, 06/08/2026: "não quero scroll horizontal aqui").
     Quem trunca é o `.app-fila-item-texto` abaixo — ele que fica de
     `nowrap` + reticências. */
  min-width: 0;
}
.app-fila-item:hover {
  /* Tingido com `--color-brand` (não mais um cinza neutro) — mesma cor do
     estado MARCADO logo abaixo, só mais fraca (18% vs. sólido) — pedido
     do Adriano, 06/08/2026: "achei muito monótona a cor quando não há
     nada selecionado ainda". */
  background: color-mix(in srgb, var(--color-brand) 18%, var(--color-surface));
  color: var(--color-text);
}
/* Texto do item (fila/analista) — trunca com reticências em vez de
   quebrar linha OU estourar a largura do dropdown (06/08/2026, pedido do
   Adriano: "ellipsis com tooltip... não quero scroll horizontal aqui").
   Nome completo ainda aparece via `title=""` no `<label>` (tooltip nativo
   do navegador ao passar o mouse). */
.app-fila-item-texto {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.app-fila-checkbox:checked + .app-fila-item {
  background: var(--color-brand);
  color: #fff;
  font-weight: 600;
}

.modal-content {
  --bs-modal-bg: var(--color-surface);
  --bs-modal-border-color: var(--color-border);
  --bs-modal-header-border-color: var(--color-border);
  --bs-modal-footer-border-color: var(--color-border);
  color: var(--color-text);
}

/* Bug real achado 17/08/2026 (modal "Editar perfil" > aba Recursos, um
   accordion expandido ficava sem scroll e cortava opções): `.modal-content`
   é `display:flex;flex-direction:column`, e é essa cadeia flex que faz
   `.modal-body` ganhar `overflow-y:auto`/travar na altura da tela quando o
   modal usa `.modal-dialog-scrollable`. Um `<form>` embrulhando `.modal-
   header`/`.modal-body`/`.modal-footer` (padrão usado em vários modais do
   sistema, ex. Perfis/Tarefas/Usuários) quebra essa cadeia — o form vira
   uma caixa normal no meio do layout, então o modal cresce até a altura
   natural do conteúdo em vez de travar e rolar por dentro.
   `display:contents` remove a caixa do form sem remover o form em si
   (o submit continua funcionando), deixando header/body/footer como
   filhos flex diretos de `.modal-content` de novo — mesmo efeito que
   se não houvesse form nenhum no meio. */
.modal-content > form {
  display: contents;
}

/* Máscara padrão do sistema mais escura que o default do Bootstrap (.5) —
   pedido do Adriano: o conteúdo "escondido" atrás do modal ficava visível
   demais, mesmo modal-empilhado.js já subindo o z-index certo. Vale pra
   todo modal do app (não só os empilhados) — mesmo padrão do
   command-center-vercel. */
.modal-backdrop.show {
  opacity: .85;
}

.accordion-item {
  --bs-accordion-bg: var(--color-surface);
  --bs-accordion-border-color: var(--color-border);
  --bs-accordion-btn-bg: var(--color-surface);
  --bs-accordion-active-bg: color-mix(in srgb, var(--color-brand) 12%, var(--color-surface));
  --bs-accordion-active-color: var(--color-text);
  --bs-accordion-btn-color: var(--color-text);
  --bs-accordion-body-color: var(--color-text);
}

.accordion-button::after {
  filter: none;
}

.page-link {
  --bs-pagination-bg: var(--color-surface);
  --bs-pagination-border-color: var(--color-border);
  --bs-pagination-color: var(--color-text);
  --bs-pagination-hover-bg: color-mix(in srgb, var(--color-text) 8%, var(--color-surface));
  --bs-pagination-hover-border-color: var(--color-border);
  --bs-pagination-hover-color: var(--color-text);
  --bs-pagination-active-bg: var(--color-brand);
  --bs-pagination-active-border-color: var(--color-brand);
  --bs-pagination-disabled-bg: var(--color-surface);
  --bs-pagination-disabled-border-color: var(--color-border);
}

.popover {
  --bs-popover-bg: var(--color-surface);
  --bs-popover-border-color: var(--color-border);
  --bs-popover-body-color: var(--color-text);
  --bs-popover-box-shadow: var(--shadow-md);
}

/* Tabela — o cabeçalho (`<thead>`, sem classe própria) e o hover de linha
   usam tokens escuros FIXOS do Bootstrap por padrão (--bs-emphasis-color/
   --bs-tertiary-bg), sem relação com o tema ativo. Mesmo padrão de sempre:
   sobrescreve com as variáveis do tema pra qualquer `<table>` do app. */
.table {
  --bs-table-bg: transparent;
  --bs-table-color: var(--color-text);
  --bs-table-border-color: var(--color-border);
  --bs-table-striped-bg: color-mix(in srgb, var(--color-text) 4%, var(--color-surface));
  --bs-table-hover-bg: color-mix(in srgb, var(--color-text) 6%, var(--color-surface));
  --bs-table-hover-color: var(--color-text);
}

.table > thead {
  --bs-table-color: var(--color-text);
  border-bottom-color: var(--color-border);
}

/* `.table-sm` deixa o padding horizontal apertado de propósito (pensado
   pra tabela com poucas colunas) — no drill-down de Chamados, com 8
   colunas bem cheias de dado, ficava tudo colado (achado do Adriano,
   05/08/2026). Classe própria (não muda `.table-sm` global — outras
   tabelas do app continuam como estavam). Seletor bate a especificidade
   do próprio Bootstrap (`.table > :not(caption) > * > *`), sem precisar
   de `!important`. */
.app-tabela-espacada > :not(caption) > * > * {
  padding-left: .9rem;
  padding-right: .9rem;
}

/* Tabela do modal duplo (`TicketDrill`) — classe PRÓPRIA, não mexe em
   `.app-tabela-espacada` (reaproveitada por ~10 outras telas fora do
   modal duplo, que dependem do layout automático de sempre). Sem
   `table-layout:fixed`, os `<col>` de `colunasPadrao()` (`assets/js/
   ticket-drill.js`) eram só um "chute" — o navegador ainda expandia
   colunas pra caber conteúdo sem quebra (Cliente/Atendente/Serviço com
   nome comprido), forçando scroll lateral mesmo com `.text-truncate`
   nelas (achado do Adriano, 11/08/2026: "da pra diminuir um pouco pra
   prevenir scroll lateral?"). Com `fixed`, as larguras do `<colgroup>`
   passam a valer de verdade e o truncamento com reticências funciona.
   Largura da tabela: voltou a ser 100% (Bootstrap `.table`), SEM
   `width:auto` — tentativa anterior (11/08/2026, 1ª rodada: "vejo espaço
   de sobra na largura das colunas Datas/Tempos") deixava a tabela do
   tamanho EXATO da soma das colunas declaradas, mas isso trocou "sobra
   dentro das células" por "sobra vazia à direita do modal inteiro"
   (2ª achado do Adriano, mesmo dia, com print de `op_chamados.php`: "a
   tabela agora não ocupa 100% da largura do modal"). Resolvido de outro
   jeito: a coluna "Chamado" (`colunasPadrao()`) ficou SEM `largura`
   própria (vira um `<col>` sem `width`) — com `table-layout:fixed` +
   tabela 100%, QUALQUER coluna sem largura declarada absorve sozinha TODA
   a sobra, enquanto as outras (Cliente/Atendente/Fila/Serviço/Datas/
   Tempos/etc, todas COM largura declarada) ficam EXATAS, sem distorcer.
   "Chamado" é a escolha natural pra absorver a sobra: já é a coluna mais
   "elástica" por natureza (nº do ticket + assunto variável), diferente
   de Datas/Tempos que são sempre a MESMA largura de conteúdo goste ou
   não da largura da coluna. */
.app-td-tabela {
  table-layout: fixed;
}

/* Cabeçalho do modal duplo NUNCA quebra linha (11/08/2026, achado do
   Adriano com print: "Atendente" + os ícones de sort/filtro iam pra linha
   de baixo, só nessa coluna) — `table-layout:fixed` faz a LARGURA da
   coluna valer de verdade, mas não impede o TEXTO de quebrar dentro dela;
   colunas mais estreitas (Atendente/Fila) apertam primeiro quando o total
   de colunas cresce (ex.: nova coluna "Modificado"). `nowrap` aqui é a
   defesa de verdade — não depende de nenhuma largura específica dar certo. */
#_tdCabecalho th {
  white-space: nowrap;
}

/* Linha inteira clicável pra abrir edição (Usuários/Clientes/Perfis) — sem
   mais ícone de editar dedicado na tabela; excluir mora dentro do modal. */
.linha-clicavel {
  cursor: pointer;
}

/* ---------- Filtro por coluna: funil ao lado do título (popover), no
   lugar de uma linha de campos sempre visível. ---------- */
.app-filtro-btn {
  color: var(--color-text-muted);
  text-decoration: none;
  vertical-align: middle;
}

.app-filtro-btn:hover {
  color: var(--color-brand);
}

.app-filtro-btn.text-warning:hover {
  color: var(--color-brand-dark) !important;
}

/* ---------- Tela de login: layout split-screen, idéia do apontamentos-v2
   (assets/css/login.css de lá) — painel de marca à esquerda + formulário à
   direita. Adaptado pra usar as variáveis --color-* do tema ativo (lá é
   tudo cor fixa, porque a tela de login deles não tem seletor de tema; aqui
   tem, então o login já nasce respeitando Padrão/Escuro/Azul/Cinza). O
   painel de marca usa --color-sidebar-bg (sempre escuro nos 4 temas, até no
   Padrão) — por isso o texto dele pode ser branco fixo sem checar tema. */
.login-body {
  min-height: 100vh;
  background: var(--color-bg);
}

.login-shell {
  min-height: 100vh;
  display: flex;
}

.login-visual {
  flex: 1.1;
  background: linear-gradient(135deg, var(--color-sidebar-bg) 0%, var(--color-sidebar-hover) 120%);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  padding: 4rem;
  color: #fff;
  position: relative;
  overflow: hidden;
}

.login-visual::after {
  content: '';
  position: absolute;
  width: 480px;
  height: 480px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--color-brand-soft), transparent 70%);
  right: -140px;
  bottom: -140px;
}

.login-visual-icon {
  width: 4rem;
  height: 4rem;
  margin-bottom: 2rem;
}

.login-visual h1 {
  font-size: 2.1rem;
  font-weight: 700;
  max-width: 460px;
  line-height: 1.25;
  position: relative;
}

.login-visual p {
  color: var(--color-sidebar-text);
  max-width: 420px;
  margin-top: 1rem;
  position: relative;
}

.login-form-side {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
}

.login-card {
  width: 100%;
  max-width: 400px;
}

.login-card h2 {
  font-weight: 700;
  margin-bottom: 0.35rem;
  color: var(--color-text);
}

.login-card .subtitle {
  color: var(--color-text-muted);
  margin-bottom: 1.5rem;
}

.login-divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1.25rem 0;
  color: var(--color-text-muted);
  font-size: 0.8rem;
}

.login-divider::before,
.login-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--color-border);
}

.login-footer-note {
  margin-top: 1.75rem;
  font-size: 0.8rem;
  color: var(--color-text-muted);
  text-align: center;
}

@media (max-width: 860px) {
  .login-visual {
    display: none;
  }
}

/* ---------- Shell da aplicação: barra cheia no topo (marca + abas +
   usuário), sidebar contextual abaixo dela — sidebar e conteúdo rolam de
   forma independente, cada um dentro da própria altura disponível. ---------- */
.app-page {
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: hidden;
}

.app-topbar-full {
  flex-shrink: 0;
  display: flex;
  align-items: stretch;
  background: var(--color-sidebar-bg);
  border-bottom: 1px solid var(--color-border);
}

/* No tema Padrão, --color-border é claro (pensado pro conteúdo, que é
   claro) — usado embaixo do topbar (que é escuro, cor do menu) ele vira uma
   linha divisória muito destacada. Um sobretom do próprio fundo do menu fica
   mais discreto e integrado. */
html[data-theme="padrao"] .app-topbar-full {
  border-bottom-color: color-mix(in srgb, var(--color-sidebar-bg) 70%, white 30%);
}

.app-topbar-brand {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0 1.25rem;
  font-weight: 600;
  color: var(--color-sidebar-text);
  white-space: nowrap;
}

.app-topbar-brand-icon {
  width: 1.5rem;
  height: 1.5rem;
}

.app-tabbar-tabs {
  display: flex;
  align-items: stretch;
  gap: 0.25rem;
  padding: 0 0.5rem;
  overflow-x: auto;
  flex: 1 1 auto;
  min-width: 0;
}

/* Sombra na borda direita indicando que há mais conteúdo pra rolar
   horizontalmente — igual big techs fazem em tabelas largas (pedido do
   Adriano, 06/08/2026, tabela de drill-down do `TicketDrill`). Some
   sozinha quando o scroll chega no fim (classe alternada via JS). Funde
   com `--color-surface` (a mesma cor de fundo do modal) em vez de uma
   sombra escura fixa — assim funciona em qualquer tema sem hardcode. */
.app-scroll-x {
  position: relative;
}

.app-scroll-x::after {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 28px;
  background: linear-gradient(to right, transparent, var(--color-surface) 85%);
  opacity: 0;
  transition: opacity 0.15s ease;
  pointer-events: none;
}

.app-scroll-x.app-scroll-x--mais::after {
  opacity: 0.95;
}

/* Mesma ideia, versão vertical — pedido do Adriano (06/08/2026, "Ver
   todos" de Clientes > Top clientes/Módulos): o scroll interno ficava
   discreto demais, sem nenhum sinal visual de "tem mais pra rolar". Some
   sozinha quando o scroll chega no fim (classe alternada via JS, mesmo
   cálculo de `scrollHeight - scrollTop - clientHeight`). */
.app-scroll-y {
  position: relative;
}

.app-scroll-y::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 28px;
  background: linear-gradient(to bottom, transparent, var(--color-surface) 85%);
  opacity: 0;
  transition: opacity 0.15s ease;
  pointer-events: none;
}

.app-scroll-y.app-scroll-y--mais::after {
  opacity: 0.95;
}

/* Abas estilo "underline" (07/08/2026, pedido do Adriano — achou o
   padrão do apontamentos-v2 mais bonito que o Bootstrap padrão/"pill
   com caixa" que o modal de Perfil usava). Global — qualquer
   `.nav-tabs`/`.nav-link` do app (Bootstrap) ganha esse visual, sem
   precisar de classe extra por tela. Mesma receita 1:1 do
   apontamentos-v2 (`assets/css/app.css`), só trocando os nomes de
   variável pelos deste projeto. */
.nav-tabs {
  border-bottom: 1px solid var(--color-border);
  gap: 1.75rem;
}

.nav-tabs .nav-link {
  border: none;
  background: none;
  color: var(--color-text-muted);
  font-weight: 500;
  padding: .1rem .1rem .85rem;
  border-radius: 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}

.nav-tabs .nav-link:hover {
  background: none;
  color: var(--color-text);
  border-bottom-color: var(--color-border);
}

.nav-tabs .nav-link.active {
  color: var(--color-brand);
  border-bottom-color: var(--color-brand);
  background: none;
  font-weight: 600;
}

.nav-tabs .nav-link.disabled {
  color: var(--color-border);
  cursor: not-allowed;
}

/* `.list-group-item` do Bootstrap vem com fundo/borda claros por padrão
   (pensados pra tema claro) — sem override, aparecia uma caixa clara
   "vazando" por trás da lista dentro de painéis escuros (achado do
   Adriano, 07/08/2026, aba "Membros" do modal de Time). Fundo
   `transparent` (a lista já vive dentro de um modal/card-panel que tem
   a cor certa por baixo — mesma classe de bug do "hero terminando em
   transparent" já corrigida antes) + borda/texto usando as variáveis do
   tema.
*/
.list-group-item {
  background: transparent;
  border-color: var(--color-border);
  color: var(--color-text);
}

.app-tab {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0 0.9rem;
  color: var(--color-sidebar-text);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  font-size: 0.95rem;
}

/* Largura fixa pro glyph do ícone — sem isso, o texto do rótulo "pula" de
   leve assim que a webfont dos ícones termina de carregar (o espaço antes
   dela carregar é ligeiramente menor que o glyph real). */
.app-tab i,
.app-topbar-brand i {
  width: 1rem;
  text-align: center;
}

.app-tab:hover {
  color: #fff;
}

.app-tab.active {
  color: var(--color-brand);
  border-bottom-color: var(--color-brand);
}

.app-tabbar-user {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  padding: 0 1rem;
}

.app-user-btn {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.4rem 0.6rem;
  color: var(--color-sidebar-text);
  background: none;
  border: none;
  border-radius: 0.4rem;
}

.app-user-btn:hover,
.app-user-btn:focus,
.app-user-btn.show {
  color: #fff;
  background: var(--color-sidebar-hover);
}

.app-user-btn-label {
  max-width: 10rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.app-shell {
  flex: 1 1 auto;
  display: flex;
  min-height: 0;
}

.app-sidebar {
  width: 16.5rem;
  flex-shrink: 0;
  overflow-y: auto;
  background: var(--color-sidebar-bg);
  border-right: 1px solid var(--color-border);
  padding: 1rem 0;
}

/* Menu lateral recolhível em telas estreitas (19/08/2026) — botão
   `.app-sidebar-toggle` (ao lado do logo) só existe visualmente abaixo
   do breakpoint; ver assets/js/sidebar-responsivo.js. Acima do
   breakpoint a sidebar sempre aparece normal — a forma de "minimizar o
   menu" em qualquer largura (inclusive desktop) é o botão de MODO FOCO
   logo abaixo (`.app-fs-btn`), não este. */
.app-sidebar-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border: none;
  border-radius: var(--radius);
  background: var(--color-sidebar-hover);
  color: var(--color-sidebar-text);
  font-size: 1.1rem;
  cursor: pointer;
}
.app-sidebar-toggle:hover {
  filter: brightness(1.2);
}

.app-sidebar-backdrop {
  display: none;
}

@media (max-width: 992px) {
  .app-sidebar-toggle {
    display: inline-flex;
  }
  .app-shell {
    position: relative;
  }
  .app-sidebar {
    display: none;
  }
  body.app-sidebar-aberta .app-sidebar {
    display: flex;
    flex-direction: column;
    position: absolute;
    inset: 0 auto 0 0;
    z-index: 500;
    box-shadow: 4px 0 16px rgba(0, 0, 0, .35);
  }
  body.app-sidebar-aberta .app-sidebar-backdrop {
    display: block;
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, .5);
    z-index: 499;
  }
}

/* Modo foco / tela cheia (19/08/2026, pedido do Adriano: "mesmo acima
   de 992px, quero como minimizar o menu"). Achado comparando com a
   produção real: lá existe exatamente este recurso — um botão
   flutuante fixo no canto inferior direito, disponível em QUALQUER
   largura de tela (sem media query nenhuma), que esconde topbar+
   sidebar juntos via 1 classe no body (produção usa `.fs-mode`/
   `#fs-btn`, aqui replicado com os nomes/tokens do v2). Diferente do
   `.app-sidebar-toggle` acima (que só existe abaixo de 992px e vira
   uma gaveta sobreposta) — este é global e some com AMBOS de vez,
   reaproveitando o próprio espaço do layout (`.app-shell`/`.app-main`
   são flex, então a sidebar sumindo já faz o conteúdo expandir sozinho,
   sem precisar recalcular margem). Não persiste em localStorage de
   propósito — é sessão de foco pontual (mesma convenção do drawer
   mobile acima), confirmado que a produção também não persiste isso.
   Ver assets/js/foco-total.js pro toggle (clique ou tecla F, Esc sai). */
.app-fs-btn {
  position: fixed;
  bottom: 1.375rem;
  right: 1.375rem;
  z-index: 600;
  width: 2.375rem;
  height: 2.375rem;
  border-radius: 50%;
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  cursor: pointer;
  box-shadow: var(--shadow-md);
  transition: all .2s;
}
.app-fs-btn:hover {
  border-color: var(--color-brand);
  color: var(--color-brand);
  transform: scale(1.08);
}
body.app-fs-mode .app-fs-btn {
  background: var(--color-brand-soft);
  border-color: var(--color-brand);
  color: var(--color-brand);
}

body.app-fs-mode .app-topbar-full,
body.app-fs-mode .app-sidebar,
body.app-fs-mode .app-sidebar-backdrop {
  display: none !important;
}

.app-sidebar-nav {
  display: flex;
  flex-direction: column;
}

.app-sidebar .nav-link {
  padding: 0.5rem 1rem;
  color: var(--color-sidebar-text);
  border-radius: 0;
}

.app-sidebar .nav-link:hover {
  background: var(--color-sidebar-hover);
  color: #fff;
}

.app-sidebar .nav-link.active {
  background: var(--color-sidebar-active);
  color: #fff;
  font-weight: 600;
}

.app-sidebar .nav-link i {
  width: 1.25rem;
  display: inline-block;
}

.app-nav-grupo-rotulo {
  padding: 0.75rem 1rem 0.25rem;
  /* Era `.7rem`/opacidade `.6` — "muito discreto" (achado do Adriano,
     14/08/2026, mesmo problema de fonte pequena já visto em outras
     telas nesta sessão). Subido pra `.78rem`/opacidade `.75` — ainda
     nitidamente menor/mais discreto que um item de menu de verdade
     (mantém a hierarquia visual "rótulo de grupo" < "item clicável"),
     só que legível. */
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--color-sidebar-text);
  opacity: 0.75;
  /* Grupos minimizáveis (06/08/2026, pedido do Adriano — "reparei que no
     Vercel original era assim") — o próprio rótulo é o "manípulo" que
     recolhe/expande o `.app-nav-grupo-corpo` logo abaixo dele (ver
     appToggleGrupoNav(), assets/js/sidebar-grupos.js). */
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  user-select: none;
}

.app-nav-grupo-rotulo:first-child {
  padding-top: 0;
}

/* Linha divisória entre grupos da sidebar — antes de TODO grupo exceto
   o 1º da aba (ver `layout_topo.php`, `$grupoIndex > 0`). Era colorida
   (`--color-sidebar-active` a .35 de opacidade, pedido de 12/08/2026:
   "algo mais chamativo") — o Adriano reconsiderou (14/08/2026: "não
   estou gostando das linhas horizontais coloridas") e voltou pra um
   traço neutro simples, mesma cor de borda usada em qualquer outro
   divisor do app (`--color-border`), sem tingir com a cor de marca. */
.app-nav-grupo-divisor {
  height: 1px;
  margin: .75rem 1rem .5rem;
  background: var(--color-sidebar-hover);
  border-radius: 1px;
}

/* Título fixo da aba na sidebar (19/08/2026) — só usado por
   "Administração"/"Sistema", que saiu do topo e ficou sem nenhum sinal
   de "você está aqui dentro" (as outras abas ainda mostram isso via o
   próprio tab ativo). Mesma "cara" de `.app-tab.active` (cor de marca +
   borda colorida) — pedido do Adriano: "dá pra colorir como se fosse
   um botão do menu superior clicado?" — reusa a MESMA receita em vez
   de inventar um destaque novo. Mais destacado que
   `.app-nav-grupo-rotulo` (rótulo de GRUPO, um nível abaixo) — é o nome
   da ABA inteira. */
.app-sidebar-titulo-aba {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .25rem 1rem 1rem;
  font-size: .95rem;
  font-weight: 700;
  color: var(--color-brand);
  border-bottom: 2px solid var(--color-brand);
  margin-bottom: .5rem;
}

/* Horário de sync ao lado de um <h1> (BH × Analista, Apontamento ×
   Analista) — bem discreto, não pode competir com o título. */
.app-titulo-sync {
  font-size: 0.7rem;
  font-weight: 400;
  color: var(--color-text-muted);
  opacity: 0.75;
}

/* Ícone de saúde de sync (TarefaAgendadaService::resumoSaude) — some no
   fundo por padrão (mesmo espírito discreto do `.app-titulo-sync`); só
   ganha cor quando alguma tarefa prerequisito está atrasada/nunca rodou/
   deu erro. Cor muda, mas NÃO pisca de propósito — "blink" cansa a vista
   numa tela que fica aberta o dia todo e é ruim de acessibilidade
   (09/08/2026, decisão consciente após discutir com o Adriano). Erro
   ganha uma pulsação BEM suave (opacidade, não cor/tamanho) só pra chamar
   atenção sem irritar. */
.app-titulo-sync-icon {
  /* Único indicador de sync na tela (09/08/2026: texto ao lado do título
     foi removido a pedido do Adriano) — precisa de tamanho/opacidade que
     se note mesmo no estado "ok", diferente de quando era só um extra ao
     lado do texto. */
  font-size: 1.4rem;
  color: var(--color-text-muted);
  opacity: .8;
  cursor: help;
  vertical-align: middle;
  /* 1ª tentativa (inline-block + line-height + text-align) ainda "andava"
     um pouco no giro (09/08/2026, 2ª rodada) — causa real: o glyph do
     Bootstrap Icons vem com `vertical-align:-.125em` no próprio `::before`
     (parte do CSS deles), que `line-height`/`text-align` não anula. Flexbox
     centraliza pela caixa de conteúdo de verdade — `vertical-align` não
     tem efeito nenhum dentro de um container flex, então essa particularidade
     do ícone deixa de importar. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.4rem;
  height: 1.4rem;
  transform-origin: center;
  /* Nudge fino pra baixo — mesmo com flexbox centralizando o glyph na
     própria caixa, essa caixa em si ficava um pouco ALTA em relação à
     linha de base do título ao lado (09/08/2026, achado do Adriano). */
  position: relative;
  top: .15rem;
  /* Engrossa o traço do glyph (ícone de fonte, não SVG — não tem
     `stroke-width` de verdade) — só funciona em navegadores baseados em
     Chromium/WebKit, mas não quebra em nenhum outro (propriedade
     desconhecida é ignorada) (09/08/2026, pedido do Adriano: "a linha da
     setinha mais larga"). */
  -webkit-text-stroke: .6px currentColor;
}

/* Gira e pausa (como um "tentando sincronizar..." periódico) em vez de
   piscar ou ter borda/glow — 3ª tentativa de animação pro aviso de
   problema (09/08/2026: borda/glow "ficou feio"). Reaproveita o próprio
   sentido do ícone (`bi-arrow-repeat`, setas de repetição) em vez de
   inventar um efeito genérico. Erro gira mais rápido/com pausa mais curta
   que atrasada/nunca — mesma escada de urgência de sempre. */
/* Giro de ~1s + pausa de 5s (16,67% do ciclo de 6s é a volta, o resto é
   descanso) — intervalo pedido pelo Adriano (09/08/2026, última rodada). */
@keyframes app-titulo-sync-girar {
  0% { transform: rotate(0deg); }
  16.67% { transform: rotate(360deg); }
  100% { transform: rotate(360deg); }
}

.app-titulo-sync-icon--atrasada,
.app-titulo-sync-icon--nunca {
  color: var(--color-warn);
  opacity: 1;
  animation: app-titulo-sync-girar 6s linear infinite;
}

.app-titulo-sync-icon--erro {
  color: var(--color-danger);
  opacity: 1;
  animation: app-titulo-sync-girar 6s linear infinite;
}

/* `--erro` FICA DE FORA de propósito (09/08/2026, o Adriano confirmou
   depois de ver o próprio navegador reduzindo a animação: "quero que
   anime mesmo assim") — falha de sync é urgente o bastante pra valer a
   pena ignorar essa preferência; atrasada/nunca (mais brando) continua
   respeitando. */
@media (prefers-reduced-motion: reduce) {
  .app-titulo-sync-icon--atrasada,
  .app-titulo-sync-icon--nunca {
    animation: none;
  }
}

/* "Filtros" (dentro de `.app-sidebar-filtro`, que já tem seu PRÓPRIO
   padding horizontal pros campos do formulário) NÃO pode somar o padding
   horizontal do `.app-nav-grupo-rotulo` por cima — dobrava o recuo desse
   título em relação aos outros (Overview/Análises/...), que são filhos
   diretos da `nav` sem nenhum wrapper com padding próprio (achado do
   Adriano, 06/08/2026: "esse título não tem o mesmo padrão dos demais").
   Zera só o horizontal aqui — o vertical continua igual aos outros. */
.app-sidebar-filtro .app-nav-grupo-rotulo {
  padding-left: 0;
  padding-right: 0;
}

.app-nav-grupo-chevron {
  font-size: .65rem;
  transition: transform .15s ease;
  flex-shrink: 0;
  /* Box fixo centralizado — sem isso a rotação (linha abaixo) girava o
     glifo em torno do próprio canto, deslocando ele visualmente e
     "roubando" espaço do lado do título (achado do Adriano, 14/08/2026:
     "quando minimizado... falta um pouco de espaço... tá sem simetria"). */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1rem;
}

.app-nav-grupo-rotulo.recolhido .app-nav-grupo-chevron {
  transform: rotate(-90deg);
}

.app-nav-grupo-corpo.recolhido {
  display: none;
}

/* Fica no TOPO da sidebar agora (antes do menu, não depois) — a borda de
   separação virou de baixo, não mais de cima. */
.app-sidebar-filtro {
  margin-bottom: 0.75rem;
  padding: 0.75rem 1rem 1rem;
  border-bottom: 1px solid var(--color-border);
}

/* Filtros em barra HORIZONTAL, no topo do conteúdo (10/08/2026, piloto em
   op_chamados.php — protótipo aprovado pelo Adriano) — alternativa à
   sidebar acima pras telas que migrarem. Um `.card-panel` comum (mesmo
   fundo/borda de qualquer outro painel do conteúdo) com os campos em
   linha; cada campo é uma coluna estreita (label em cima, controle
   embaixo), reaproveitando os MESMOS componentes de dropdown da sidebar
   (`.app-fila-toggle`/`.app-fila-dropdown-menu`/`.app-fila-item` — nenhum
   deles é exclusivo da sidebar). Sem contador "N chamados"/chips de
   filtro ativo aqui, de propósito — pedido do Adriano vendo o protótipo:
   o próprio rótulo do dropdown já mostra o que está marcado, repetir
   embaixo em chips só consumia espaço à toa. */
.app-topo-filtros {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 1rem;
  margin-bottom: 1.1rem;
}

.app-topo-filtro-campo {
  display: flex;
  flex-direction: column;
  gap: .3rem;
  /* Largura padrão pedida pelo Adriano (10/08/2026), ~175px — os
     dropdowns de Fila/Cliente/Atendente (`.app-fila-toggle`, que herda
     `width:100%` de `.form-select`) ficam com essa largura mínima; o
     Período tem largura própria no `<select>` (mesmo valor, ver
     op_chamados.php) porque o campo dele pode crescer mais que isso
     quando "Período personalizado" mostra De/Até ao lado. */
  min-width: 175px;
}

.app-topo-filtro-campo .form-label {
  margin-bottom: 0;
}

/* Label/legenda do filtro usava `.form-label`/`.text-muted` GERAIS, cuja
 * cor é pensada pro conteúdo principal (fundo claro no tema "padrao") —
 * mas a sidebar é SEMPRE escura, nos 4 temas (`--color-sidebar-bg`), então
 * no tema "padrao" o texto saía escuro sobre fundo escuro, quase ilegível
 * (achado do Adriano, 05/08/2026). Usa a MESMA cor que o resto do menu já
 * usa pra texto sobre a sidebar (`--color-sidebar-text`, já tunada por
 * tema pra sempre contrastar com `--color-sidebar-bg`). */
.app-sidebar-filtro .form-label {
  color: var(--color-sidebar-text);
}

/* Destaque (borda pulsando) em QUALQUER filtro global que a tela ATUAL
   exija preenchido de um jeito específico — pedido original do Adriano
   (06/08/2026, Cliente/Recorrência: exige 1 cliente específico, não
   "Todos"), estendido pra Período (12/08/2026, Apontamento × Analista:
   exige um mês específico, não "Todos os meses"/"Personalizado") — por
   isso o nome da classe é genérico (`app-campo-pulsar`, ANTES chamava
   `app-sidebar-cliente-pulsar`, renomeado nesse 2º uso pra não sugerir
   que é exclusivo de Cliente). Sinaliza sem mexer na opção em si nem no
   valor selecionado (ver includes/layout_topo.php, `$exigeClienteEscolhido`
   / `$exigePeriodoEscolhido`). Some sozinho assim que o filtro exigido é
   escolhido — a classe nem é aplicada nesse caso. */
@keyframes app-pulsar-borda {
  0%, 100% { border-color: var(--color-border); box-shadow: none; }
  50% { border-color: var(--color-warn); box-shadow: 0 0 0 4px rgba(245, 158, 11, .45); }
}

.app-campo-pulsar {
  /* `!important` no border-width — no tema "Padrão" o campo já tem um
     contorno claro contra o fundo escuro da sidebar, um anel fino de 1px
     ficava discreto demais (achado do Adriano); 2px + glow mais forte
     resolve nos 4 temas (--color-warn é fixo entre eles, não varia com a
     marca). */
  border-width: 2px !important;
  animation: app-pulsar-borda 1.4s ease-in-out infinite;
}

/* Variante SÓ com glow (sem tocar em `border-color`/`border-width`) —
   Contratos SSG (12/08/2026, achado do Adriano ao reaproveitar
   `.app-campo-pulsar` pra "olha aqui" num card de detalhe: "a borda que
   pisca sobrescreve a borda de cor do topo do card [status do contrato],
   dá pra manter?"). `.app-campo-pulsar` original anima TODAS as bordas
   (pensado pra campo de formulário sem cor própria); aqui o card já tem
   `border-top` colorido por status (vermelho/amarelo/verde) que não pode
   sumir — só o `box-shadow` pulsa, a borda em si fica intocada. */
@keyframes app-pulsar-glow {
  0%, 100% { box-shadow: var(--shadow-sm); }
  50% { box-shadow: 0 0 0 4px rgba(245, 158, 11, .45); }
}

.app-campo-pulsar-glow {
  animation: app-pulsar-glow 1.4s ease-in-out infinite;
}

/* Variante SÓ embaixo (14/08/2026, "Conta selecionada" da Carteira —
   achado do Adriano: ".app-campo-pulsar-glow" pulsando nos 4 lados do
   título ficava "grande" demais pra uma linha inteira; a linha já tem
   `border-bottom` (herdado de `.app-secao-colapsavel`), então pulsa só
   ESSA borda + uma sombra ancorada embaixo (offset Y positivo, sem
   espalhar pros lados/topo como o anel do `.app-campo-pulsar-glow`). */
@keyframes app-pulsar-borda-baixo {
  /* `inset` (14/08/2026, achado do Adriano com print: a sombra sem
     `inset` espalhava pros LADOS também, mesmo só com offset em Y —
     blur de `box-shadow` cresce em todas as direções a partir da borda,
     não só pra baixo). `inset` desenha a sombra PRA DENTRO da própria
     caixa — fica contida na largura da linha, sem vazar. */
  0%, 100% { border-bottom-color: var(--color-border); box-shadow: none; }
  50% { border-bottom-color: var(--color-warn); box-shadow: inset 0 -6px 6px -4px rgba(245, 158, 11, .55); }
}

.app-campo-pulsar-borda-baixo {
  border-bottom-width: 2px;
  animation: app-pulsar-borda-baixo 1.4s ease-in-out infinite;
}

/* Aviso próprio (06/08/2026, Recorrência: "esse tom de amarelo do alerta
   não está bom") — o `.alert-warning` cru do Bootstrap usa a paleta
   default dele (amarelo pastel/texto oliva fixos), sem nenhuma ligação
   com os tokens do app; destoava do resto da tela. Mesma fórmula já usada
   em badges/bordas de "atenção" no app inteiro (fundo = tinta suave de
   --color-warn, texto/ícone = --color-warn sólido) — funciona nos 4 temas
   sem hardcode de claro/escuro. */
.app-alerta-aviso {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .85rem 1.1rem;
  border-radius: var(--radius);
  background: rgba(245, 158, 11, .12);
  border: 1px solid rgba(245, 158, 11, .35);
  color: var(--color-text);
}

.app-alerta-aviso i {
  color: var(--color-warn);
  font-size: 1.15rem;
  flex-shrink: 0;
}

.app-sidebar-filtro .text-muted {
  color: var(--color-sidebar-text) !important;
  opacity: .65;
}

.app-main {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow: hidden;
}

.app-content {
  padding: 1.5rem;
  flex: 1 1 auto;
  overflow-y: auto;
}

/* ---------- Preferências do usuário (tema/densidade) ---------- */
.card-panel {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  padding: 1.5rem;
}

/* Variante com menos padding vertical — nasceu pontual (Adriano,
   06/08/2026, nos 3 cards de "Saúde do SLA OTRS") e depois virou o
   padrão COMPARTILHADO pra qualquer painel que precise ganhar espaço
   vertical, incluindo os HEROES de todas as telas (mesmo pedido,
   06/08/2026: "esse padding dos heroes pode ser uma config global
   também... assim evitamos fazer estilo diferente entre as telas") —
   por isso é 1 classe só, reusada, não um valor novo por tela. NÃO
   mudei o `.card-panel` base (padding:1.5rem) — ele ainda é o padrão
   pra card comum; esta classe é o "modo compacto" que quem quiser
   aplica por cima, dos 2 lados (heroes E cards de estatística única). */
.card-panel-compacto {
  padding-top: .9rem;
  padding-bottom: .9rem;
}

/* Mini-painel da "Visão do cliente" — borda-topo colorida "flutuando" no
   fundo do card-pai, SEM `card-panel` (26/08/2026, pedido do Adriano:
   "não gosto de box dentro de box com mesma cor de fundo", item 175/177)
   — usado tanto nas faixas clicáveis de "Previsão de conclusão" quanto
   no "88%" de "Cumprimento da previsão" (item 178, "quero transformar
   num painel também, pra ter o mesmo estilo do painel ao lado"). Classe
   BASE genérica (sem hover/cursor — isso é só de quem for clicável, ver
   `.rc-faixa-clicavel` abaixo) pra não duplicar
   border-radius/padding/transition entre os 2 usos. */
.rc-painel-mini {
  border-radius: .5rem;
  padding: .35rem .5rem .6rem;
  transition: background-color .15s ease;
}
/* Extra SÓ pra quem é clicável (26/08/2026, pedido do Adriano: "da pra
   fazer um background mudando de cor pra ficar mais explícito que o
   painel é clicável"). Tingido NEUTRO de propósito (não a cor de cada
   faixa — teria que reimplementar por variável CSS dinâmica por
   elemento, sem ganho real: a borda-topo já entrega a cor, o hover só
   precisa confirmar "isso aqui reage ao clique"). `color-mix` com
   `--color-text` (não um valor fixo em rgba) pra funcionar certo nos 2
   temas sem duplicar regra — texto claro no escuro clareia, texto
   escuro no claro escurece. */
.rc-faixa-clicavel:hover {
  background: color-mix(in srgb, var(--color-text) 7%, transparent);
}

/* Hero com STATUS (ok/warning/critical) — pedido do Adriano (09/08/2026):
   "quando eu mudar o hero de UMA página, isso já reflete em TODA página
   com hero" — antes disso, a borda de status do BH × Analista estava
   hard-coded só naquele arquivo; qualquer ajuste (cor, espessura) exigia
   editar módulo por módulo. Agora é 1 classe base (`.app-hero`, o mesmo
   fundo neutro --color-surface↔--color-bg que o Adriano pediu) + 1
   modificador por status — qualquer tela que precisar de um hero com
   semáforo usa isso, sem inventar CSS nova. */
.app-hero {
  background: linear-gradient(135deg, var(--color-surface), var(--color-bg), var(--color-surface));
}

/* Mesmo gradiente no box de filtro (`.app-topo-filtros`) logo ACIMA do
   Hero (11/08/2026, pedido do Adriano) — o Hero já sinaliza status pela
   BORDA lateral colorida + cor dos números/texto; o gradiente ali é só
   estético, não carrega significado sozinho. Faz mais sentido repetir o
   MESMO acabamento no filtro do que ele ficar plano encostado num Hero
   com gradiente — os 2 boxes que abrem a tela ganham o mesmo tratamento.
   Precisa vir DEPOIS de `.card-panel` no arquivo (mesma especificidade
   de classe única — `.app-topo-filtros` sozinha, lá em cima, perdia pro
   `background` sólido do `.card-panel`, que vem depois no cascade). */
.app-topo-filtros {
  background: linear-gradient(135deg, var(--color-surface), var(--color-bg), var(--color-surface));
}

.app-hero-status--ok {
  border-left: 4px solid var(--color-ok);
}

.app-hero-status--warning {
  border-left: 4px solid var(--color-warn);
}

.app-hero-status--critical {
  border-left: 4px solid var(--color-danger);
}

/* 4º nível — telas como Chamados/Atendentes têm 3 faixas onde a "melhor"
   não é necessariamente "tudo ok" (ex.: taxa de conclusão razoável, sem
   nada crítico, mas sem ser um "ok" pleno) — usa --color-info (azul),
   igual ao "Saúde Operacional" do Executivo (09/08/2026, varredura de
   todos os heroes do sistema). */
.app-hero-status--info {
  border-left: 4px solid var(--color-info);
}

.theme-swatch {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .55rem;
  cursor: pointer;
}

.theme-swatch-color {
  width: 3rem;
  height: 3rem;
  border-radius: .65rem;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .08);
  outline: 2px solid transparent;
  outline-offset: 3px;
  transition: outline-color .15s ease, transform .15s ease;
  color: #fff;
  font-size: 1.1rem;
}

.theme-swatch:hover .theme-swatch-color {
  transform: translateY(-1px);
}

.theme-swatch.active .theme-swatch-color {
  outline-color: var(--color-brand);
}

.theme-swatch-color i {
  opacity: 0;
  transition: opacity .15s ease;
}

.theme-swatch.active .theme-swatch-color i {
  opacity: 1;
}

.theme-swatch span.label {
  font-size: .85rem;
  font-weight: 500;
  color: var(--color-text-muted);
}

.theme-swatch.active span.label {
  color: var(--color-text);
  font-weight: 600;
}

.density-option {
  border: 2px solid var(--color-border);
  border-radius: .55rem;
  padding: 1rem;
  text-align: center;
  cursor: pointer;
  transition: border-color .15s ease;
}

.density-option.active {
  border-color: var(--color-brand);
  background: var(--color-brand-soft);
}

.density-option .bi {
  font-size: 1.4rem;
  color: var(--color-text-muted);
  margin-bottom: .4rem;
  display: block;
}

.density-option.active .bi {
  color: var(--color-brand);
}

/* ---------- Flatpickr — a lib só tem tema claro de fábrica; sem isso,
   o calendário abre com fundo branco fixo em qualquer tema escuro. ---------- */
.flatpickr-calendar {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-md);
}

.flatpickr-calendar.arrowTop:before,
.flatpickr-calendar.arrowTop:after {
  display: none;
}

.flatpickr-months .flatpickr-month,
.flatpickr-current-month,
.flatpickr-current-month input.cur-year {
  color: var(--color-text);
}

.flatpickr-months .flatpickr-prev-month,
.flatpickr-months .flatpickr-next-month {
  color: var(--color-text-muted);
  fill: var(--color-text-muted);
}

.flatpickr-months .flatpickr-prev-month:hover,
.flatpickr-months .flatpickr-next-month:hover {
  color: var(--color-brand);
}

.flatpickr-months .flatpickr-prev-month svg,
.flatpickr-months .flatpickr-next-month svg {
  fill: currentColor;
}

/* O CSS de fábrica do Flatpickr tem uma regra própria pro hover
   (`:hover svg { fill: #f64747 }`, vermelho fixo) com a MESMA especificidade
   da nossa acima — sem repetir o `:hover` aqui, essa regra do Flatpickr
   sempre vence por vir depois no arquivo dele. */
.flatpickr-months .flatpickr-prev-month:hover svg,
.flatpickr-months .flatpickr-next-month:hover svg {
  fill: var(--color-brand);
}

.flatpickr-weekdays {
  background: var(--color-surface);
}

span.flatpickr-weekday {
  background: var(--color-surface);
  color: var(--color-text-muted);
}

.flatpickr-day {
  color: var(--color-text);
}

.flatpickr-day.flatpickr-disabled,
.flatpickr-day.flatpickr-disabled:hover,
.flatpickr-day.prevMonthDay,
.flatpickr-day.nextMonthDay {
  color: var(--color-text-muted);
  opacity: .4;
}

.flatpickr-day:hover {
  background: color-mix(in srgb, var(--color-text) 10%, var(--color-surface));
  border-color: transparent;
}

.flatpickr-day.today {
  border-color: var(--color-brand);
}

.flatpickr-day.selected,
.flatpickr-day.selected:hover {
  background: var(--color-brand);
  border-color: var(--color-brand);
  color: #fff;
}

/* ---------- Barra de rolagem (Firefox via `scrollbar-*`, Chrome/Edge/Safari
   via `::-webkit-scrollbar`) — padrão pra ferramenta inteira, não só o
   sidebar; sem isso a barra fica cinza/clara do SO, destoando de qualquer
   tema escuro. ---------- */
* {
  scrollbar-color: var(--color-border) var(--color-surface);
  scrollbar-width: thin;
}

::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

::-webkit-scrollbar-track {
  background: var(--color-surface);
}

::-webkit-scrollbar-thumb {
  background: var(--color-border);
  border-radius: 6px;
}

::-webkit-scrollbar-thumb:hover {
  background: var(--color-text-muted);
}

/* O sidebar tem fundo próprio (escuro em qualquer tema), então a barra usa
   os tons dele — e fica bem mais fina/discreta que a do resto do app,
   "scroll de menu", não uma barra de rolagem de conteúdo comum. */
.app-sidebar {
  scrollbar-color: var(--color-sidebar-hover) transparent;
  scrollbar-width: thin;
}

/* Fino, mas VISÍVEL (06/08/2026, 2ª rodada — achado do Adriano: "os
   scrolls do menu lateral precisam de revisão... o scroll do multiselect
   tá até transparente"). 1ª tentativa usava `--color-sidebar-hover`
   (tom quase igual ao próprio fundo da sidebar — sumia). Trocado pra
   `--color-sidebar-text` (a cor de TEXTO da sidebar, sempre legível
   contra `--color-sidebar-bg` em qualquer tema, por definição), com
   opacidade reduzida só pra não competir com o texto de verdade — e
   largura subiu de 2px pra 4px, ainda bem mais fino que o padrão global
   (10px) mas dá pra ver/pegar com o mouse. */
.app-sidebar::-webkit-scrollbar {
  width: 4px;
}

.app-sidebar::-webkit-scrollbar-button {
  display: none;
  width: 0;
  height: 0;
}

.app-sidebar::-webkit-scrollbar-track {
  background: transparent;
}

.app-sidebar::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--color-sidebar-text) 45%, transparent);
  border-radius: 2px;
}

.app-sidebar::-webkit-scrollbar-thumb:hover {
  background: var(--color-sidebar-active);
}

/* Scroll fino nos dropdowns de Fila/Atendente/Cliente — 4ª rodada
   (07/08/2026, achado do Adriano: "estão com fundo transparente" — o
   print mostrava um trilho meio claro/inconsistente atrás do thumb).
   Causa provável: `background:transparent` no TRILHO deixa o navegador
   decidir o que aparece por trás — mesma categoria de bug já corrigida
   hoje à noite no gradiente dos heroes ("termina em transparent, revela
   o que tiver por trás, nem sempre o esperado"). Trocado pra um trilho
   SÓLIDO (`--color-surface`, a mesma cor de fundo do próprio dropdown —
   visualmente "some" dentro do card sem depender de transparência) +
   thumb `--color-brand` sólido (sempre saturado/visível). Largura
   voltou pra 4px — "bem fino" (pedido explícito), já que o thumb sólido
   não depende mais de largura extra pra ficar visível. */
/* 5ª rodada (07/08/2026): Adriano pediu discreto, não destaque — o
   `--color-brand` sólido chamava mais atenção que o conteúdo do dropdown.
   Thumb agora é um sobretom da própria superfície (`--color-surface`
   misturado com `--color-text`), não mais a cor de marca. Track continua
   sólida (não `transparent` — era o bug real das rodadas 1-3, ver
   histórico). Largura também caiu de 4px pra 3px (mais fina). */
.app-fila-dropdown-menu::-webkit-scrollbar {
  width: 3px;
}

.app-fila-dropdown-menu::-webkit-scrollbar-button {
  display: none;
  width: 0;
  height: 0;
}

.app-fila-dropdown-menu::-webkit-scrollbar-track {
  background: var(--color-surface);
}

.app-fila-dropdown-menu::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--color-text) 25%, var(--color-surface));
  border-radius: 2px;
}

.app-fila-dropdown-menu::-webkit-scrollbar-thumb:hover {
  background: color-mix(in srgb, var(--color-text) 40%, var(--color-surface));
}

.app-fila-dropdown-menu {
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--color-text) 25%, var(--color-surface)) var(--color-surface);
}

/* ---------- Paginação (início–fim de total + navegação + tamanho) ---------- */
/* `flex-end` (11/08/2026, pedido do Adriano com print do modal duplo:
   "os números da paginação [`.st-pagination-info`, ex.: '1–10 de 13572']
   dá pra ficar ao lado dos botões, no canto direito? acho melhor ficar
   junto") — antes era `space-between`, que só faz diferença quando
   `.st-pagination` ocupa a largura TOTAL do container (caso do modal
   duplo, onde fica dentro do `.modal-body` sem nenhum wrapper flex em
   volta — empurrava a info pro canto esquerdo isolada dos botões). Na
   outra tela que reusa esta classe (`otrs_chamados.php`), `.st-pagination`
   já vive dentro de um flex `justify-content-between` PRÓPRIO (que separa
   a contagem "N chamado(s)" dela) — ali a div fica com largura só do seu
   próprio conteúdo (sem sobra pra redistribuir), então esta troca não
   muda nada visualmente lá. */
.st-pagination {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
}

/* Modificador (12/08/2026, pedido do Adriano) — volta o quantitativo
   ("Exibindo X–Y de Z") pro canto ESQUERDO, separado dos botões — o
   OPOSTO do `.st-pagination` base acima. Usado por `ListagemService::
   paginacaoHtml()` (as ~14 telas de administração/listagem: Usuários,
   Clientes, Auditoria etc.) E pelo modal duplo (TicketDrill,
   `#_tdPaginacao`) — mesmo padrão nos 2 lugares, pedido explícito do
   Adriano ("temos que ter padrão no sistema"), revertendo a preferência
   original dele só pro modal (item 230, "acho melhor ficar junto").
   `flex: 1` — em ambos os casos esta div é o ÚNICO filho "de peso" da
   sua linha (nas listagens, o rótulo "N usuário(s)" que ficava do lado
   foi removido de propósito no mesmo pedido — virou redundante depois do
   "Exibindo X–Y de Z"; no modal ela já era sozinha no `.modal-body`) —
   sem crescer pra ocupar a largura toda da linha, `justify-content:
   space-between` não teria NENHUMA folga pra separar quantitativo de
   botões. */
.st-pagination--separado {
  justify-content: space-between;
  flex: 1;
}

.st-pagination-info {
  color: var(--color-text-muted);
  font-size: .875rem;
  white-space: nowrap;
}

.st-pagination-nav {
  display: flex;
  align-items: center;
  gap: .35rem;
}

.st-pagination-page {
  font-size: .875rem;
  color: var(--color-text);
  padding: 0 .5rem;
  white-space: nowrap;
}

/* `.st-pagination` nunca teve margem própria — cada chamador cuidava do
   espaçamento (`ListagemService::paginacaoHtml()` sempre veio dentro de um
   wrapper com `mt-*` no PHP). `TabelaCliente` injeta a paginação sozinha,
   sem nenhum wrapper pra dar essa margem (26/08/2026, achado do Adriano na
   tabela "Detalhamento por chamado" — mesma falta de espaço já existia,
   sem ninguém ter reparado, nos 2 usos ainda em `ListagemService::
   paginacaoHtml()` sem wrapper próprio, `_rc_bh_bloco.php`). Seletor de
   irmão (não a classe base) — só afeta quando a paginação vem
   IMEDIATAMENTE depois de uma tabela, sem tocar no uso dentro do modal
   duplo (TicketDrill), que tem contexto/espaçamento próprio. */
.table-responsive + .st-pagination {
  margin-top: 1rem;
}

.st-page-size {
  width: auto;
  margin-left: .5rem;
}

.app-pref-chave {
  font-family: 'SFMono-Regular', Consolas, monospace;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .02em;
  color: var(--color-text-muted);
}

/* ---------- Cards de estatística com barra de status (borda esquerda
   colorida) — mesmo componente visual do v1 (`.tri-thermo*` no index.html
   dele), portado pros 4 temas daqui (o v1 só tem tema escuro fixo). Reusável
   em qualquer tela que precise de "número grande + rótulo + semáforo"
   (Triagem hoje, outros dashboards depois). ---------- */
.app-stat-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: .625rem;
  margin-bottom: 1rem;
}

@media (max-width: 720px) {
  .app-stat-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

.app-stat-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: .75rem;
  padding: .8rem 1rem;
  position: relative;
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}

.app-stat-card::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: var(--color-text-muted);
}

.app-stat-card.ok::before { background: var(--color-ok); }
.app-stat-card.warn::before { background: var(--color-warn); }
.app-stat-card.danger::before { background: var(--color-danger); }
.app-stat-card.info::before { background: var(--color-info); }

.app-stat-num {
  font-size: 1.6rem;
  font-weight: 800;
  color: var(--color-text);
  line-height: 1;
}

.app-stat-card.warn .app-stat-num { color: var(--color-warn); }
.app-stat-card.danger .app-stat-num { color: var(--color-danger); }
.app-stat-card.info .app-stat-num { color: var(--color-info); }

.app-stat-lbl {
  font-size: .72rem;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: .05em;
  margin-top: .4rem;
  font-weight: 600;
}

/* ---------- Padrão de tamanho de fonte da Triagem (daqui até o fim dos
   `.app-tri-*`/`.app-ticket-*`): mínimo .85rem pra qualquer texto lido como
   informação real (badge, contador, %, label de botão) — levemente abaixo
   do menu superior (`.app-tab`, .95rem), nunca menor. Antes cada badge
   tinha seu próprio tamanho "ad-hoc" (.64 a .8rem), foi ficando difícil de
   ler com o uso real (achado do Adriano, várias rodadas de print
   comparando). Só elementos puramente decorativos (ícone dentro de
   badge, via `em` relativo) ficam de fora dessa regra. ---------- */

/* ---------- "Carga dos times" — porta fiel do `.tri-carga*` do v1
   (chip compacto em linha: nome + nº sob controle + botão "cobrar"),
   substituindo o card multi-linha genérico de antes (achado real do
   Adriano comparando print: "estão bem diferentes do projeto original").
   ---------- */
.app-tri-carga {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: .75rem;
  padding: .8rem 1rem;
  margin-bottom: 1.5rem;
}

.app-tri-carga-hd {
  font-size: .85rem;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: .06em;
  font-weight: 700;
  margin-bottom: .6rem;
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
}

.app-tri-carga-hd-sub {
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
}

.app-tri-carga-chips {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
}

.app-tri-carga-chip {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .45rem .6rem;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: .55rem;
  font-size: .88rem;
  font-weight: 600;
  color: var(--color-text);
}

.app-tri-carga-chip.danger {
  border-color: color-mix(in srgb, var(--color-danger) 40%, transparent);
  background: color-mix(in srgb, var(--color-danger) 8%, var(--color-bg));
}

.app-tri-carga-chip.warn {
  border-color: color-mix(in srgb, var(--color-warn) 35%, transparent);
  background: color-mix(in srgb, var(--color-warn) 7%, var(--color-bg));
}

.app-tri-carga-chip-n {
  font-family: 'SFMono-Regular', Consolas, monospace;
  font-size: .88rem;
  font-weight: 700;
}

.app-tri-carga-chip.danger .app-tri-carga-chip-n { color: var(--color-danger); }
.app-tri-carga-chip.warn .app-tri-carga-chip-n { color: var(--color-warn); }

.app-tri-carga-chip-cobrar {
  padding: .15rem .55rem;
  background: transparent;
  border: 1px solid var(--color-border);
  border-radius: .4rem;
  font-size: .85rem;
  font-weight: 700;
  color: var(--color-text-muted);
  cursor: pointer;
  font-family: inherit;
  transition: all .15s ease;
}

.app-tri-carga-chip-cobrar:hover {
  color: var(--color-brand);
  border-color: var(--color-brand);
}

/* ---------- Modal "Cobrança" — porta de `.tri-pick-overlay`/`.tri-cobr-text`
   do v1: mostra a mensagem antes de copiar, nunca copia às cegas. ---------- */
.app-tri-cobr-overlay {
  position: fixed;
  inset: 0;
  z-index: 1200;
  background: rgba(8, 11, 16, .7);
  backdrop-filter: blur(6px);
  display: none;
  align-items: center;
  justify-content: center;
}

.app-tri-cobr-overlay.on {
  display: flex;
}

.app-tri-cobr-modal {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: .9rem;
  width: 860px;
  max-width: 92vw;
  max-height: 85vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.app-tri-cobr-hd {
  padding: 1.1rem 1.35rem;
  border-bottom: 1px solid var(--color-border);
}

.app-tri-cobr-title {
  font-size: .95rem;
  font-weight: 700;
  color: var(--color-text);
}

.app-tri-cobr-sub {
  font-size: .85rem;
  color: var(--color-text-muted);
  margin-top: .25rem;
}

.app-tri-cobr-body {
  padding: 1rem 1.1rem;
  overflow-y: auto;
  flex: 1;
}

.app-tri-cobr-text {
  white-space: pre-wrap;
  word-break: break-word;
  font-family: 'SFMono-Regular', Consolas, monospace;
  font-size: .85rem;
  line-height: 1.55;
  color: var(--color-text);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: .5rem;
  padding: .9rem 1rem;
  margin: 0;
}

.app-tri-cobr-foot {
  padding: .8rem 1.1rem;
  border-top: 1px solid var(--color-border);
  display: flex;
  gap: .5rem;
  justify-content: flex-end;
}

.app-tri-cobr-btn {
  padding: .45rem .9rem;
  border-radius: .5rem;
  font-size: .85rem;
  font-weight: 600;
  cursor: pointer;
  border: 1px solid var(--color-border);
  background: var(--color-bg);
  color: var(--color-text-muted);
}

.app-tri-cobr-btn.primary {
  border-color: var(--color-brand);
  color: var(--color-brand);
  font-weight: 700;
}

/* ---------- Card individual de ticket (fila de triagem, e reusável em
   qualquer tela futura que precise listar tickets em "boxes" em vez de
   tabela) — porta fiel do `.tri-card*` REAL do v1 (não o `.sq-card`
   genérico usado noutras telas — são componentes diferentes, achado só
   depois de comparar print a print com o Adriano). Sem borda de acento
   por padrão — só fica vermelha quando "parado" (>=60min ou SLA vencido),
   igual o original. ---------- */
.app-ticket-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: .75rem;
}

/* Empilhado (1 coluna, 100% da largura) — usado na Fila de Triagem, pedido
   do Adriano pra bater com o layout do v1 (lá é assim nessa tela específica,
   embora o mesmo `.tri-card` também sirva de base pra grid multi-coluna
   noutras telas). */
.app-ticket-cards--empilhado {
  grid-template-columns: 1fr;
}

.app-ticket-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: .75rem;
  padding: 1.1rem 1.25rem;
  cursor: pointer;
  transition: border-color .2s ease;
}

.app-ticket-card:hover {
  border-color: color-mix(in srgb, var(--color-text) 20%, var(--color-border));
}

/* "Parado": esperando há >=60min OU SLA já vencido — mesmo critério do v1
   (`.tri-card.parado`). Barra de acento à esquerda via box-shadow (não
   border-left, pra não deslocar o padding) + borda toda avermelhada. */
.app-ticket-card.parado {
  border-color: color-mix(in srgb, var(--color-danger) 35%, var(--color-border));
  box-shadow: inset 3px 0 0 var(--color-danger);
}

/* Marcado como "roteado" no navegador (sessionStorage, ver script no rodapé
   da tela) — esmaece o card até o cron confirmar de verdade que o ticket
   saiu da fila. Puramente visual/local, não é estado do banco. */
.app-ticket-card.roteado {
  opacity: .55;
}

.app-ticket-roteado-aviso {
  margin-top: .7rem;
  padding: .5rem .7rem;
  border-radius: .4rem;
  background: color-mix(in srgb, var(--color-ok) 14%, var(--color-surface));
  color: var(--color-ok);
  font-size: .85rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: .4rem;
}

/* Pergunta de confirmação depois que o agente fecha a popup do "Mandar pra"
   — não dá pra saber sozinho se rolou submit lá dentro (janela de outra
   origem), então perguntamos em vez de assumir. */
.app-ticket-confirma-roteado {
  margin-top: .7rem;
  padding: .55rem .7rem;
  border-radius: .4rem;
  background: color-mix(in srgb, var(--color-info) 12%, var(--color-surface));
  border: 1px solid color-mix(in srgb, var(--color-info) 30%, transparent);
  font-size: .85rem;
  color: var(--color-text);
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
}

.app-ticket-confirma-roteado button {
  border: 1px solid transparent;
  border-radius: .35rem;
  padding: .3rem .6rem;
  font-size: .85rem;
  font-weight: 700;
  cursor: pointer;
}

.app-ticket-confirma-sim {
  background: var(--color-ok);
  color: #fff;
}

.app-ticket-confirma-nao {
  background: var(--color-bg);
  color: var(--color-text-muted);
  border-color: var(--color-border);
}

.app-ticket-card-hd {
  display: flex;
  align-items: center;
  gap: .65rem;
  margin-bottom: .65rem;
  flex-wrap: wrap;
}

.app-ticket-num {
  font-family: 'SFMono-Regular', Consolas, monospace;
  font-size: .85rem;
  font-weight: 700;
  color: var(--color-info);
  background: color-mix(in srgb, var(--color-info) 10%, transparent);
  padding: .25rem .55rem;
  border-radius: .4rem;
  text-decoration: none;
  border: 1px solid color-mix(in srgb, var(--color-info) 25%, transparent);
}

.app-ticket-num:hover {
  background: color-mix(in srgb, var(--color-info) 18%, transparent);
}

/* Nome do cliente ocupa o espaço que sobrar — é isso que empurra os badges
   de SLA/idade pro canto superior DIREITO do card (mesmo layout do v1). */
.app-ticket-cli {
  font-size: .85rem;
  font-weight: 700;
  color: var(--color-text);
  flex: 1;
  min-width: 0;
  line-height: 1.4;
}

/* Idade — badge/botão, igual pedido do Adriano (só o tom de cor tinha ficado
   ruim antes). Mistura com --color-bg (não "transparent") pra dar uma cor
   sólida de verdade em qualquer tema — claro ou escuro, o contraste sai
   proporcional ao fundo real daquele tema, não a um alpha "no vácuo". */
/* Os 4 badges do cabeçalho do card (módulo/SLA/parado/idade) compartilham a
   MESMA geometria (padding/font-size/border-radius/border) — só a cor muda
   por tipo/estado. Antes cada um tinha um tamanho ligeiramente diferente
   (Adriano notou: "os botões devem ter o mesmo tamanho, estão diferentes"). */
/* Altura fixa + `line-height` IGUAL à altura (não `line-height:1`) — trava a
   caixa de linha do texto no valor exato da altura do badge, centralizando
   de verdade independente da métrica de cada fonte (a combinação de
   `align-items:center` + `line-height:1` ainda deixava badge com fonte
   monoespaçada (idade/abertura) e badge com ícone de fonte (parado) com
   centralização vertical ligeiramente diferente — achado real do Adriano
   comparando print, 2 rodadas seguidas). */
.app-ticket-age,
.app-ticket-sla-badge,
.app-ticket-parado-badge,
.app-ticket-mod-badge,
.app-ticket-abertura {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  height: 1.55rem;
  line-height: 1.55rem;
  padding: 0 .55rem;
  border-radius: .4rem;
  border: 1px solid transparent;
  font-size: .85rem;
  font-weight: 700;
  white-space: nowrap;
  box-sizing: border-box;
  overflow: hidden;
}

.app-ticket-parado-badge i,
.app-ticket-urg-flag i {
  font-size: .85em;
  line-height: inherit;
  vertical-align: middle;
}

.app-ticket-age {
  font-family: 'SFMono-Regular', Consolas, monospace;
  font-weight: 600;
  color: var(--color-text-muted);
  background: var(--color-bg);
  border-color: var(--color-border);
}

.app-ticket-age.warn {
  color: var(--color-warn);
  background: color-mix(in srgb, var(--color-warn) 16%, var(--color-bg));
  border-color: color-mix(in srgb, var(--color-warn) 40%, var(--color-border));
}

.app-ticket-age.danger {
  color: var(--color-danger);
  background: color-mix(in srgb, var(--color-danger) 16%, var(--color-bg));
  border-color: color-mix(in srgb, var(--color-danger) 40%, var(--color-border));
}

/* Data/hora de abertura (horário de Brasília) ao lado do badge de idade —
   pedido do Adriano: ver a hora cheia, não só o tempo relativo. Mesmo chip
   neutro do badge de idade (antes era texto solto, sem caixa — destoava
   dos outros 3 badges da mesma linha, "tamanho diferente"). */
.app-ticket-abertura {
  font-family: 'SFMono-Regular', Consolas, monospace;
  font-weight: 600;
  color: var(--color-text-muted);
  background: var(--color-bg);
  border-color: var(--color-border);
  opacity: .85;
}

/* Badge de SLA — 5 estados reais (porta de `.tri-sla-*` do v1: ok/warn/crit/
   vencido/none). Fundo mixado com a SUPERFÍCIE do card (não com "transparent")
   — dá uma cor sólida de verdade, mais legível que um tom quase-transparente
   competindo com o texto colorido por cima. */
.app-ticket-sla-badge {
  font-family: 'SFMono-Regular', Consolas, monospace;
}

.app-ticket-sla-badge.none { background: var(--color-bg); color: var(--color-text-muted); border-color: var(--color-border); }
.app-ticket-sla-badge.ok { background: color-mix(in srgb, var(--color-ok) 18%, var(--color-surface)); color: var(--color-ok); border-color: color-mix(in srgb, var(--color-ok) 40%, transparent); }
.app-ticket-sla-badge.warn { background: color-mix(in srgb, var(--color-warn) 20%, var(--color-surface)); color: var(--color-warn); border-color: color-mix(in srgb, var(--color-warn) 40%, transparent); }
.app-ticket-sla-badge.crit,
.app-ticket-sla-badge.vencido { background: var(--color-danger); color: #fff; }

/* "Parado" — mesmo visual do badge de idade (borda + fundo tingido com a cor
   de fundo do card), a pedido do Adriano: o fundo sólido/texto branco de
   antes destoava demais dos outros badges do cabeçalho. */
.app-ticket-parado-badge {
  color: var(--color-danger);
  background: color-mix(in srgb, var(--color-danger) 16%, var(--color-bg));
  border-color: color-mix(in srgb, var(--color-danger) 40%, var(--color-border));
  text-transform: uppercase;
  letter-spacing: .05em;
}

/* Badge de módulo (FISCAL/EAI-INTEGRACAO/etc.) — porta de `.tri-mod-badge`
   do v1, detectado por palavra-chave no assunto/corpo/serviço. */
.app-ticket-mod-badge {
  background: color-mix(in srgb, var(--color-info) 14%, var(--color-surface));
  color: var(--color-info);
  border-color: color-mix(in srgb, var(--color-info) 35%, transparent);
  letter-spacing: .02em;
}

/* --color-ok/warn/danger/info são fixos entre temas (mesmo valor no claro e
   nos 3 escuros) — combinam bem com fundo escuro (texto claro/saturado sobre
   fundo quase-preto), mas no tema "padrao" (claro) o mesmo tom aplicado como
   TEXTO sobre um fundo quase-branco (color-mix a 15-20%) fica com contraste
   baixo, difícil de ler (achado real do Adriano, print comparando). Só o
   texto muda pra uma variante mais escura da mesma cor — fundo/borda
   continuam iguais aos outros temas. */
html[data-theme="padrao"] .app-ticket-age.warn,
html[data-theme="padrao"] .app-ticket-sla-badge.warn {
  color: #b45309;
}

html[data-theme="padrao"] .app-ticket-age.danger,
html[data-theme="padrao"] .app-ticket-parado-badge {
  color: #be123c;
}

html[data-theme="padrao"] .app-ticket-sla-badge.ok {
  color: #047857;
}

html[data-theme="padrao"] .app-ticket-mod-badge {
  color: #1d4ed8;
}

/* MESMO problema, na classe utilitária CRUA do Bootstrap `.text-warning`
 * (`!important` no próprio Bootstrap — daí o `!important` aqui também) —
 * usada pela cor de "Idade" em Chamados/Triagem/Recorrência e pela tabela
 * de `triagem_atendentes`. Mesmo âmbar já vetado
 * acima (SLA badge) — sem inventar cor nova. `.text-info` NÃO precisa
 * mais desse tipo de override — `EstadoOtrs::corClasse()` não usa mais
 * classe crua do Bootstrap pra estado, ver `.app-estado-*` abaixo.
 * Tom ajustado de novo em 14/08/2026 (achado do Adriano em Contratos BH,
 * "% Consumido" 75,7%): o `#92400e` original tinha contraste ótimo
 * (~7,3:1) mas ficou ESCURO/marrom demais — não lia como "warning" à
 * primeira vista. `#b45309` mantém contraste bom (~5,2:1, acima do
 * mínimo 4,5:1) só que mais vívido/alaranjado — mesmo valor usado agora
 * em TODOS os lugares que compartilhavam essa cor (SLA badge acima,
 * `.app-estado-aguardando` abaixo), pra não voltar a divergir. */
html[data-theme="padrao"] .text-warning {
  color: #b45309 !important;
}

/**
 * Cor de TEXTO por categoria de estado (`EstadoOtrs::corClasse()`) — MESMA
 * paleta/mesmos `var()` que a bolinha/barra de "Por estado" usam
 * (`EstadoOtrs::corFundo()`), pra tabela de drill-down e modal de detalhe
 * do ticket baterem com o painel ao lado (achado do Adriano, 05/08/2026:
 * antes cada um vinha de uma paleta diferente — Bootstrap cru vs. `--color-*`
 * do app). `progresso`/`aguardando` usados como TEXTO precisam do mesmo
 * override de contraste no tema claro que `.app-ticket-mod-badge`/
 * `.app-ticket-sla-badge.warn` já tinham (mesmo problema, reaproveita os
 * mesmos tons já vetados) — `urgente`/`sucesso`/`neutro` não precisam
 * (mesmo critério de antes, com `text-danger`/`text-success`/`text-muted`).
 */
.app-estado-urgente { color: var(--color-danger); }
.app-estado-progresso { color: var(--color-info); }
.app-estado-aguardando { color: var(--color-warn); }
.app-estado-sucesso { color: var(--color-ok); }
.app-estado-neutro { color: var(--color-text-muted); }

html[data-theme="padrao"] .app-estado-progresso {
  color: #1d4ed8;
}

html[data-theme="padrao"] .app-estado-aguardando {
  color: #b45309;
}

/* Assunto — texto simples, sem caixa/fundo/borda (pedido do Adriano: o
   "sobretom + borda esquerda reforçada" migrado do v1 ficava carregado). */
.app-ticket-assunto {
  font-size: .88rem;
  font-weight: 600;
  color: var(--color-text);
  margin-bottom: .35rem;
  line-height: 1.4;
}

.app-ticket-solicitante {
  font-size: .85rem;
  color: var(--color-text-muted);
  margin: -.1rem 0 .3rem;
  opacity: .85;
}

.app-ticket-preview {
  font-size: .85rem;
  color: var(--color-text-muted);
  margin: -.1rem 0 .6rem;
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  opacity: .85;
}

/* Flag de urgência (sinais de texto tipo "parado"/"fora do ar") — porta de
   `.tri-urg-flag` do v1. */
.app-ticket-urg-flag {
  font-size: .85rem;
  color: var(--color-danger);
  background: color-mix(in srgb, var(--color-danger) 10%, var(--color-surface));
  border: 1px solid color-mix(in srgb, var(--color-danger) 25%, transparent);
  border-radius: .4rem;
  padding: .45rem .65rem;
  margin-bottom: .6rem;
  font-weight: 600;
  line-height: 1.45;
}

.app-ticket-urg-flag strong {
  color: var(--color-danger);
  font-weight: 800;
}

/* ---------- "Mandar pra" — botões de time, porta de `.tri-card-actions`/
   `.tri-squad-btn` do v1. Abrem o ticket já com fila+estado pré-selecionados
   (ver OtrsClient::urlRoteamento) — não movem nada sozinhos, o agente
   confirma/salva na tela real do OTRS. ---------- */
.app-ticket-actions {
  display: flex;
  gap: .4rem;
  flex-wrap: wrap;
  align-items: center;
  margin-top: .7rem;
  padding-top: .7rem;
  border-top: 1px solid var(--color-border);
}

.app-ticket-actions-lbl {
  font-size: .85rem;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: .06em;
  font-weight: 700;
  margin-right: .2rem;
}

.app-ticket-time-btn {
  padding: .45rem .75rem;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: .5rem;
  color: var(--color-text);
  font-size: .85rem;
  font-weight: 600;
  text-decoration: none;
  letter-spacing: .01em;
  transition: all .15s ease;
}

.app-ticket-time-btn:hover {
  border-color: var(--color-info);
  background: color-mix(in srgb, var(--color-info) 8%, var(--color-bg));
  color: var(--color-info);
}

.app-ticket-time-btn.sugerido {
  background: color-mix(in srgb, var(--color-ok) 16%, var(--color-bg));
  border-color: color-mix(in srgb, var(--color-ok) 45%, transparent);
  color: var(--color-ok);
}

.app-ticket-time-btn.sugerido:hover {
  border-color: var(--color-ok);
  background: color-mix(in srgb, var(--color-ok) 24%, var(--color-bg));
}

.app-ticket-sug-pct {
  font-size: .85rem;
  opacity: .75;
  margin-left: .25rem;
  font-family: 'SFMono-Regular', Consolas, monospace;
}

/* Chip de sugestão de time — porta de `.sq-card-sim` do v1 (limpei uma
   duplicata desta regra que tinha ficado de uma edição anterior). */
.app-ticket-sugestao {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  margin-top: .6rem;
  padding: .4rem .65rem;
  background: color-mix(in srgb, var(--color-info) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--color-info) 30%, transparent);
  border-radius: .5rem;
  color: var(--color-info);
  font-size: .85rem;
  font-weight: 600;
}

.app-ticket-sugestao.baixa-confianca {
  background: color-mix(in srgb, var(--color-text-muted) 10%, transparent);
  border-color: color-mix(in srgb, var(--color-text-muted) 28%, transparent);
  color: var(--color-text-muted);
}

.app-ticket-sugestao strong {
  font-weight: 800;
}

/* ---------- Filtro "por time sugerido" — porta de `.tri-filtro*` do v1. ---------- */
.app-tri-filtro {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}

.app-tri-filtro-lbl {
  font-size: .85rem;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: .06em;
  font-weight: 700;
  margin-right: .15rem;
}

.app-tri-filtro-chip {
  padding: .4rem .75rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 1.2rem;
  color: var(--color-text-muted);
  font-size: .85rem;
  font-weight: 600;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  transition: all .15s ease;
}

.app-tri-filtro-chip span {
  font-family: 'SFMono-Regular', Consolas, monospace;
  font-size: .85rem;
  opacity: .7;
}

.app-tri-filtro-chip:hover {
  border-color: var(--color-info);
  color: var(--color-text);
}

.app-tri-filtro-chip.on {
  background: var(--color-brand-soft);
  border-color: color-mix(in srgb, var(--color-brand) 45%, transparent);
  color: var(--color-brand);
}

/* Chip pequeno de fila na tabela de Times (coluna "Filas") — era `.btn`
   desabilitado antes, ficava alto/pesado demais e empilhava mal numa
   coluna estreita (achado real do Adriano, print comparando). Badge
   simples, mesmo espírito do resto do app. */
.app-fila-badge {
  display: inline-flex;
  align-items: center;
  padding: .2rem .5rem;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: .35rem;
  font-size: .72rem;
  font-weight: 600;
  color: var(--color-text-muted);
  white-space: nowrap;
}

/* ---------- Flatpickr (calendário/time-picker de .js-date e .js-time) ----------
   O CSS padrão da lib é um skin claro fixo, sem noção de tema — nos temas
   escuros (Escuro/Azul/Cinza) o popup abria claro em cima de uma tela escura
   (achado real do Adriano). Sobrescreve com as variáveis do tema ativo, mesmo
   padrão já usado pra `.popover`/`.table` acima. */
.flatpickr-calendar {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-md);
  color: var(--color-text);
}

.flatpickr-calendar.arrowTop::before,
.flatpickr-calendar.arrowTop::after {
  border-bottom-color: var(--color-border);
}

.flatpickr-months .flatpickr-month,
.flatpickr-current-month,
.flatpickr-weekdays {
  background: var(--color-surface);
  color: var(--color-text);
  fill: var(--color-text);
}

.flatpickr-current-month .flatpickr-monthDropdown-months,
.flatpickr-current-month input.cur-year {
  background: transparent;
  color: var(--color-text);
}

.flatpickr-current-month .flatpickr-monthDropdown-months option {
  background: var(--color-surface);
  color: var(--color-text);
}

.flatpickr-prev-month:hover svg,
.flatpickr-next-month:hover svg {
  fill: var(--color-brand);
}

span.flatpickr-weekday {
  color: var(--color-text-muted);
  background: var(--color-surface);
}

.flatpickr-day {
  color: var(--color-text);
}

.flatpickr-day.flatpickr-disabled,
.flatpickr-day.flatpickr-disabled:hover,
.flatpickr-day.prevMonthDay,
.flatpickr-day.nextMonthDay {
  color: var(--color-text-muted);
}

.flatpickr-day:hover {
  background: var(--color-bg);
  border-color: var(--color-bg);
}

.flatpickr-day.today {
  border-color: var(--color-brand);
}

.flatpickr-day.selected,
.flatpickr-day.selected:hover,
.flatpickr-day.selected:focus {
  background: var(--color-brand);
  border-color: var(--color-brand);
  color: #fff;
}

.flatpickr-time {
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
}

.flatpickr-time input,
.flatpickr-time .flatpickr-time-separator,
.flatpickr-time .flatpickr-am-pm {
  color: var(--color-text);
  background: transparent;
}

.flatpickr-time input:hover,
.flatpickr-time input:focus,
.flatpickr-time .flatpickr-am-pm:hover,
.flatpickr-time .flatpickr-am-pm:focus {
  background: var(--color-bg);
}

.numInputWrapper span.arrowUp:after {
  border-bottom-color: var(--color-text-muted);
}

.numInputWrapper span.arrowDown:after {
  border-top-color: var(--color-text-muted);
}

.numInputWrapper:hover {
  background: var(--color-bg);
}

/* ---------- Toast (assets/js/toast.js) — porta do mesmo componente do
   apontamentos-v2, adaptado pras variáveis de tema já existentes aqui em vez
   de duplicar uma paleta clara/escura fixa (o <html> já ganha data-bs-theme
   automaticamente — ver theme.js —, então o botão de fechar já inverte
   sozinho no dark mode nativo do Bootstrap, sem CSS extra). ---------- */
.app-toast {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
  min-width: 20rem;
  background: var(--color-surface);
  color: var(--color-text);
}

.app-toast .toast-body {
  font-size: .88rem;
  font-weight: 500;
}

/* Fundo colorido nos 4 tipos, a pedido do Adriano (09/08/2026: "o de
   problema fica melhor com fundo vermelho... dá pra padronizar verde/
   amarelo/vermelho?"). 1ª tentativa (só `rgba(...,.14)` como `background`)
   ficou "transparente demais" — o toast é `position:fixed`, fica por cima
   de conteúdo que MUDA (rola por baixo), e uma tinta fraca sozinha deixa
   esse fundo variável transparecer. Fix: base OPACA (`--color-surface`,
   mesma de sempre) + uma segunda camada de cor bem mais forte por cima
   (`background-image`, não composita com o que está atrás da janela) —
   fica um cartão colorido de verdade, não uma janela semitransparente.
   RGBA fixo (não `color-mix` com token) porque ok/warn/danger/info já são
   os MESMOS valores nos 4 temas — sem risco de destoar. 2ª rodada
   (09/08/2026): .35 ficava "rosa clarinho" no tema Padrão, mas .6 (a
   correção) criou um problema DIFERENTE — o texto normal (`--color-text`,
   escuro no tema Padrão) contra um vermelho/rosa já bem saturado virou uma
   combinação de cor feia ("essa fonte escura nesse vermelho está
   horrível"), mesmo com contraste tecnicamente OK. 3ª rodada: volta pra
   uma tinta BEM leve (.16, mesmo nível do `.app-alerta-aviso` que já
   existe no app sem reclamação) — a base opaca (`--color-surface`) já
   resolve sozinha o problema original de transparência; não precisa de
   saturação alta pra isso. */
.app-toast-info {
  background-color: var(--color-surface);
  background-image: linear-gradient(rgba(79, 142, 247, .16), rgba(79, 142, 247, .16));
  border-color: rgba(79, 142, 247, .4);
}

.app-toast-info .bi {
  color: var(--color-info);
}

.app-toast-success {
  background-color: var(--color-surface);
  background-image: linear-gradient(rgba(16, 185, 129, .16), rgba(16, 185, 129, .16));
  border-color: rgba(16, 185, 129, .4);
}

.app-toast-success .bi {
  color: var(--color-ok);
}

.app-toast-warning {
  background-color: var(--color-surface);
  background-image: linear-gradient(rgba(245, 158, 11, .16), rgba(245, 158, 11, .16));
  border-color: rgba(245, 158, 11, .4);
}

.app-toast-warning .bi {
  color: var(--color-warn);
}

/* Tentativa de reusar os tokens do hero de status (--color-hero-status-*)
   aqui foi REVERTIDA (09/08/2026, mesmo dia) — nos temas escuros esses
   tokens misturam contra "transparent" de propósito (fazem sentido pro
   HERO, que não tem `background-color` opaco próprio por baixo), mas o
   toast TEM (`background-color: var(--color-surface)` logo abaixo) —
   layer semi-transparente com 2 tons de opacidade DIFERENTES por cima de
   uma base opaca cria um gradiente de transparência desigual dentro do
   próprio card ("um gradiente meio transparente" — achado do Adriano,
   comparando os 4 temas lado a lado). Fix: cor CHAPADA (mesmo valor nos
   dois pontos do gradiente = sem gradiente de verdade), 1 opacidade leve
   só, igual nos 4 temas — rgba fixo porque --color-danger já é idêntico
   nos 4 temas mesmo. */
/* Texto vermelho (pedido do Adriano numa rodada anterior) foi REVERTIDO
   pra `--color-text` normal (herdado de `.app-toast`) — nos temas
   escuros/azul/cinza a fonte CLARA de sempre lia melhor que vermelho
   (09/08/2026, achado do Adriano comparando os 4 temas). */
.app-toast-error {
  background-color: var(--color-surface);
  background-image: linear-gradient(rgba(244, 63, 94, .18), rgba(244, 63, 94, .18));
  border-color: rgba(244, 63, 94, .4);
}

.app-toast-error .bi {
  color: var(--color-danger);
}

/* ---------- Cobrança (Triagem > Cobrança) — porta de "Equipes & Cobrança"
   do command-center-vercel. Mesmo piso de fonte .85rem da Triagem (ver nota
   lá em cima) — nada aqui é decorativo, tudo é informação real. ---------- */
.app-cobr-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  margin-bottom: .75rem;
  overflow: hidden;
}

.app-cobr-card-hd {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .75rem 1rem;
  cursor: pointer;
}

.app-cobr-chevron {
  transition: transform .15s ease;
  color: var(--color-text-muted);
}

.app-cobr-card.recolhido .app-cobr-chevron {
  transform: rotate(-90deg);
}

/* Cabeçalho de ZONA colapsável (título + dica) — mesma receita de chevron
   de `.app-cobr-chevron` (Triagem > Cobrança), generalizada pra qualquer
   bloco "título + corpo" da aplicação (pedido do Adriano, 06/08/2026,
   "SLA & Tempos": "pode ser em linhas suprimíveis?"). O cabeçalho e o
   corpo são irmãos diretos no HTML — não precisa de wrapper novo, o
   `+` (irmão adjacente) já resolve. */
.app-secao-chevron {
  transition: transform .15s ease;
  color: var(--color-text-muted);
  font-size: 1rem;
}

.app-secao-colapsavel {
  /* SEM `cursor:pointer` aqui de propósito — o clique de recolher/
     expandir é só no ícone/título (div interna, `style="cursor:pointer"`
     inline), não na linha inteira. Antes a linha toda era clicável e
     dava pra clicar no espaço vazio entre o título e a dica lateral sem
     querer (achado do Adriano, 06/08/2026). */
  padding-bottom: .5rem;
  border-bottom: 1px solid var(--color-border);
}

.app-secao-colapsavel.recolhida .app-secao-chevron {
  transform: rotate(-90deg);
}

.app-secao-colapsavel.recolhida + .app-secao-corpo {
  /* `!important` (18/08/2026, achado real do Adriano em "Decida esta
     semana"/Visão Semanal): o corpo dessa seção usa `d-flex` (utilitário
     do Bootstrap, que já vem com `display:flex !important`) — sem o
     `!important` aqui, essa regra perdia a "queda de braço" de
     especificidade e o painel nunca escondia de verdade, mesmo com a
     classe `recolhida` aplicada certinho pelo JS (conferido: a classe
     entrava, só o CSS que não vencia). Cobre qualquer `app-secao-corpo`
     futuro que também use classes utilitárias `!important` do Bootstrap
     (`d-flex`/`d-grid`/etc.), não só este caso específico. */
  display: none !important;
}

.app-cobr-card.recolhido .app-cobr-card-body {
  display: none;
}

/* "Atendente" > Meu Painel (19/08/2026) — card visual de ticket dos 4
   blocos de ação, porta de `.sq-card` do command-center-vercel. Borda
   esquerda pela cor do SLA (mesma convenção de card-panel colorido já
   usada em "Decida esta semana"/Visão Semanal), "fala" (frase de
   cobrança) com 3 níveis de intensidade — ver AtendentePainelService::
   frasePersonificada(). */
/* Grid dos cards (19/08/2026, achado do Adriano: "largura mínima um
   pouco maior" — `col-md-4` do Bootstrap virava 3 colunas fixas
   estreitas demais em telas menores) — mesmo padrão `auto-fill` +
   `minmax` já usado em Comparativo/Em Espera/etc. (nunca inventar
   grid novo, reusar a convenção). 280px acomoda bem o conteúdo do
   card (número+badge/assunto/fala/rodapé) sem ficar apertado. */
.aten-cards-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: .5rem;
}

.aten-card {
  border-left: 3px solid var(--color-border);
  height: 100%;
}
.aten-card-ok {
  border-left-color: var(--color-ok);
}
.aten-card-warn {
  border-left-color: var(--color-warn);
}
.aten-card-crit {
  border-left-color: var(--color-danger);
}
.aten-card-nt {
  border-left-color: var(--color-border);
}
.aten-card-num {
  font-family: var(--font-mono, monospace);
  font-weight: 700;
  font-size: .875rem;
  color: var(--color-text);
  text-decoration: none;
}
.aten-card-num:hover {
  color: var(--color-brand);
}
.aten-card-assunto {
  font-weight: 600;
  font-size: .875rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.aten-card-fala {
  font-size: .75rem;
  font-style: italic;
  padding: 6px 8px;
  border-radius: 6px;
  margin-top: 4px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
}
.aten-card-fala-lvl1 {
  color: var(--color-warn);
  border-color: color-mix(in srgb, var(--color-warn) 40%, var(--color-border));
}
.aten-card-fala-lvl2 {
  color: var(--color-brand);
  border-color: color-mix(in srgb, var(--color-brand) 40%, var(--color-border));
}
.aten-card-fala-lvl3 {
  color: var(--color-danger);
  border-color: color-mix(in srgb, var(--color-danger) 40%, var(--color-border));
}

/* "Atenção aqui" (holofote) — porta de `.sq-spot`: borda pulsante,
   emoji balançando, eyebrow oscilando. SEM fundo colorido de propósito
   (19/08/2026, achado do Adriano: o gradiente vermelho de fundo deixava
   o pulso da borda quase imperceptível E ele não queria esse fundo de
   qualquer forma) — fundo neutro de `.card-panel`, só a borda/ícone/
   eyebrow carregam o sinal. A animação da borda combina a sombra BASE
   do `.card-panel` (`--shadow-sm`) com o anel pulsante — sem isso, o
   `box-shadow` do `.card-panel` (mesma especificidade, mas definido
   ANTES no arquivo) perderia a queda de braço só nos frames em que o
   anel está transparente, piscando estranho. `prefers-reduced-motion`
   desativa tudo (acessibilidade). */
.aten-spot {
  position: relative;
  border: 2px solid color-mix(in srgb, var(--color-danger) 45%, var(--color-border));
  animation: atenSpotPulse 2.2s ease-in-out infinite;
}
.aten-spot.warn-tone {
  border-color: color-mix(in srgb, var(--color-warn) 45%, var(--color-border));
  animation-name: atenSpotPulseWarn;
}
.aten-spot-emoji {
  display: inline-block;
  font-size: 1.8rem;
  line-height: 1;
  flex-shrink: 0;
  animation: atenSpotBounce 1.4s ease-in-out infinite;
}
.aten-spot-eyebrow {
  display: inline-block;
  font-weight: 900;
  letter-spacing: .08em;
  text-transform: uppercase;
  animation: atenSpotSway 1.8s ease-in-out infinite;
  transform-origin: left center;
}
@keyframes atenSpotPulse {
  0%, 100% { box-shadow: var(--shadow-sm), 0 0 0 0 color-mix(in srgb, var(--color-danger) 55%, transparent); }
  50% { box-shadow: var(--shadow-sm), 0 0 0 10px color-mix(in srgb, var(--color-danger) 0%, transparent); }
}
@keyframes atenSpotPulseWarn {
  0%, 100% { box-shadow: var(--shadow-sm), 0 0 0 0 color-mix(in srgb, var(--color-warn) 55%, transparent); }
  50% { box-shadow: var(--shadow-sm), 0 0 0 10px color-mix(in srgb, var(--color-warn) 0%, transparent); }
}
@keyframes atenSpotBounce {
  0%, 100% { transform: translateY(0) rotate(-5deg); }
  50% { transform: translateY(-3px) rotate(8deg); }
}
@keyframes atenSpotSway {
  0%, 100% { transform: rotate(-3deg); }
  50% { transform: rotate(3deg); }
}
/* SEM guarda de `prefers-reduced-motion` de propósito (19/08/2026) —
   mesmo precedente já registrado no ícone de sync `--erro` (09/08/2026,
   ver comentário lá): o Adriano tem "reduzir movimento" ativo no
   próprio navegador/SO e confirmou que quer VER essa animação mesmo
   assim (achado ao vivo: ele reportou "borda não pulsa/ícone não
   mexe/título não muda" — testei emulando `reduced_motion=reduce` via
   Playwright e reproduzi exatamente o sintoma; sem essa emulação, tudo
   funcionava). Removido o `@media` que desligava tudo — este bloco de
   animação sempre anima, independente da preferência do SO. */

/* Simetria com o ícone do holofote (1.8rem) nos 3 cards de atenção. */
.aten-att-icon {
  font-size: 1.8rem;
}

/* Pulso de destaque ao pular pro bloco (ver `atenAbrirBloco()`) — o
   Adriano pediu explicitamente pra REAPROVEITAR o pulso que já existe
   em Análises > Recorrência (filtro Cliente), não inventar um novo:
   `.app-campo-pulsar-glow` (ver docblock dela mais acima, achado de
   12/08/2026 — variante SÓ com glow, não mexe em `border-color`,
   pensada exatamente pra card que já tem borda colorida própria, como
   os `.aten-card` aqui, que têm borda por status de SLA). É
   `infinite` por padrão; aqui o JS aplica e remove a classe via
   `setTimeout` pra durar só ~3s. */

.app-cobr-card-nome {
  font-weight: 700;
  font-size: 1rem;
}

.app-cobr-card-gestor {
  color: var(--color-text-muted);
  font-size: .85rem;
}

.app-cobr-card-stats {
  margin-left: auto;
  color: var(--color-text-muted);
  font-size: .85rem;
  white-space: nowrap;
}

.app-cobr-btn-coletiva {
  background: var(--color-brand);
  color: #fff;
  border: none;
  border-radius: .4rem;
  padding: .4rem .75rem;
  font-size: .85rem;
  font-weight: 600;
  white-space: nowrap;
}

.app-cobr-btn-coletiva:hover {
  background: var(--color-brand-dark);
}

.app-cobr-card-body {
  border-top: 1px solid var(--color-border);
}

.app-cobr-consultor {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .6rem 1rem;
  border-bottom: 1px solid var(--color-border);
}

.app-cobr-consultor:last-child {
  border-bottom: none;
}

.app-cobr-dot {
  width: .6rem;
  height: .6rem;
  border-radius: 50%;
  flex-shrink: 0;
}

.app-cobr-dot.ok { background: var(--color-ok); }
.app-cobr-dot.warn { background: var(--color-warn); }
.app-cobr-dot.crit { background: var(--color-danger); }

.app-cobr-consultor-info {
  flex: 1;
  min-width: 0;
}

.app-cobr-consultor-nome {
  font-weight: 700;
  font-size: .9rem;
}

.app-cobr-consultor-sub {
  color: var(--color-text-muted);
  font-size: .85rem;
}

.app-cobr-consultor-antigo {
  font-size: .85rem;
  color: var(--color-text-muted);
}

/* Só o número de dias fica destacado (>= DIAS_ANTIGO_DESTAQUE), não a linha
   inteira — igual a referência original. Achado real do Adriano comparando
   print: a 1ª versão desta porta coloria "Mais antigo: 98d · #ticket" todo,
   a original só o "98d". */
.app-cobr-consultor-antigo .destaque {
  font-weight: 700;
  color: var(--color-warn);
}

.app-cobr-num {
  font-family: 'SFMono-Regular', Consolas, monospace;
  font-size: 1.3rem;
  font-weight: 700;
  min-width: 2rem;
  text-align: center;
}

.app-cobr-num.ok { color: var(--color-ok); }
.app-cobr-num.warn { color: var(--color-warn); }
.app-cobr-num.crit { color: var(--color-danger); }

.app-cobr-btn-individual {
  background: var(--color-brand);
  color: #fff;
  border: none;
  border-radius: .4rem;
  padding: .35rem .65rem;
  font-size: .85rem;
  font-weight: 600;
  white-space: nowrap;
}

.app-cobr-btn-individual:hover {
  background: var(--color-brand-dark);
}

/* "Cliente"/"Time" (Em Espera, 07/08/2026) — passaram por 3 versões:
   1ª cor própria (âmbar/azul) → 2ª unificada com o botão sólido de
   Triagem > Cobrança (`.app-cobr-btn-individual`, fundo `--color-brand`)
   → 3ª e atual: `.app-cobr-btn-discreto` (achado do Adriano: com 1-2
   botão POR CARD e dezenas de cards na grade, o preenchimento sólido
   pesa demais — em Triagem é 1-2 botão por TELA, densidade bem menor).
   Mesma linguagem visual que os badges destes cards já usam (fundo
   tingido a 13%, texto na cor cheia) — harmoniza com o que já existe no
   card em vez de introduzir um 3º estilo. Ícone (`bi-megaphone`) e
   rótulo curto ("Cliente"/"Time") continuam os mesmos da 2ª versão. Os
   botões de cabeçalho ("Cobrar retornos no grupo"/"Escalar
   reincidentes", 1 de cada por tela) CONTINUAM sólidos — baixa
   densidade lá, o problema é só nos botões por card.

   O par de botões usa `.app-cobr-slot` em vez do `.flex-fill` do
   Bootstrap (achado real, print do Adriano: com só 1 dos 2 botões
   presentes, o `.flex-fill` — `flex-basis: auto` — dava um tamanho pro
   slot vazio baseado no texto/ícone que sobrava, não uma coluna igual à
   do botão pareado). `flex-basis: 0` + `min-width: 0` já resolve a
   diferença de CONTEÚDO, mas sobrava uma 2ª causa (achado via medição
   real com Playwright, não só o olho): o `<div>` vazio não tem padding
   nenhum, e padding NÃO é zerável por `min-width` (é espaço físico
   sempre reservado, `min-width:0` só remove o piso do conteúdo/texto) —
   isso dava ~17px de vantagem pro botão de verdade mesmo com flex-basis
   igual. Fix definitivo: o placeholder virou um BOTÃO de verdade da
   MESMA classe, só `visibility:hidden` — caixa estruturalmente idêntica
   (mesmo padding), sem precisar duplicar valor de padding em 2 lugares
   que poderiam divergir no futuro. */
.app-cobr-slot {
  flex: 1 1 0;
  min-width: 0;
}

.app-cobr-btn-discreto {
  background: color-mix(in srgb, var(--color-brand) 12%, transparent);
  color: var(--color-brand);
  border: none;
  border-radius: .4rem;
  padding: .35rem .5rem;
  font-size: .8rem;
  font-weight: 600;
  white-space: nowrap;
}

.app-cobr-btn-discreto:hover {
  background: color-mix(in srgb, var(--color-brand) 22%, transparent);
}

/* "Escalar reincidentes" — mesma receita, cor de alerta (a ação em si já
   é uma escalada, faz sentido chamar mais atenção que o botão coletivo
   ao lado). "Cobrar retornos no grupo" reusa `.app-cobr-btn-coletiva`
   (já existia, mesmo conceito de ação em lote) — não duplicado. */
.app-cobr-btn-escalar {
  background: var(--color-danger);
  color: #fff;
  border: none;
  border-radius: .4rem;
  padding: .4rem .75rem;
  font-size: .85rem;
  font-weight: 600;
  white-space: nowrap;
}

.app-cobr-btn-escalar:hover {
  background: color-mix(in srgb, var(--color-danger) 85%, black);
}

.app-cobr-gestor-bloco {
  margin-bottom: 1.25rem;
}

.app-cobr-gestor-hd {
  font-weight: 700;
  font-size: .95rem;
  padding: .5rem 0;
  color: var(--color-text);
}

.app-detalhe-modal {
  max-width: 1300px;
  width: 95vw;
}

/* ═══ Comparativo Mensal (05/08/2026) — porta de .comp-* do
   command-center-vercel, confirmado ao vivo em produção real antes de
   portar (ver docblock de modules/op_comparativo.php). ═══ */

/* `.app-comp-runrate` (outer)/`-icon`/`-main`/`-tag`/`-titulo` removidas
   (07/08/2026, pedido do Adriano: "rever esse HEROE pra deixar no
   padrão das demais telas, tirar o ícone do canto esquerdo") — o hero de
   Comparativo agora usa `card-panel card-panel-compacto` + gradiente
   inline direto no PHP, igual todo outro hero da app; não precisa mais
   de layout/classe própria. `-sub`/`-num`/`-num-lbl` continuam (ainda
   usadas pelo hero de Comparativo E pelos heroes de Chamados/Backlog). */
.app-comp-runrate-sub {
  color: var(--color-text-muted);
  line-height: 1.5;
}

.app-comp-runrate-sub strong {
  color: var(--color-text);
  font-weight: 600;
}

.app-comp-runrate-num {
  font-size: 2.5rem;
  font-weight: 700;
  line-height: 1.1;
  color: var(--color-brand);
}

.app-comp-runrate-num-lbl {
  font-size: .875rem;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: .05em;
  margin-top: .25rem;
}

/* `.app-comp-runrate-delta*` removida (07/08/2026, junto com o resto do
   redesign do hero) — a variação% agora é o próprio `.app-comp-runrate-
   num` (cor inline calculada no PHP), não um badge separado embaixo. */

.app-comp-vol-tgl {
  background: transparent;
  border: none;
  color: var(--color-text-muted);
  font-size: .68rem;
  font-weight: 600;
  padding: .4rem .75rem;
  border-radius: .4rem;
  cursor: pointer;
}

/* Botões de mês (Período A/B) do Comparativo Mensal — classes PRÓPRIAS em
   vez de `.btn-outline-info`/`.btn-outline-warning` do Bootstrap (achado
   do Adriano, 10/08/2026: cores fixas do Bootstrap não acompanham os 4
   temas do app). Mesma receita de "cor sólida + texto branco no estado
   ativo" já usada em `.app-fila-item`/`.ativo` (sidebar) — reaproveita
   `--color-info`/`--color-brand`, que já são os tokens corretos pros 2
   tons (A=azul/info, B=âmbar/warn) em todos os temas.

   B NÃO usa `--color-brand`: testei nos 4 temas e no tema "azul" o brand
   TAMBÉM vira azul (mesma família de --color-info) — A e B ficavam quase
   idênticos, perdendo a distinção. `--color-warn` (âmbar) é o MESMO valor
   fixo nos 4 temas (nunca colide com o azul de A), então ficou a escolha
   certa mesmo sendo também a cor de status "Atenção" em outro contexto da
   mesma tela — a distância visual entre um botão de mês e um badge de
   status é grande o suficiente pra não confundir. */
.app-mes-toggle-a {
  --bs-btn-color: var(--color-info);
  --bs-btn-border-color: var(--color-info);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--color-info);
  --bs-btn-hover-border-color: var(--color-info);
  --bs-btn-active-color: #fff;
  --bs-btn-active-bg: var(--color-info);
  --bs-btn-active-border-color: var(--color-info);
}
.app-mes-toggle-b {
  --bs-btn-color: var(--color-warn);
  --bs-btn-border-color: var(--color-warn);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--color-warn);
  --bs-btn-hover-border-color: var(--color-warn);
  --bs-btn-active-color: #fff;
  --bs-btn-active-bg: var(--color-warn);
  --bs-btn-active-border-color: var(--color-warn);
}

.app-comp-vol-tgl:hover { color: var(--color-text); }
/* Texto ESCURO no ativo, não branco — o teal (--color-accent) é claro
   demais pra texto branco em cima (contraste medido ~1.9:1, bem abaixo
   do mínimo de acessibilidade ~4.5:1); achado real do Adriano
   (05/08/2026), "esse fundo verde tá bem ruim de ler". */
.app-comp-vol-tgl.ativo { background: var(--color-accent); color: #0b2622; font-weight: 700; }

/* Linha vira grid de colunas FIXAS (não flex com min-width solto) —
   pedido do Adriano (05/08/2026): "simetria dos dados à direita, estilo
   tabela". Com flex, cada coluna só respeitava um min-width (piso, não
   largura fixa), então uma linha com "3h 44min"/"44.6h" (mais larga que
   "915"/"73") empurrava a seta/badge dessa linha específica, quebrando o
   alinhamento vertical entre linhas. Grid trava a largura de cada coluna
   igual em TODAS as linhas. */
.app-comp-row {
  display: grid;
  grid-template-columns: 2.2rem 1fr 5rem 1.6rem 5rem 4.2rem;
  align-items: center;
  gap: .5rem;
  padding: .5rem 0;
  border-bottom: 1px solid var(--color-border);
  font-size: .78rem;
}

.app-comp-row:last-child { border-bottom: none; }

/* Linha de lista "tipo ranking" (Top Cliente/Serviço/Atendente etc.) —
   borda inferior discreta separando cada item, pra não parecer texto
   flutuante solto (pedido do Adriano, 09/08/2026, sobre os blocos "Top
   Clientes/Top Serviços/Top Atendentes" de Projetos & Melhorias). Antes
   dessa classe existir, o único consumidor (`op_projetos_melhorias.php`)
   já tentava essa borda inline com `var(--border)` — variável que NUNCA
   existiu neste arquivo (só `--color-border`) — então a borda nunca era
   desenhada de verdade; script buscado no resto do sistema (Eficiência da
   Equipe em `op_executivo.php`, Comparativo) não achou nenhuma classe
   equivalente já pronta pra reusar, daí a classe nova aqui em vez de mais
   um estilo inline solto. */
.app-ranking-linha {
  border-bottom: 1px solid var(--color-border);
}

.app-ranking-linha:last-child {
  border-bottom: none;
}

/* Variante sem a 1ª coluna (ícone de direção 🎯↑/🎯↓) — usada pelo
   "Comparativo com mês anterior" DENTRO de Chamados (06/08/2026): o v1
   nunca teve esse ícone ali (só o Comparativo Mensal, tela separada, tem
   `opCompDirIcone()`). Mesmas colunas de valor (`.app-comp-prev/arrow/
   curr/delta`), só sem a coluna do ícone — mesma simetria, sem duplicar
   o grid inteiro por 1 coluna de diferença. */
.app-comp-row-simples {
  grid-template-columns: 1fr 5rem 1.6rem 5rem 4.2rem;
}

.app-comp-dir-ic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.05rem;
  color: var(--color-text-muted);
  cursor: help;
}

.app-comp-label { color: var(--color-text); }

.app-comp-prev {
  font-size: .8rem;
  color: var(--color-text-muted);
  text-align: right;
}

.app-comp-arrow {
  font-size: 1.15rem;
  text-align: center;
}

.app-comp-curr {
  font-size: .9rem;
  font-weight: 600;
  text-align: right;
}

.app-comp-delta {
  font-size: .7rem;
  font-weight: 700;
  padding: .15rem .5rem;
  border-radius: 999px;
  justify-self: center;
  text-align: center;
}

/* Selos "vol"/"SLA" dentro de cada card de mês — mesma caixinha do
   .app-comp-delta, só sem min-width fixo (texto mais variável). Tamanho
   subido de .64rem pra .7rem (05/08/2026, achado do Adriano: "precisa de
   revisão no tamanho da fonte" mesmo em tela grande) — mesmo .7rem já
   padronizado pros badges da Triagem (item 28 da memória do projeto), não
   um valor novo. */
.app-comp-sinal {
  display: inline-flex;
  align-items: center;
  font-size: .7rem;
  font-weight: 700;
  padding: .15rem .5rem;
  border-radius: 999px;
}

/* Versão "só texto" do selo acima — sem pílula/fundo, achado do Adriano
   (07/08/2026, "Retornos Devidos por Atendente"): "cliente esperando/
   respondeu" virou botãozinho colorido de mais, era só texto colorido
   antes do card ganhar o padrão quadrado-com-borda-no-topo. "ok" NÃO
   ganha cor (usa `.text-muted` junto no HTML) — só warn/crit chamam
   atenção de verdade; texto verde pra "tudo bem" é ruído. */
.app-comp-texto-sinal {
  font-size: .7rem;
  font-weight: 700;
}
.app-comp-texto-sinal.warn { color: var(--color-warn); }
.app-comp-texto-sinal.crit { color: var(--color-danger); }

/* Seta (↑/↓/▬) do selo "vol" — um pouco maior que o resto do texto do
   selo (senão fica ilegível), mas SEM exagerar (1.05rem ficou grande
   demais e desalinhado verticalmente — achado do Adriano) e com
   `vertical-align` explícito pra centralizar com o texto ao lado dentro
   do flex. */
.app-comp-sinal-seta {
  display: inline-flex;
  align-items: center;
  font-size: .85rem;
  line-height: 1;
  vertical-align: middle;
  margin-right: .3rem;
}

.app-comp-sinal.ok { background: rgba(16, 185, 129, .1); color: var(--color-ok); }
.app-comp-sinal.warn { background: rgba(245, 158, 11, .1); color: var(--color-warn); }
.app-comp-sinal.crit { background: rgba(244, 63, 94, .1); color: var(--color-danger); }
.app-comp-sinal.nt { background: rgba(90, 98, 120, .1); color: var(--color-text-muted); }

/* Grid dos cards por mês — CSS grid, não breakpoint fixo do Bootstrap: em
   tela grande cabe mais card por linha automaticamente (pedido do
   Adriano, 05/08/2026: "cabe mais card por linha"). `auto-fit` +
   `minmax(175px, 1fr)` (era 160px até 11/08/2026 — trocado de
   `auto-fill`+`190px` fixo em 05/08/2026 — sobrava espaço vazio à
   direita quando a largura da tela não dividia certinho por 190px) —
   os cards da última coluna CRESCEM pra preencher a linha inteira, sem
   gap sobrando. Largura mínima subiu de 160px (11/08/2026, achado do
   Adriano em "Comparativo Mensal": a 160px os 2 selos — variação de
   volume + % SLA — não cabiam lado a lado com texto mais longo tipo
   "↑ 271% vol", quebravam linha só nesses cards, misturando altura de
   card na mesma grade; "tava mais elegante" quando cabia numa linha
   só) — passou por 195px, depois voltou pra 175px no mesmo dia (o
   Adriano achou 195px largo demais, "sobrou espaço horizontal" depois
   do card ficar mais baixo com o título+total na mesma linha).
   Conteúdo alinhado à esquerda explicitamente. */
.app-comp-mes-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(175px, 1fr));
  gap: .75rem;
}

/* Modificador (07/08/2026, "Em Espera" > Retornos Devidos por Atendente)
   — pedido do Adriano: nome de analista precisa de mais largura que mês
   ("ago/24"). Não mexe no `minmax` base (usado em Comparativo, onde
   160px já é o suficiente) — só esta tela pede o card mais largo.
   `auto-fill` em vez de `auto-fit` (18/08/2026, 3ª rodada do mesmo
   achado — ver comentário completo mais abaixo, "MESMO problema..."):
   tentei antes um teto fixo (340px) no lugar do `1fr`, só que isso
   quebrou o caso de MUITOS cards — o Adriano notou que a régua de 1920px
   antes acomodava 6 painéis lado a lado ocupando 100% da linha (sem
   sobra), e com teto fixo passou a caber menos por linha E ainda sobrava
   espaço em branco no fim de cada linha cheia. A distinção real
   `auto-fill` vs. `auto-fit` resolve os 2 casos ao mesmo tempo, sem
   trade-off: `auto-fit` COLAPSA as colunas sem conteúdo e redistribui o
   espaço sobrando só entre as poucas populadas (por isso poucos cards
   esticavam pra longe um do outro); `auto-fill` mantém todas as colunas
   que caberiam (mesmo vazias) como faixas `1fr` de verdade — com poucos
   cards, cada 1 ocupa só a fração da SUA própria coluna (não estica pra
   nenhuma das vazias ao lado, que ficam em branco sem esticar nada); com
   cards suficientes pra preencher a linha toda, todas as colunas viram
   populadas e o resultado é idêntico a antes (edge-to-edge, sem sobra). */
.app-comp-mes-grid.app-comp-mes-grid-largo {
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
}

/* Mais largo ainda que `-largo` — Contratos SSG (12/08/2026), card de
   detalhe por contrato tem MUITO mais conteúdo que os outros usos deste
   grid (nome+badge, limite/mês+trim, barra do trimestre, linha de
   projeção, e ainda 3 células mês-a-mês lado a lado) — 230px espremia
   as 3 células, achado do Adriano: "painéis muito estreitos, vamos
   aumentar pra dar simetria perfeita ao conteúdo". */
.app-comp-mes-grid.app-comp-mes-grid-xl {
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}

/* Com `auto-fit` + `1fr`, quando sobra só 1 card na linha (ex.: depois de
   filtrar pra 1 cliente só) ele estica pra 100% da largura — enorme e sem
   graça (achado do Adriano, 12/08/2026: "fica feio, dá pra limitar o
   tamanho máximo?"). Teto no CARD, não na coluna do grid — a coluna
   continua `1fr` (podendo esticar), mas o conteúdo dentro para de crescer
   depois de 480px, sobrando espaço vazio ao lado em vez de esticar tudo. */
.app-comp-mes-grid.app-comp-mes-grid-xl > .card-panel {
  max-width: 480px;
}

/* MESMO problema, achado de novo em "Em Espera" > Espera por Cliente ·
   Cobrança (18/08/2026, achado do Adriano: filtrando pra 2 clientes, cada
   card "fica com 100% da página" — mesma causa do achado de 12/08/2026
   acima, só que ninguém tinha aplicado o teto pro modificador `-largo`).
   Teto menor que o de `-xl` (card mais simples aqui: nome+total, 2 badges,
   selo de espera, até 2 botões de cobrança — não tem as 3 células
   mês-a-mês que justificam 480px lá). Grid com `justify-items: stretch`
   (padrão) + item mais estreito que a coluna `1fr` já alinha à ESQUERDA
   sozinho (sobra espaço vazio à direita, não precisa de float). */
.app-comp-mes-grid.app-comp-mes-grid-largo > .card-panel {
  max-width: 340px;
}

.app-comp-mes-kpi {
  /* Padding vertical alinhado ao padrão de painel compacto (`.9rem`) —
     mesma revisão do `.app-comp-runrate` acima. */
  text-align: left;
  padding: .9rem 1.1rem;
}

/* Card com altura total da linha do grid (grid já estica os itens da
   mesma linha por padrão, `align-items: stretch`) + o "rodapé" (selo de
   espera, e nos cards de cobrança também os botões) fixado no fundo —
   achado real (07/08/2026, print do Adriano em "Espera por Cliente" e
   "Retornos Devidos"): card com menos conteúdo no meio (sem reincidência,
   badges cabendo em 1 linha em vez de 2, só 1 botão de cobrança) sobrava
   em branco, e o selo/botão de cada card ficava numa altura diferente
   dos vizinhos na mesma linha — nada errado no dado, só a falta desse
   `margin-top:auto` no grupo final. Reusado em "por Atendente" (rodapé =
   selo + reincidência) e "por Cliente" (rodapé = selo + botões). */
.app-comp-mes-kpi-flex {
  display: flex;
  flex-direction: column;
  height: 100%;
}
.app-comp-mes-kpi-rodape {
  margin-top: auto;
}

/* ---------- "Contratos SSG" (12/08/2026, revisão completa pra bater com a
   produção real — ver ContratosSsgService). Prefixo `.app-ctr-*`. ---------- */

/* Os 3 cards de ação (Cobrar agora/Vai estourar/Upsell alvo) reaproveitam
   `.app-stat-card` (já usado em Alertas Críticos) — só ganham clique pra
   filtrar a tabela/cards abaixo, sem reload de página (mesmos dados já
   renderizados, só esconde/mostra via `data-status`/`data-upsell`). */
.app-ctr-acao {
  cursor: pointer;
  transition: transform .1s ease, box-shadow .1s ease;
}
.app-ctr-acao:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-md, 0 4px 12px rgba(0, 0, 0, .15));
}
.app-ctr-acao.ativo {
  outline: 2px solid var(--color-brand);
  outline-offset: -2px;
}
.app-ctr-acao-vazio {
  cursor: default;
  opacity: .7;
}
.app-ctr-acao-vazio:hover {
  transform: none;
  box-shadow: var(--shadow-sm);
}

/* Ícone grande no canto superior direito de cards de ação/stat (nasceu em
   Contratos SSG, 12/08/2026, generalizada em 13/08/2026 pra Contratos BH
   usar o mesmo estilo — nome sem prefixo de tela de propósito). O card-pai
   precisa de `position:relative` (`.app-stat-card` já tem; `.card-panel`
   precisa declarar na hora de usar). */
.app-stat-icone-grande {
  position: absolute;
  top: .9rem;
  right: .7rem;
  font-size: 2.3rem;
  line-height: 1;
  opacity: .85;
}

/* Banner de ação + comparativo Q×Q lado a lado (13/08/2026) — CSS GRID
   em vez de flexbox: `align-items:stretch` do flexbox só garante altura
   igual entre itens da MESMA linha flex, e depende de como o navegador
   calcula flex-basis/flex-grow junto com flex-wrap — na prática o
   Adriano viu os 2 blocos com altura visivelmente diferente ao vivo,
   mesmo com `align-items-stretch` aplicado. Grid resolve isso de forma
   mais direta: toda célula de uma mesma linha de grid tem a MESMA altura
   por padrão (`align-items:stretch` é o default do grid), sem depender
   de cálculo de flex-basis. */
.app-ctr-acoes-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .75rem;
}

@media (max-width: 860px) {
  .app-ctr-acoes-grid {
    grid-template-columns: 1fr;
  }
}

/* Barrinha de progresso mini (célula "Acumulado" da tabela executiva). */
.app-ctr-mini-bar {
  height: 4px;
  background: var(--color-border);
  border-radius: 2px;
  overflow: hidden;
  margin-top: .25rem;
}
.app-ctr-mini-bar-fill {
  height: 100%;
  border-radius: 2px;
}

/* Nota "só chamados do cliente..." — SEMPRE renderizada no HTML (com ou
   sem texto), altura fixa pra caber até 2 linhas (12/08/2026, achado do
   Adriano: card sem chamado de equipe ficava mais BAIXO que os outros —
   quebrava o alinhamento do resto do card pra baixo —, e em telas mais
   estreitas o texto podia quebrar em 2 linhas só nalguns cards, mesmo
   problema de outro jeito). Altura fixa resolve os 2 casos de uma vez:
   card sem texto reserva o espaço vazio mesmo assim; texto que quebra em
   2 linhas cabe exatamente no mesmo espaço que os de 1 linha só. */
.app-ctr-equipe-nota {
  min-height: 1.85rem;
  line-height: 1.3;
}

/* Barra grande de progresso do trimestre (card de detalhe por cliente). */
.app-ctr-trim-bar {
  height: 8px;
  background: var(--color-border);
  border-radius: 4px;
  overflow: hidden;
}
.app-ctr-trim-bar-fill {
  height: 100%;
  border-radius: 4px;
}

/* 3 células mês-a-mês no rodapé do card de detalhe — mesma ideia dos cards
   de mês do Comparativo, só que 3 fixas (sempre o trimestre inteiro) em vez
   de um grid auto-fit. */
.app-ctr-mes-cell {
  flex: 1;
  text-align: center;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: .5rem;
  padding: .4rem .3rem;
}
.app-ctr-mes-cell.atual {
  border-color: var(--color-brand);
}
.app-ctr-mes-cell.warn {
  border-color: color-mix(in srgb, var(--color-warn) 45%, var(--color-border));
}
.app-ctr-mes-cell.crit {
  border-color: color-mix(in srgb, var(--color-danger) 45%, var(--color-border));
}
.app-ctr-mes-cell-num {
  font-weight: 700;
  font-size: .95rem;
}
.app-ctr-mes-cell-lbl {
  font-size: .65rem;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: .03em;
}
.app-ctr-mes-cell-pct {
  font-size: .65rem;
  color: var(--color-text-muted);
}

/* Heatmap de consumo mensal — "Contratos BH" (13/08/2026, porta do heatmap
   embutido na Zona 3 da produção real). 4 faixas (ok/mid/warn/crit) + "na"
   pra mês sem dado — 1 faixa a mais que `.app-ctr-mes-cell` (que só tem
   warn/crit), porque aqui a cor É o dado principal da célula (tabela
   inteira é feita de células coloridas), não um detalhe de borda. */
.app-bh-heat-tab th,
.app-bh-heat-tab td {
  font-size: .78rem;
  vertical-align: middle;
}
.app-bh-heat-cel {
  text-align: center;
  font-weight: 600;
  border-radius: .35rem;
}
.app-bh-heat-cel.ok {
  background: rgba(16, 185, 129, .1);
  color: var(--color-ok);
}
.app-bh-heat-cel.mid {
  background: rgba(14, 165, 233, .12);
  color: var(--color-info);
}
.app-bh-heat-cel.warn {
  background: rgba(245, 158, 11, .14);
  color: var(--color-warn);
}
.app-bh-heat-cel.crit {
  background: rgba(244, 63, 94, .14);
  color: var(--color-danger);
}
.app-bh-heat-cel.na {
  color: var(--color-text-muted);
  font-weight: 400;
}
/* MESMO problema de contraste no tema claro (`var(--color-warn)`/
   `var(--color-danger)` direto como texto, ~2,2:1/~3,8:1 contra fundo
   claro) — mesmos tons já vetados em `.text-warning`/`.app-bh-det-card`
   acima, reaproveitados aqui (achado do Adriano, 14/08/2026, revisando o
   Heatmap de consumo). */
html[data-theme="padrao"] .app-bh-heat-cel.warn {
  color: #b45309;
}
html[data-theme="padrao"] .app-bh-heat-cel.crit {
  color: #be123c;
}

/* Kanban do Funil de Cobrança — "Contratos BH" (13/08/2026), modal
   "Faturar". 5 colunas fixas (identificado/validado/comunicado/faturado/
   pago), scroll horizontal se não couber tudo. */
.app-bh-funil-kanban {
  overflow-x: auto;
  padding-bottom: .5rem;
}
.app-bh-funil-coluna {
  flex: 1 1 220px;
  min-width: 220px;
  /* `color-mix` contra `--color-surface` (não `--color-bg`) — essa coluna
     só aparece DENTRO de um modal, cujo fundo já É `--color-surface`
     (ver `.modal-content`). `--color-bg` chegava perto demais de
     `--color-surface` nos temas escuros (ex. tema "escuro": #0a0a0b vs
     #18181b), lendo como baixo contraste ("péssimo", 14/08/2026, pedido
     do Adriano) — `color-mix` sempre garante uma diferença mínima
     visível em QUALQUER tema, sem precisar de token novo por tema. */
  background: color-mix(in srgb, var(--color-text) 12%, var(--color-surface));
  border: 1px solid color-mix(in srgb, var(--color-text) 28%, var(--color-surface));
  border-radius: .5rem;
  padding: .6rem;
}
.app-bh-funil-coluna-titulo {
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--color-text-muted);
  margin-bottom: .5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.app-bh-funil-coluna-corpo {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  min-height: 2rem;
}
.app-bh-funil-card {
  /* Mais "elevado" que a coluna que o envolve (20% vs 12% acima) — camada
     visível a mais, não só a mesma cor repetida. */
  background: color-mix(in srgb, var(--color-text) 20%, var(--color-surface));
  border: 1px solid color-mix(in srgb, var(--color-text) 34%, var(--color-surface));
  border-radius: .5rem;
  padding: .5rem .6rem;
}

/* Card de detalhe completo por contrato (Renegociar/Renovar, 13/08/2026) —
   grid de células label-em-cima/valor-embaixo, reaproveitado nas várias
   seções (Pool e saldo/Trimestre vigente/Cobrança/Tendência/Rentabilidade). */
/* Tamanho igual ao maior rótulo de seção já usado no app (`h6
   text-uppercase text-muted`, ex. _atendentes_painel.php "Carga atual da
   equipe") — subiu de .72rem (escala de `.app-stat-lbl`, legenda de KPI)
   pra .875rem (escala de `text-muted small`) e depois pra 1rem/peso 500
   (escala de `h6`), 2 pedidos seguidos do Adriano no mesmo dia
   (14/08/2026: "estão discreto demais" → "aumente um pouco mais"). */
.app-bh-det-lbl {
  font-size: 1rem;
  font-weight: 500;
  text-transform: uppercase;
  color: var(--color-text-muted);
  margin: 1.75rem 0 .5rem;
}

/* CSS Grid (não flex) — com `flex:1 1 150px`, uma linha que "quebra" com
   só 1 célula sobrando esticava ela pra 100% da largura (achado do
   Adriano, 14/08/2026: viu isso em "Rentabilidade do projeto", 6
   células = 5+1 na quebra). `auto-fill` cria o MESMO número de colunas
   sempre que a largura do container for a mesma — sobra vira coluna
   vazia, não estica a célula sozinha — e como bônus resolve de vez a
   assimetria entre seções com quantidades diferentes de células (ex.
   "Cobrança e renovação" com 4 vs. "Trimestre vigente" com 5, que antes
   precisava de uma célula invisível manual pra alinhar — não precisa
   mais, todo `.app-bh-det-grid` no mesmo modal calcula a MESMA largura
   de coluna automaticamente). */
.app-bh-det-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: .6rem;
}
/* Cada célula é o próprio box pequeno (não um box geral em volta do
   grid inteiro) — mesma receita de "caixa aninhada" já usada nesta
   telha pelas colunas do Funil de Cobrança (`.app-bh-funil-coluna`),
   14/08/2026, pedido do Adriano ("cada item interno... deve ser um
   box"). */
.app-bh-det-cell {
  /* Rodada 2 (mesmo dia): a caixa fechada (fundo+borda dos 4 lados) ficou
     "feia" pro Adriano, mesmo depois de melhorar o contraste — pediu algo
     "mais delicado", igual ao v1/Vercel: SEM fundo nem borda, só uma
     borda SUPERIOR (mesmo espírito dos cards de KPI do topo da tela,
     `border-top:3px solid <cor>`, só que aqui uma linha neutra por
     célula, não colorida por status — a cor already vem do valor em si,
     `text-danger`/`.text-warning` etc.). Rodada 3: a versão via
     `color-mix` (mais saturada que `--color-border` puro) lia como mais
     "grossa" que as linhas divisórias da tabela "Trimestre a trimestre"
     no mesmo modal, mesmo nos dois sendo 1px — trocado pro MESMO token
     que a tabela usa (`--color-border`, via `--bs-table-border-color`),
     garantindo consistência visual real entre as duas (14/08/2026). */
  border-top: 1px solid var(--color-border);
  padding: .5rem 0 0;
}
/* "Risco de consumo"/"Risco comercial" — painel PADRÃO do app (borda +
   fundo sutil + barra colorida no topo sinalizando status), igual ao
   estilo dos cards de KPI do topo da tela (Faturar/Renegociar/Renovar,
   `card-panel` + `border-top:3px solid <cor>`). Diferente de
   `.app-bh-det-cell` (só linha fina neutra) de propósito — aqui a cor
   da barra JÁ sinaliza o status (crít/atenção/ok), pedido explícito do
   Adriano (14/08/2026) pra usar "nosso estilo de painel padrão". Fundo
   via `color-mix` (não `var(--color-bg)` puro) pela mesma razão dos
   outros componentes deste card: só existe dentro de modal, cujo fundo
   já é `--color-surface`. */
.app-bh-det-risco-card {
  background: color-mix(in srgb, var(--color-text) 6%, var(--color-surface));
  border: 1px solid var(--color-border);
  border-top: 3px solid var(--color-border);
  border-radius: var(--radius);
  padding: .6rem .9rem;
}
.app-bh-det-cell label {
  display: block;
  /* Era `.68rem` — com a densidade "média" deste app (`html[data-
     densidade="media"] { font-size: 13px }`), isso computava ~8,8px na
     tela, ilegível (achado do Adriano, 14/08/2026: "vejo fontes de
     8px... parece pequena demais"). `.78rem` ≈ 10,1px, ainda menor que
     o valor (`strong`, .92rem) mas legível. */
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--color-text-muted);
  margin-bottom: .15rem;
}
.app-bh-det-cell strong {
  font-size: .92rem;
}
/* "Tendência do pool" com dupla projeção lado a lado (Projeção 1 · últimos
   3 meses / Projeção 2 · média do contrato) — porta o layout real do v1
   (`command-center-original/index.html`, `.bh-det-proj-dupla`/`.bh-det-
   proj`, ~linha 1841): a caixa de fora (`.app-bh-det-proj`) tem borda nos
   4 lados (separa os 2 grupos de comparação); as células de dentro
   reaproveitam a MESMA borda-superior das demais células do card (nada
   pra zerar aqui — `.app-bh-det-cell` já cobre isso sozinho). */
.app-bh-det-proj-dupla {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .6rem;
  margin-bottom: .5rem;
}
@media (max-width: 700px) {
  .app-bh-det-proj-dupla {
    grid-template-columns: 1fr;
  }
}
.app-bh-det-proj {
  /* Diferente do `.app-bh-det-cell` (só borda superior) — aqui são só 2
     caixas na tela toda (Projeção 1 vs Projeção 2), então a borda nos 4
     lados ajuda a separar visualmente os 2 grupos de comparação (pedido
     do Adriano, 14/08/2026, depois de aprovar o estilo "só borda
     superior" pras células menores). Sem `background` (só borda) — meio-
     termo entre a caixa cheia da 1ª tentativa e o flat total. */
  border: 1px solid var(--color-border);
  border-radius: .5rem;
  padding: .6rem .75rem;
}
.app-bh-det-proj-titulo {
  font-size: .82rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--color-text-muted);
  margin-bottom: .5rem;
  display: flex;
  align-items: center;
  gap: .4rem;
  flex-wrap: wrap;
}
/* O badge "curto prazo"/"longo prazo" herdaria `.75em` relativo ao
   `.app-bh-det-proj-titulo` (Bootstrap `.badge`) — isso COMPOSTO com um
   pai já pequeno ficava minúsculo (~8px). Tamanho absoluto próprio, não
   relativo, pra não compor pra baixo. */
.app-bh-det-proj-titulo .badge {
  font-size: .72rem;
}
.app-bh-det-proj-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: .5rem .75rem;
}
.app-bh-det-proj-rodape {
  font-size: .85rem;
  color: var(--color-text-muted);
  text-align: center;
  margin: .25rem 0 .5rem;
}
/* Tabela "Trimestre a trimestre" — larguras de coluna padronizadas
   (pedido do Adriano, 14/08/2026), em vez do padrão do Bootstrap de
   deixar cada coluna do tamanho do próprio conteúdo (a coluna
   "Trimestre" ficava mais larga por causa do "◀ atual", desalinhando o
   resto). `table-layout:fixed` obriga todas a respeitarem a largura
   declarada abaixo, independente do texto dentro. */
.app-bh-trim-tabela {
  table-layout: fixed;
}
.app-bh-trim-tabela th:first-child,
.app-bh-trim-tabela td:first-child {
  width: 22%;
}
.app-bh-trim-tabela th:not(:first-child),
.app-bh-trim-tabela td:not(:first-child) {
  width: 15.6%;
}
/* Linha do trimestre atual (`.table-active`, Bootstrap padrão) usava um
   cinza genérico do Bootstrap, sem relação com o resto da paleta do
   card — trocado pro MESMO `color-mix` usado nas outras caixinhas deste
   modal (`.app-bh-det-cell` etc.), pra ficar tudo com um padrão só
   (pedido do Adriano, 14/08/2026). `--bs-table-active-bg` é a variável
   que o Bootstrap consulta pra colorir `tr.table-active` dentro de
   `.table` — sobrescrever ela aqui é mais robusto que brigar com a regra
   `.table-active` original (especificidade). */
.app-bh-trim-tabela.table > tbody > tr.table-active > * {
  --bs-table-active-bg: color-mix(in srgb, var(--color-text) 12%, var(--color-surface));
}
.app-bh-det-motivo {
  background: color-mix(in srgb, var(--color-text) 12%, var(--color-surface));
  border-left: 3px solid var(--color-warn);
  border-radius: .35rem;
  padding: .5rem .75rem;
  font-size: .85rem;
}
.app-bh-det-acao {
  background: color-mix(in srgb, var(--color-text) 12%, var(--color-surface));
  border-radius: .35rem;
  padding: .5rem .75rem;
}
/* "Baseline Contratual" — hero de destaque no topo do card (porta o
   estilo do v1, `.bh-det-baseline*`, mas com tokens do tema em vez de
   rgba fixo, pra funcionar nos 4 temas — o v1 só tinha 1 tema escuro
   fixo). Sem a variante "portal a validar" do v1 (não existe mais
   comparação manual-vs-portal no v2, ver comentário no PHP). */
/* Estilo neutro/discreto (rodada 2, mesmo dia) — igual ao `.app-hero`
   usado no topo de outras telas (gradiente sutil, sem tingimento de
   cor): o Adriano achou o tom verde chamativo demais pra um hero
   puramente informativo (não é um sinal de status). Gradiente via
   `color-mix` (não os tokens `--color-surface`/`--color-bg` direto,
   IGUAIS ao `.app-hero` original) — esse card só existe dentro de
   modal, cujo fundo já É `--color-surface`; usar esses 2 tokens aqui
   repetiria o mesmo bug de contraste já corrigido antes nos outros
   componentes deste arquivo. */
.app-bh-det-baseline {
  padding: .75rem .9rem;
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--color-text) 5%, var(--color-surface)),
    color-mix(in srgb, var(--color-text) 11%, var(--color-surface)),
    color-mix(in srgb, var(--color-text) 5%, var(--color-surface)));
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}
.app-bh-det-baseline-hd {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .82rem;
  font-weight: 700;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: .03em;
  margin-bottom: .6rem;
}
.app-bh-det-baseline-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: .6rem;
}
.app-bh-det-baseline-grid .app-bh-det-cell {
  border-top: none;
  padding: 0;
}
/* `.text-danger`/`.text-warning`/`.text-success` do Bootstrap usam a
   paleta PADRÃO dele (`--bs-danger` #dc3545 etc.), nunca remapeada pro
   semáforo próprio do app (`--color-danger` #f43f5e/`--color-warn`
   #f59e0b/`--color-ok` #10b981 — usado em `bhCorStatus()`, badges,
   heatmap etc.). O vermelho do Bootstrap é mais "sujo"/menos legível em
   fundo escuro (achado do Adriano, 14/08/2026: "essa fonte vermelha ta
   muito ruim de ler") — em vez de remapear `.text-danger` pro app
   INTEIRO (mudança grande, fora do escopo pedido), o fix fica só
   dentro do card de detalhe do BH (`.app-bh-det-card`), onde essas
   classes aparecem dezenas de vezes. `!important` necessário porque as
   próprias classes do Bootstrap já usam `!important`. */
.app-bh-det-card .text-danger { color: var(--color-danger) !important; }
.app-bh-det-card .text-warning { color: var(--color-warn) !important; }
.app-bh-det-card .text-success { color: var(--color-ok) !important; }
/* --color-danger/warn/ok direto como TEXTO funciona bem nos 3 temas
   escuros, mas no tema "padrao" (claro) esses mesmos tons têm contraste
   baixo contra fundo quase-branco (mesmo problema geral documentado
   acima pro `.text-warning` cru do Bootstrap) — `--color-warn`
   (#f59e0b) contra branco dá só ~2,2:1. Reaproveita os MESMOS tons
   escuros já vetados nesse tema pra warning/danger/ok (#b45309/#be123c/
   #047857 — ver `.app-ticket-age`/`.text-warning` acima), sem inventar
   cor nova. */
html[data-theme="padrao"] .app-bh-det-card .text-danger { color: #be123c !important; }
html[data-theme="padrao"] .app-bh-det-card .text-warning { color: #b45309 !important; }
html[data-theme="padrao"] .app-bh-det-card .text-success { color: #047857 !important; }

/* `.app-alerta-aviso` é um componente GLOBAL (Contratos SSG também usa,
   ver comentário mais abaixo) dimensionado pra banner de página inteira
   — dentro deste card, ao lado de rótulos de .68-1rem, ficava grande
   demais (achado do Adriano, 14/08/2026: "mensagens de alerta muito
   grandes comparadas ao resto da tela"). Reduzido só AQUI (escopado em
   `.app-bh-det-card`), sem tocar no tamanho usado nas outras telas. */
.app-bh-det-card .app-alerta-aviso {
  padding: .5rem .75rem;
  font-size: .85rem;
}
.app-bh-det-card .app-alerta-aviso i {
  font-size: .95rem;
}

/* Variantes de cor do banner de ação (`.app-alerta-aviso` só tinha o tom
   âmbar/warn até aqui — Contratos SSG precisa também de crítico/vermelho e
   de tranquilo/verde, conforme o pior status do trimestre selecionado). */
.app-alerta-aviso.crit {
  background: rgba(244, 63, 94, .12);
  border-color: rgba(244, 63, 94, .35);
}
.app-alerta-aviso.crit i {
  color: var(--color-danger);
}
.app-alerta-aviso.ok {
  background: rgba(16, 185, 129, .12);
  border-color: rgba(16, 185, 129, .35);
}
.app-alerta-aviso.ok i {
  color: var(--color-ok);
}

/* Tooltip que segue o cursor (assets/js/tooltips.js) — substitui o nativo
   do navegador E o Bootstrap Tooltip clássico (esse ancorava no
   ELEMENTO, não no ponteiro — ficava longe do cursor em elemento largo).
   `position:fixed` porque o JS usa clientX/clientY (relativo à viewport,
   não precisa somar scroll). Cor fixa (não muda por tema) — mesmo visual
   escuro que o Bootstrap Tooltip já tinha, só a posição mudou. */
.app-tooltip-cursor {
  position: fixed;
  z-index: 2000;
  background: rgba(20, 20, 24, .95);
  color: #fff;
  font-size: .78rem;
  line-height: 1.35;
  padding: .4rem .7rem;
  border-radius: .4rem;
  /* Linha do ícone de saúde de sync é bem comprida (ex.: "• Detalhe por
     analista — BH × Analista • último: 09/08/2026 21:00 · próximo: às
     22:00", ~85 caracteres) — 460px ainda quebrava no meio (09/08/2026,
     2ª rodada: o Adriano mandou print confirmando). 620px cabe a linha
     inteira sem quebra. */
  max-width: 620px;
  /* `\n` dentro do texto vira quebra de linha de verdade (ex.: ícone de
     saúde de sync com 1 linha por tarefa agendada) — antes só dava pra
     tooltip de 1 linha só, `white-space` normal colapsa `\n` (09/08/2026). */
  white-space: pre-line;
  pointer-events: none;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity .1s ease, transform .1s ease;
  box-shadow: 0 4px 16px rgba(0, 0, 0, .35);
}

.app-tooltip-cursor.show {
  opacity: 1;
  transform: translateY(0);
}

/* Tooltip flutuante dos sparklines (assets/js/charts.js) — canvas tem só
   28px de altura, então o tooltip nativo do Chart.js (desenhado dentro do
   próprio canvas) ficava cortado/atrás da linha da próxima linha da tabela.
   position:fixed + z-index alto escapa desse limite. */
.app-chart-tooltip {
  position: fixed;
  z-index: 2100;
  background: rgba(20, 20, 24, .95);
  color: #fff;
  font-size: .7rem;
  line-height: 1.35;
  padding: .35rem .6rem;
  border-radius: .4rem;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, -115%);
  transition: opacity .1s ease;
  box-shadow: 0 4px 16px rgba(0, 0, 0, .35);
}

.app-chart-tooltip-title {
  font-weight: 600;
  margin-bottom: .1rem;
}

/* ---------- TabelaCliente (13/08/2026) — ordenar/paginar/filtrar 100% em
   memória no navegador (`assets/js/tabela-cliente.js`), porta do SmartTable
   do apontamentos-v2. Motivo: `ListagemService` fazia round-trip ao
   servidor a cada clique, reprocessando toda a agregação da tela (lento,
   ~1s, em telas com chamada externa por trás — Carteira/Contratos BH).
   A paginação (`.st-pagination*`) REUSA as classes já existentes de
   `ListagemService::paginacaoHtml()` — mesmo visual, sem CSS duplicado. */
.tc-th-label {
  display: inline-block;
  /* Reserva espaço suficiente pro funil E pro indicador de ordenação
     (quando ATIVO nessa coluna — só nesse caso ele ocupa espaço, ver
     `.tc-sort-indicator` abaixo) — prioridade decidida pelo Adriano
     (13/08/2026): "overflow do título e deixar os ícones sempre
     visíveis fica melhor" — o RÓTULO trunca com reticências antes de
     deixar qualquer ícone ficar sem espaço/cortado. */
  max-width: calc(100% - 1.5rem);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: middle;
}

.tc-th-label-locked {
  max-width: none;
}

.tc-sortable {
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  /* Rede de segurança (13/08/2026) — `.tc-th-label` já reserva espaço
     pros ícones (`max-width` acima) e trunca o rótulo antes deles, mas
     isso sozinho não impede um vazamento visual se, por algum motivo,
     algo ainda escapar da largura da coluna (achado real do Adriano: sem
     isso, o excedente vazava por cima da coluna vizinha). */
  overflow: hidden;
}

/* Só ocupa espaço/aparece na coluna ATIVAMENTE ordenada (ganha a classe
   `bi-caret-up-fill`/`bi-caret-down-fill` só nesse caso) — mesmo padrão
   do antigo `ListagemService::cabecalho()`, que só desenhava esse ícone
   pra coluna com `ordenarPor` ativo. Sem isso, um `<i>` vazio (sem
   nenhum glifo) ainda reservava a própria margem em TODA coluna
   ordenável, apertando ainda mais colunas estreitas com largura fixa. */
.tc-sort-indicator {
  display: none;
  font-size: .7rem;
  color: var(--color-text-muted);
}

.tc-sort-indicator.bi-caret-up-fill,
.tc-sort-indicator.bi-caret-down-fill {
  display: inline;
  margin-left: .2rem;
  color: var(--color-brand);
}

.tc-filter-icon {
  border: none;
  background: none;
  padding: 0;
  margin-left: .25rem;
  font-size: .75rem;
  color: var(--color-text-muted);
  vertical-align: middle;
  line-height: 1;
}

.tc-filter-icon:hover {
  color: var(--color-brand);
}

.tc-filter-icon.active {
  color: var(--color-warn);
}

.tc-filter-icon.active.negated {
  color: var(--color-danger);
}

.tc-filter-popover {
  display: none;
  position: fixed;
  z-index: 2000;
  min-width: 220px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: .5rem;
  box-shadow: var(--shadow-md);
  padding: .75rem;
}

.tc-filter-popover.show {
  display: block;
}

.tc-filter-popover-check {
  display: flex;
  align-items: center;
  gap: .4rem;
  font-size: .8rem;
  color: var(--color-text-muted);
  margin-top: .5rem;
  font-weight: 400;
}

/* Filtro MULTISELECT (26/08/2026) — lista de checkboxes no lugar do
   `<select>` de escolha única, pra colunas de valor fechado
   (`data-filtro-opcoes`) onde faz sentido marcar mais de 1 (ex.:
   "Situação"/"Com quem está" em "Seus chamados" — pedido do Adriano).
   Rolagem própria pra não estourar o popover em colunas com muitas
   opções (ex.: "Aberto Por", 1 por pessoa). */
.tc-filter-popover-multi {
  max-height: 180px;
  overflow-y: auto;
}

.tc-filter-popover-opcao {
  display: flex;
  align-items: center;
  gap: .4rem;
  font-size: .8rem;
  padding: .15rem 0;
  font-weight: 400;
}

.tc-filter-popover-actions {
  display: flex;
  gap: .5rem;
  margin-top: .6rem;
}

.tc-filter-popover-actions .btn {
  flex: 1;
}

.tc-toolbar-row {
  margin-bottom: .5rem;
}

.tc-global-search {
  width: auto;
}

.tc-cell-wrap td {
  white-space: normal;
}

/* ---------- Sombra de scroll horizontal (13/08/2026) — avisa que existe
   mais conteúdo pra rolar de um lado ou de outro de `.table-responsive`
   (`assets/js/scroll-shadow.js`). `box-shadow: inset` (não borda/elemento
   novo). Precisa das 3 regras: 2 sozinhas + 1 combinada (quando os dois
   lados têm o que rolar ao mesmo tempo — no meio do scroll — os 2
   box-shadow têm que estar na MESMA declaração, CSS não empilha
   `box-shadow` de regras diferentes no mesmo elemento).
   Sempre ESCURECE (`black`), nunca usa `--color-text` — correção real
   (13/08/2026, achado do Adriano: "a sombra não combinou com o tema"):
   nos 3 temas escuros deste app, `--color-text` é uma cor CLARA (texto
   legível sobre fundo escuro) — misturar com ela produzia um brilho
   CLARO sobre fundo escuro, parecendo um borrão/reflexo em vez de sombra.
   Escurecer sempre é o padrão real usado por Gmail/Notion/GitHub, nos
   dois temas — sombra sempre lê como "sombra", nunca como um brilho
   estranho. */
.table-responsive.has-scroll-shadow-left:not(.has-scroll-shadow-right) {
  box-shadow: inset 12px 0 8px -8px rgba(0, 0, 0, .14);
}

.table-responsive.has-scroll-shadow-right:not(.has-scroll-shadow-left) {
  box-shadow: inset -12px 0 8px -8px rgba(0, 0, 0, .14);
}

.table-responsive.has-scroll-shadow-left.has-scroll-shadow-right {
  box-shadow:
    inset 12px 0 8px -8px rgba(0, 0, 0, .14),
    inset -12px 0 8px -8px rgba(0, 0, 0, .14);
}

/* Coluna de texto longo — single-line com reticências por padrão,
   alternável pra visão expandida por um botão no cabeçalho (20/08/2026,
   "Descrição" de "Atividades Realizadas" no Relatório Cliente, pedido do
   Adriano: texto longo deixava a tabela larga/alta demais por padrão).
   O toggle mexe numa classe na TABELA inteira (não por linha) — afeta a
   coluna inteira de uma vez, não célula a célula (ver `alternarColunaExpandida()`
   em `listagem.js`). Reusável em qualquer tabela com 1 coluna de texto
   livre longo (`<td class="app-col-truncar">` + o botão no `<th>`). */
.app-col-truncar {
  max-width: 320px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

table.app-col-expandida .app-col-truncar {
  /* Antes `none` — sem teto, a coluna podia crescer demais e espremer o
     resto da tabela (achado do Adriano, 21/08/2026: "não pode crescer de
     mais, dá pra limitar um pouco?"). 520px dá espaço real pro texto
     multi-linha sem dominar a largura da tabela. */
  max-width: 520px;
  /* `pre-line` (não `normal`) — achado do Adriano, 20/08/2026: a descrição
     tem quebra de linha DE VERDADE (`\n` cru, já visível no tooltip nativo
     do `title`), mas `white-space:normal` trata `\n` como espaço em
     branco comum e ignora a quebra, virando 1 parágrafo corrido. `pre-line`
     preserva a quebra real e ainda deixa o texto dar wrap normalmente. */
  white-space: pre-line;
  overflow: visible;
  text-overflow: clip;
}

/* Chips de status ("Todos"/"Em aberto"/etc. em "Seus chamados",
   26/08/2026) — antes o NÚMERO (badge) ia colorido por categoria, o que
   brigava com o fundo sólido do chip ativo (achado do Adriano: "não
   combina com os numéricos coloridos internos"). Cor movida pro botão:
   faixa na borda esquerda (`style="border-left"` inline, cor por
   categoria vinda de `$rcChips[...]['cor']`) — o número agora é sempre
   neutro (Bootstrap subtle cinza). `border-left` é setado inline no
   próprio `<button>`, então `.app-chip-ativo` não pode mexer em
   `border-color` (mexeria nos 4 lados, sobrescrevendo a faixa) — o
   estado ativo vira só fundo suave + negrito. */
.app-chip-ativo {
  background: var(--color-brand-soft) !important;
  font-weight: 600;
}
