/* ===========================
   PAYT SUPORTE — Design System
   Identity: Payt brand · Plus Jakarta Sans
   =========================== */

/* Fontes NÃO vêm por @import aqui (era uma requisição encadeada que travava a pintura e pedia 7 famílias):
   cada <head> carrega só as que usa por <link> — partials/sidebar.ejs, partials/auth-estilo.ejs, error.ejs. */

/* ===== Light theme (default) ===== */
:root {
  /* Brand — Payt palette */
  --brand:        #e47c24;
  --brand-rgb:    228, 124, 36;   /* p/ rgba(var(--brand-rgb), a) */
  --brand-dark:   #884710;
  --brand-deeper: #763d0e;
  --brand-light:  #fcc48c;
  --brand-warm:   #dcccbc;
  --brand-dim:    rgba(228,124,36,.1);
  --brand-dim2:   rgba(228,124,36,.06);
  --brand-border: rgba(228,124,36,.28);
  --chart-rgb:    210, 87, 15;    /* linha principal dos gráficos — lido por public/js/p-charts.js */

  /* Surfaces — warm off-white */
  --bg:           #faf8f5;
  --bg-2:         #ffffff;
  --surface:      #ffffff;
  --surface-2:    #f7f3ee;
  --surface-3:    #ede8e0;

  /* Borders — warm beige */
  --border:       #e0d8cc;
  --border-2:     #cfc5b4;
  --border-3:     #bfb09a;

  /* Text */
  --text:         #1a1410;
  --text-2:       #4a3f35;
  --text-3:       #8a7a6a;
  --text-4:       #b8aba0;
  /* Alias do portal-gestão (lá o texto principal é --text-1). Mesmo elemento do html.dark,
     então resolve contra o --text do tema ativo. */
  --text-1:       var(--text);

  /* Semantic */
  --success:         #16a34a;
  --success-bg:      #f0fdf4;
  --success-border:  #bbf7d0;
  --warning:         #c2800a;
  --warning-bg:      #fefce8;
  --warning-border:  #fde68a;
  --danger:          #dc2626;
  --danger-bg:       #fef2f2;
  --danger-border:   #fecaca;
  /* Vermelho SÓLIDO do .btn-danger (confirmar dentro do modal destrutivo). Fixo nos dois temas:
     o --danger do escuro é um vermelho claro (#f87171) e com texto branco em cima ficava ilegível. */
  --danger-solid:       #dc2626;
  --danger-solid-hover: #b91c1c;
  /* Verde SÓLIDO do .btn-success (confirmação positiva de peso). Fixo nos dois temas pelo mesmo
     motivo do --danger-solid: o --success do escuro é claro demais para texto branco. */
  --success-solid:       #15803d;
  --success-solid-hover: #166534;
  --info:            #2563eb;
  --info-bg:         #eff6ff;
  --info-border:     #bfdbfe;
  /* Grafite do .btn-dark — preto suavizado, quente como o resto da paleta (nunca #000) */
  --graphite:        #4a4038;
  --graphite-dark:   #372f29;
  --purple:          #7c3aed;
  --purple-bg:       #f5f3ff;
  --purple-border:   #ddd6fe;
  /* Laranja = crítico/urgente (âmbar --warning = atenção). Mesmos valores do portal-gestão. */
  --purple-solid:    #6d28d9;   /* fundo sólido roxo com texto --on-cor (igual nos dois temas) */
  --orange:          #ea580c;
  --orange-bg:       #fff7ed;
  --orange-border:   #fed7aa;
  /* Fundo sólido de aviso com texto branco (toast de alerta). Igual nos dois temas. */
  --warning-solid:   #b45309;

  /* Layout */
  --sidebar-w: 220px;
  --topbar-h:  52px;
  --radius:    5px;
  --radius-md: 8px;
  --radius-lg: 11px;

  --shadow-xs: 0 1px 2px rgba(0,0,0,.04);
  --shadow-sm: 0 1px 3px rgba(0,0,0,.07), 0 1px 2px rgba(0,0,0,.04);
  --shadow:    0 4px 8px rgba(0,0,0,.07), 0 1px 3px rgba(0,0,0,.05);
  --shadow-md: 0 10px 20px rgba(0,0,0,.08), 0 4px 8px rgba(0,0,0,.05);
  --shadow-lg: 0 20px 40px rgba(0,0,0,.1),  0 8px 16px rgba(0,0,0,.06);

  /* Cor SOBRE cor: texto/ícone em cima de fundo sólido (brand, danger, success…) — igual nos dois temas.
     `--escuro` é a base de escurecer/sombrear por color-mix(in srgb, var(--escuro) 18%, transparent);
     nunca usar nenhum dos dois como texto ou fundo de página (isso é --text/--surface). */
  --on-cor:       #ffffff;
  --escuro:       #000000;
  --overlay:      rgba(0,0,0,.45);   /* fundo atrás de modal/gaveta */
  --overlay-forte: rgba(0,0,0,.6);   /* modal sobre modal */

  --font: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, sans-serif;

  /* Sidebar */
  --sidebar-bg:          #e47c24;
  --sidebar-text:        rgba(255,255,255,0.85);
  --sidebar-text-muted:  rgba(255,255,255,0.80);
  --sidebar-hover-bg:    rgba(255,255,255,0.14);
  --sidebar-active-bg:   rgba(255,255,255,0.24);
  --sidebar-active-text: #ffffff;
  --sidebar-border:      rgba(0,0,0,0.12);
  --sidebar-divider:     rgba(255,255,255,0.20);

  /* Seletor "Operação | CRM" — cores da pele do CRM (canvas da diretoria) */
  --sys-trilho:  #F4ECE5;
  --sys-ink:     #2A1E17;
  --sys-crm:     #FF6B1A;
  --sys-crm-bg:  #FFEFE3;
  --sys-on-cor:  #ffffff;
}

/* ===== Dark theme ===== */
html.dark {
  --sys-trilho:  #211B18;
  --sys-ink:     #F3ECE6;
  --sys-crm:     #FF7A2E;
  --sys-crm-bg:  #3A2316;
  --sys-on-cor:  #1A1310;
  --bg:           #1c1c1e;
  --bg-2:         #242426;
  --surface:      #2c2c2e;
  --surface-2:    #363638;
  --surface-3:    #424244;

  --border:       rgba(255,255,255,.13);
  --border-2:     rgba(255,255,255,.20);
  --border-3:     rgba(255,255,255,.28);

  --text:         #f2f2f2;
  --text-2:       #d0d0d0;
  --text-3:       #a0a0a0;
  --text-4:       #686868;

  /* Só vira texto (título de card, posição do ranking): no escuro o marrom some no fundo */
  --brand-deeper: #fcc48c;

  --success:         #4ade80;
  --success-bg:      rgba(74,222,128,.1);
  --success-border:  rgba(74,222,128,.2);
  --warning:         #fbbf24;
  --warning-bg:      rgba(251,191,36,.1);
  --warning-border:  rgba(251,191,36,.2);
  --danger:          #f87171;
  --danger-bg:       rgba(248,113,113,.1);
  --danger-border:   rgba(248,113,113,.2);
  --danger-solid:       #dc2626;
  --danger-solid-hover: #b91c1c;
  --success-solid:       #15803d;
  --success-solid-hover: #166534;
  --info:            #60a5fa;
  --info-bg:         rgba(96,165,250,.1);
  --info-border:     rgba(96,165,250,.2);
  /* No escuro o grafite tem que ficar ACIMA do fundo da linha, senão o botão vira um buraco */
  --graphite:        #55555a;
  --graphite-dark:   #66666b;
  --purple:          #c4b5fd;
  --purple-bg:       rgba(196,181,253,.1);
  --purple-border:   rgba(196,181,253,.2);
  --orange:          #fb923c;
  --orange-bg:       rgba(251,146,60,.12);
  --orange-border:   rgba(251,146,60,.25);
  --warning-solid:   #b45309;

  --shadow-xs: 0 1px 2px rgba(0,0,0,.3);
  --shadow-sm: 0 2px 4px rgba(0,0,0,.4);
  --shadow:    0 4px 12px rgba(0,0,0,.5);
  --shadow-md: 0 8px 24px rgba(0,0,0,.6);
  --shadow-lg: 0 16px 40px rgba(0,0,0,.7);

  /* Sidebar */
  --sidebar-bg:          #c56110;
  --sidebar-text:        rgba(255,255,255,0.88);
  --sidebar-text-muted:  rgba(255,255,255,0.80);
  --sidebar-hover-bg:    rgba(255,255,255,0.13);
  --sidebar-active-bg:   rgba(255,255,255,0.22);
  --sidebar-active-text: #ffffff;
  --sidebar-border:      rgba(0,0,0,0.18);
  --sidebar-divider:     rgba(255,255,255,0.18);
}

/* ===== Reset ===== */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { font-size: 14px; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
body { font-family: var(--font); background: var(--bg); color: var(--text); line-height: 1.5; transition: background .2s, color .2s; }
/* Fundo da área de trabalho branco no tema claro (piloto aprovado em /gestao/vendas, 01/10/2026):
   os cards se separam pela borda e pelo cabeçalho tintado, não pelo creme do fundo. */
html:not(.dark) body { background: var(--bg-2); }
a { color: inherit; text-decoration: none; }
button { font-family: inherit; cursor: pointer; border: none; background: none; }
img { max-width: 100%; }

/* ===== App Shell ===== */
.app { display: flex; min-height: 100vh; }

/* ===== Sidebar ===== */
.sidebar {
  width: var(--sidebar-w);
  background: var(--bg-2);
  border-right: 1px solid var(--border);
  display: flex; flex-direction: column;
  position: fixed; top: 0; left: 0; bottom: 0;
  z-index: 100; overflow-x: hidden; overflow-y: auto;
  transition: background .2s, border-color .2s, width .2s ease, transform .25s ease;
}

/* Botão hamburguer (só existe visualmente ≤768px — ver media query) e o
   backdrop do drawer de navegação mobile. Abaixo do z-index do sidebar (100),
   acima da topbar (50). */
/* seletor com tag (não só classe) pra especificidade bater a de .btn-icon
   (inline-flex) independente da ordem das regras no arquivo */
button.mobile-menu-btn { display: none; }
.sidebar-mobile-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.4); z-index: 90; }

.sidebar-brand {
  height: var(--topbar-h);
  display: flex; align-items: center;
  padding: 0 16px; gap: 10px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.sidebar-brand .brand-logo {
  width: 28px; height: 28px;
  border-radius: 7px;
  background: var(--brand);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  box-shadow: 0 1px 4px rgba(232,120,32,.35);
}
.sidebar-brand .brand-logo svg {
  width: 15px; height: 15px;
  stroke: #fff; fill: none; stroke-width: 2.2;
  stroke-linecap: round; stroke-linejoin: round;
}
.sidebar-brand .brand-name {
  font-family: 'Bebas Neue', 'Plus Jakarta Sans', sans-serif;
  font-size: 17px; font-weight: 400; color: var(--text); letter-spacing: .5px;
  text-transform: uppercase; line-height: 1;
}
.sidebar-brand .brand-tag {
  font-size: 9px; color: var(--text-4); font-weight: 600;
  letter-spacing: .8px; text-transform: uppercase; margin-top: 2px;
}

.sidebar-nav { flex: 1; padding: 4px; overflow-y: auto; }
.sidebar-section { margin-bottom: 1px; }
.sidebar-section-label {
  font-size: 10px; font-weight: 700; color: var(--text-4);
  text-transform: uppercase; letter-spacing: 1px;
  padding: 7px 10px 3px; white-space: nowrap;
}

.nav-item {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 10px; border-radius: var(--radius-md);
  color: var(--text-3); font-size: 12.5px; font-weight: 500;
  transition: background .1s, color .1s;
  white-space: nowrap; margin-bottom: 1px;
}
.nav-item:hover { background: var(--surface-2); color: var(--text); }
.nav-item.active { background: var(--brand-dim); color: var(--brand-dark); font-weight: 600; }
html.dark .nav-item.active { color: var(--brand); }
.nav-item.active .nav-icon { color: var(--brand); }

.nav-icon {
  width: 17px; height: 17px; flex-shrink: 0;
  color: var(--text-4); display: flex; align-items: center; justify-content: center;
  transition: color .1s;
}
.nav-item:hover .nav-icon { color: var(--text-3); }
.nav-item.active .nav-icon { color: var(--brand); }
.nav-icon svg { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }

.nav-badge {
  margin-left: auto; background: var(--danger); color: #fff;
  font-size: 10px; font-weight: 700; padding: 1px 5px;
  border-radius: 99px; min-width: 16px; text-align: center; line-height: 15px;
}

.sidebar-footer {
  padding: 8px 10px; border-top: 1px solid var(--border); flex-shrink: 0;
}
.sidebar-user {
  display: flex; align-items: center; gap: 9px;
  padding: 6px 6px; border-radius: var(--radius-md); transition: background .1s;
}
.sidebar-user:hover { background: var(--surface-2); }
.sidebar-user .avatar {
  width: 28px; height: 28px; border-radius: 99px;
  background: var(--brand-dim); color: var(--brand);
  display: flex; align-items: center; justify-content: center;
  font-size: 11.5px; font-weight: 700; flex-shrink: 0;
  border: 1.5px solid var(--brand-border);
  overflow: hidden; position: relative;
}
.sidebar-user .avatar-clickable { cursor: pointer; }
.sidebar-user .avatar-overlay {
  display: none; position: absolute; inset: 0; border-radius: 99px;
  background: rgba(0,0,0,.5); color: #fff;
  align-items: center; justify-content: center;
}
.sidebar-user .avatar-clickable:hover .avatar-overlay { display: flex; }
.sidebar-user .user-info { min-width: 0; flex: 1; }
/* Nome/foto abrem o menu do perfil (Sistema, foto, sair) — docs/design-system.md, 14/10/2026 */
.sidebar-user .sb-user-btn { cursor: pointer; border-radius: var(--radius); }
.sidebar-user .sb-user-btn:hover .user-name { text-decoration: underline; text-underline-offset: 2px; }
.sb-user-pop { z-index: 1100; }
.sidebar-user .sb-user-more { border: none; background: none; cursor: pointer; font: inherit; }
.sidebar-user .sb-user-more svg { stroke-width: 2.5; }
.sidebar-user .user-name {
  font-size: 12.5px; font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sidebar-user .user-role { font-size: 10.5px; color: var(--text-4); font-weight: 500; text-transform: capitalize; }
.sidebar-user .btn-logout {
  padding: 4px; border-radius: var(--radius); color: var(--text-4);
  transition: background .1s, color .1s;
  flex-shrink: 0; display: flex; align-items: center; justify-content: center;
}
.sidebar-user .btn-logout:hover { background: var(--surface-3); color: var(--text-3); }
.sidebar-user .btn-logout svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }

/* ===== Main ===== */
.main { margin-left: var(--sidebar-w); flex: 1; min-width: 0; display: flex; flex-direction: column; transition: margin-left .2s ease; }

/* ===== Topbar ===== */
.topbar {
  height: var(--topbar-h); background: var(--bg-2);
  border-bottom: 2px solid var(--brand);
  display: flex; align-items: center; padding: 0 22px; gap: 12px;
  position: sticky; top: 0; z-index: 50;
  transition: background .2s, border-color .2s;
}
/* `overflow:hidden` aqui também: sem ele a caixa de dentro corta o PRÓPRIO conteúdo, mas nada
   impede que ela mesma seja mais larga que o `.topbar-left` e desenhe para fora. Medido a 390px:
   com o `.topbar-left` em 33px, a caixa do breadcrumb ainda ia de 61 a 155. */
.topbar-left { flex: 1; min-width: 0; overflow: hidden; display: flex; align-items: center; gap: 10px; }
.topbar-left-text { min-width: 0; flex: 1 1 0; overflow: hidden; }
/* 🚫 `min-width:0` sozinho deixa a caixa ENCOLHER, não faz o conteúdo caber: o breadcrumb é
   `display:flex` e o título é texto, então sem `overflow:hidden` os dois DESENHAM PARA FORA
   do `.topbar-left` e vão parar por baixo da busca da topbar — ilegíveis, e ainda roubando o
   clique de quem está embaixo. Medido a 390px: com o `.topbar-left` em 33px, "Paytcall › CRM ›
   Relatórios" seguia desenhando até 210px, coberto pelos botões da busca.
   O par `overflow:hidden` + `text-overflow:ellipsis` + `white-space:nowrap` é o que faz CORTAR
   com reticências em vez de vazar. Não dá erro: erra calado, só na tela estreita. */
.topbar-breadcrumb { font-size: 11.5px; color: var(--text-4); display: flex; align-items: center; gap: 4px; margin-bottom: 4px; min-width: 0; overflow: hidden; white-space: nowrap; }
/* Quem cede é a ÚLTIMA folha (a página atual, um <span>): os níveis de cima são links de
   navegação e encurtá-los antes tiraria o caminho de volta. */
.topbar-breadcrumb > * { flex-shrink: 0; }
.topbar-breadcrumb > *:last-child { flex-shrink: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.topbar-breadcrumb a { color: var(--text-3); transition: color .1s; }
.topbar-breadcrumb a:hover { color: var(--brand); }
.topbar-breadcrumb .sep { color: var(--text-4); }
.topbar-title { font-size: 14px; font-weight: 600; color: var(--text); letter-spacing: -.2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* No celular o `.topbar-left` fica com ~33px (a busca tem piso de 165px e o par de botões dela
   não cede). Caminho nenhum cabe nisso: cortar "Paytcall › CRM › Relatórios" com reticências
   daria "P…" — reticência sem informação. Então ≤640 some o CAMINHO e fica só a FOLHA, que é
   onde a pessoa está. Ela já tem ellipsis pela regra acima.
   🚫 Esconder por TIPO (`> a`) não serve: nível do meio sem `href` também é span, e escapava do
   `display:none` comendo o espaço da folha. Some tudo e a folha se declara com `crumb-leaf`. */
@media (max-width: 640px) {
  .topbar-breadcrumb > * { display: none; }
  .topbar-breadcrumb > .crumb-leaf, .topbar-breadcrumb > *:last-child { display: block; }
  .topbar-breadcrumb > .sep:last-child { display: none; }
  .topbar-breadcrumb { margin-bottom: 2px; }
}
.topbar-actions { display: flex; align-items: center; gap: 4px; }

/* Topbar Polaris centrado */
.topbar-polaris {
  height: var(--topbar-h); background: var(--bg-2);
  border-bottom: 1px solid var(--border);
  display: grid; grid-template-columns: 1fr auto 1fr;
  align-items: center; padding: 0 16px; gap: 12px;
  position: sticky; top: 0; z-index: 50;
  transition: background .2s, border-color .2s;
}
.topbar-polaris .tp-left  { display: flex; align-items: center; gap: 8px; white-space: nowrap; min-width: 0; overflow: hidden; }
.topbar-polaris .tp-center { display: flex; justify-content: center; }
.topbar-polaris .tp-right  { display: flex; align-items: center; gap: 4px; justify-content: flex-end; white-space: nowrap; }

.topbar-search-wrap { position: relative; width: 100%; max-width: 380px; }
.topbar-search-wrap .search-icon {
  position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  width: 14px; height: 14px; color: var(--text-4); pointer-events: none;
}
.topbar-search-wrap .search-icon svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.topbar-search-wrap input {
  width: 100%; padding: 6px 12px 6px 32px;
  border: 1px solid var(--border); border-radius: var(--radius-md);
  font-size: 12.5px; font-family: var(--font);
  background: var(--surface-2); color: var(--text);
  outline: none; transition: border-color .12s, box-shadow .12s, background .2s;
}
.topbar-search-wrap input:focus {
  border-color: var(--brand-border);
  box-shadow: 0 0 0 3px var(--brand-dim2); background: var(--surface);
}
.topbar-search-wrap input::placeholder { color: var(--text-4); }

/* Dark mode toggle */
.theme-toggle {
  display: flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: var(--radius-md);
  color: var(--text-3); transition: background .1s, color .1s;
  cursor: pointer; border: 1px solid var(--border);
  background: var(--surface-2);
}
.theme-toggle:hover { background: var(--surface-3); color: var(--text); }
.theme-toggle svg { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.theme-toggle .icon-sun  { display: none; }
.theme-toggle .icon-moon { display: block; }
html.dark .theme-toggle .icon-sun  { display: block; }
html.dark .theme-toggle .icon-moon { display: none; }

/* ===== Page ===== */
.page { padding: 24px; flex: 1; }
.p-page { padding: 22px 24px; }
.page-header { margin-bottom: 22px; }
.page-header h1 { font-family: 'Calistoga', serif; font-size: 26px; font-weight: 400; color: var(--text); letter-spacing: -0.01em; line-height: 1.1; }
.page-header p { font-size: 12.5px; color: var(--text-3); margin-top: 3px; }

.p-page-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 22px; }
.p-page-header-left h1 { font-family: 'Calistoga', serif; font-size: 26px; font-weight: 400; color: var(--text); letter-spacing: -0.01em; line-height: 1.1; }
.p-page-header-left .p-subtitle { font-size: 12px; color: var(--text-3); margin-top: 4px; }
.p-page-header-left .p-subtitle strong { color: var(--text-2); font-weight: 600; }
/* .p-page-header-right é o nome legado do .page-actions (mesmas medidas). */
.p-page-header-right { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; flex-shrink: 0; padding-top: 3px; }

/* ===== Stat Cards ===== */
.stats-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px,1fr)); gap: 12px; margin-bottom: 22px; }
.stat-card {
  background: var(--surface); border-radius: var(--radius-lg);
  padding: 16px 18px; border: 1px solid var(--border);
  transition: border-color .15s, box-shadow .15s, transform .15s;
}
.stat-card:hover { border-color: var(--brand-border); box-shadow: var(--shadow-sm); transform: translateY(-1px); }
a.stat-card { display: block; text-decoration: none; }
a.stat-card:hover { border-color: var(--brand-border); box-shadow: var(--shadow); }
.stat-label { font-size: 10.5px; font-weight: 700; color: var(--text-4); text-transform: uppercase; letter-spacing: .6px; margin-bottom: 6px; }
.stat-value { font-size: 24px; font-weight: 700; line-height: 1; letter-spacing: -.5px; color: var(--text); }
.stat-sub { font-size: 11px; color: var(--text-3); margin-top: 5px; }

/* ===== Summary bar ===== */
/* auto-FIT, não auto-fill: com auto-fill a barra cria colunas vazias de 110px até
   encher a largura, e 4 KPIs numa tela larga ficavam espremidos no canto esquerdo
   com meio card vazio à direita (e o rótulo vazando pro vizinho). */
.p-summary {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(140px,1fr));
  background: var(--surface); border-radius: var(--radius-lg);
  border: 1px solid var(--border); overflow: hidden; margin-bottom: 18px;
  transition: border-color .2s, background .2s;
}
.p-summary-item {
  padding: 14px 18px; border-right: 1px solid var(--border);
  transition: background .1s; text-decoration: none; display: block;
  min-width: 0; /* item de grid não encolhe abaixo do conteúdo sem isto — e aí o texto escapa */
}
.p-summary-item:last-child { border-right: none; }
/* Mãozinha e hover só em item que REALMENTE navega ou filtra (`<a>`, `<button>`, ou marcado como
   clicável). Aplicados a todo item, prometiam clique em KPI que só mostra número — o usuário
   clica, nada acontece, e ele deixa de confiar no resto da tela. */
.p-summary-item:is(a, button, [role="button"], .clicavel) { cursor: pointer; }
.p-summary-item:is(a, button, [role="button"], .clicavel):hover { background: var(--surface-2); }
/* Barra DENTRO de um card: o card já desenha borda e raio, então a barra entra sem os seus —
   senão ficam duas molduras encaixadas e dois raios brigando no canto. */
.p-summary.embutida { border: none; border-radius: 0; margin: 0; background: transparent; }
.p-summary-item.active { background: var(--brand-dim2); }
/* display:block — em <span> inline o overflow:hidden não vale de nada e o rótulo
   longo ("PRÓXIMOS 7 DIAS") atravessava a divisória do KPI vizinho. */
.p-summary-label { display: block; font-size: 10px; font-weight: 700; color: var(--text-4); text-transform: uppercase; letter-spacing: .6px; margin-bottom: 5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* `tabular-nums`: número em coluna alinha pela casa — sem isto os KPIs lado a lado dançam a cada
   atualização, porque o "1" é mais estreito que o "8" na fonte padrão. */
.p-summary-value { font-size: 22px; font-weight: 700; letter-spacing: -.4px; line-height: 1; color: var(--text); font-variant-numeric: tabular-nums; }
.p-summary-item.active .p-summary-value { color: var(--brand); }
/* Linha de apoio sob o número ("na fila + em atendimento", "venda fechada pela atendente"): explica
   o que o KPI conta, quando o rótulo sozinho deixa dúvida. É o pedaço que faltava no componente e
   que fez duas telas do CRM redesenharem a barra inteira com `.cl-kpi-*`/`.sv-kpi-*`.
   ⚠️ Esta versão QUEBRA em várias linhas de propósito — as telas do CRM contam com isso. Quem
   precisa de uma linha só que trunca usa `.p-summary-sub.uma-linha` abaixo. */
.p-summary-sub { font-size: 11px; color: var(--text-3); margin-top: 4px; line-height: 1.35; }
/* Percentual embaixo do número absoluto ("97" / "97% do que saiu"), nas barras de 8-10 KPIs
   (Email marketing / SMS). Uma linha só que trunca com reticências: nessas barras a coluna é
   estreita e uma sub-linha que quebra em duas empurra a altura do card e desalinha a fila
   inteira. O texto completo fica no `title` (ver `_setPct` nas duas views). */
.p-summary-sub.uma-linha { display: block; margin-top: 5px; font-weight: 600; color: var(--text-4); line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.p-summary-sub.is-warn { color: var(--danger); }
/* Nº de colunas FIXO, para barra com muitos KPIs: `--cols` na própria tag (5 no Email marketing,
   que tem 10 cards; 4 no SMS, que tem 8) faz as filas fecharem exatas. O `auto-fit` acima escolhe
   o nº sozinho — com 10 cards ele pega 6 numa tela larga e a segunda fila fica com 4 e um buraco à
   direita, dentro da mesma caixa com borda. Só vale acima de 1024px: abaixo disso o media query
   devolve o auto-fit, que é quem sabe encolher sem estourar a divisória. */
.p-summary.p-summary-fixo { grid-template-columns: repeat(var(--cols, 4), 1fr); }
/* Rótulo que é FRASE, não palavra ("Casos críticos (30 dias ou mais)", "duração média por chamada ·
   este mês"): relatório que vai impresso para o cliente e resumo com o período dentro do rótulo.
   Aqui ele quebra linha em vez de cortar com reticências, porque rótulo cortado num relatório é
   informação perdida. O `min-width:0` do item continua segurando o texto dentro da divisória. */
.p-summary.rotulo-longo .p-summary-label { white-space: normal; overflow: visible; line-height: 1.3; }
/* Rótulo que quebra põe o número de cada item numa altura diferente. Com `subgrid`, rótulo, número
   e nota de todos os itens da mesma linha dividem as mesmas 3 faixas: o rótulo mais longo alarga a
   faixa de cima e os números saem alinhados. Item sem nota deixa a 3ª faixa vazia, sem problema. */
.p-summary.rotulo-longo > .p-summary-item { display: grid; grid-row: span 3; grid-template-rows: subgrid; }

/* ===== Cards ===== */
.card, .p-card {
  background: var(--surface); border-radius: var(--radius-lg);
  border: 1px solid var(--border); overflow: hidden; margin-bottom: 14px;
  transition: border-color .1s, background .2s;
}
.card:hover, .p-card:hover { border-color: var(--border-2); }
/* Cabeçalho tintado na marca (piloto aprovado em /gestao/vendas, 01/10/2026). */
.card-header, .p-card-header {
  padding: 13px 18px; border-bottom: 1px solid var(--brand-border);
  background: var(--brand-dim);
  display: flex; align-items: center; gap: 10px;
}
.card-header h2, .card-header h3, .p-card-header h2 {
  font-size: 13px; font-weight: 600; color: var(--brand-deeper); letter-spacing: -.1px;
}
.card-header > svg, .p-card-header > svg { color: var(--brand); flex-shrink: 0; }
.card-header .card-actions, .p-card-header .card-actions { margin-left: auto; display: flex; gap: 6px; }
.card-body, .p-card-section { padding: 16px 18px; }
.card-body.no-pad, .p-card-section.no-pad { padding: 0; }
.card-footer { padding: 12px 18px; border-top: 1px solid var(--border); background: var(--surface-2); }
/* Rodapé de AÇÕES (Cancelar + Salvar de modal/card): botões à direita. Antes cada tela escrevia
   o flex inline, e ~30 rodapés tinham `justify-content:flex-end` SEM `display:flex`, então os
   botões ficavam encostados à esquerda. Rodapé de texto/nota continua .card-footer puro. */
.card-footer-actions { display: flex; align-items: center; justify-content: flex-end; gap: var(--sp-2); flex-wrap: wrap; }

.p-card-section + .p-card-section { border-top: 1px solid var(--border); }

/* ===== Seção destacada (.p-sec) + menu de painel (.p-railnav) =====
   Padrão aprovado em 17/08 na bancada de atendimento e promovido ao design system para ser
   reaproveitado nas outras telas. Duas regras nasceram daqui:

   1. FAIXA DE TÍTULO DE SEÇÃO: fundo `--surface-3` (NÃO `--surface-2`, que é quase o branco do
      card e faz o título sumir), texto `--text-2` e uma marca de 3px da cor da marca à esquerda.
      Com várias seções abertas na mesma tela, título sem moldura não separa nada.
   2. ITEM DE MENU SELECIONADO: `--brand-dim` de fundo + `--brand-dark` no texto — a MESMA
      fórmula de `.nav-item.active` na sidebar. 🚫 Nada de filete/tarja decorativa presa à borda
      do item: destaque de menu no portal é fundo, em um lugar só.

   Os nomes `hub-*` são aliases do painel de contexto do cliente (`partials/painel-cliente`) e
   do trilho da bancada — estão aqui, e não numa cópia na view, para haver uma fonte só. */
.p-sec, .p-block, .hub-sec, .hub-block {
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--surface); padding: 12px 13px;
}
.p-sec > .p-sec-title, .p-block > .p-sec-title,
.hub-sec > .hub-section-title, .hub-block > .hub-section-title {
  margin: -12px -13px 11px; padding: 9px 13px 9px 10px;
  background: var(--surface-3); color: var(--text-2);
  border-bottom: 1px solid var(--border-2); border-left: 3px solid var(--brand);
  border-radius: var(--radius-md) var(--radius-md) 0 0;
}
/* Recolhida, a faixa vira a caixa inteira (sem borda dupla nem padding sobrando embaixo) */
.p-sec.collapsed > .p-sec-title, .hub-sec.collapsed > .hub-section-title {
  margin-bottom: -12px; border-bottom: none; border-radius: var(--radius-md);
}
/* Faixa com um CONTROLE à direita (ex.: o alternador vendedora|equipe da tabela da gaveta no /bi).
   🚫 O controle vai DENTRO da faixa, nunca num wrapper em volta dela: o `.p-sec-title` sangra até
   a borda por margem negativa, e envolvê-lo devolve o padding da caixa e desalinha a faixa.
   O padding vertical cai de 9 pra 5px porque o .p-ptab já tem 6px próprio e a faixa engordaria. */
.p-sec-title.tem-acao {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding-top: 5px; padding-bottom: 5px;
}
.p-sec-title.tem-acao > .p-ptab-group { text-transform: none; letter-spacing: 0; }
.p-sec-title, .hub-section-title {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .6px; color: var(--text-4); margin-bottom: 6px;
}

/* ===== Gaveta lateral (.p-drawer) =====
   O padrao de "abrir o detalhe sem sair da lista" do portal: entra da direita, cobre a tela
   com um veu e mantem a lista atras dela com o filtro e a pagina de pe. Nasceu na bancada de
   atendimento (`partials/bancada`) e subiu para ca quando a tela de Cobranca adotou o mesmo
   visual -- os nomes `hub-panel*` continuam valendo como alias porque e o mesmo objeto, e uma
   copia da geometria em cada view divergiria na primeira vez que alguem mexesse na largura.

   Uso: `<div class="p-drawer-overlay">` + `<div class="p-drawer">` irmaos no fim do <body>, e
   a classe `open` nos dois para mostrar. Largura em `min()` para sobrar em tela pequena. */
.p-drawer-overlay, .hub-panel-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,.35); z-index: 200;
  opacity: 0; pointer-events: none; transition: opacity .22s;
}
.p-drawer-overlay.open, .hub-panel-overlay.open { opacity: 1; pointer-events: auto; }
.p-drawer, .hub-panel {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(1120px, 97vw);
  background: var(--surface); border-left: 1px solid var(--border); z-index: 201;
  display: flex; flex-direction: column; transform: translateX(100%);
  transition: transform .24s cubic-bezier(.4,0,.2,1); box-shadow: var(--shadow-lg);
}
.p-drawer.open, .hub-panel.open { transform: translateX(0); }
.p-drawer:focus-visible, .hub-panel:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.p-drawer-header, .hub-panel-header {
  display: flex; align-items: center; gap: 10px; padding: 14px 18px;
  border-bottom: 1px solid var(--border); flex-shrink: 0;
}
.p-drawer-body, .hub-panel-body {
  flex: 1; min-width: 0; overflow-y: auto; padding: 16px 18px;
  display: flex; flex-direction: column; gap: 14px;
}
.p-drawer-footer, .hub-panel-footer {
  padding: 12px 18px; border-top: 1px solid var(--border);
  display: flex; gap: 8px; flex-wrap: wrap; flex-shrink: 0;
}
@media (max-width: 768px) { .p-drawer, .hub-panel { width: 100%; } }
/* `.estreita`: formulario curto, ficha ou lista de apoio -- nao um registro inteiro. Era a gaveta
   que cada tela desenhava por conta propria (400, 440, 500 e 520px); ficou uma largura so. */
.p-drawer.estreita, .hub-panel.estreita { width: min(520px, 100vw); }

.p-railnav, .hub-rail {
  background: var(--surface-3); border-left: 1px solid var(--border-2);
  padding: 10px 8px; display: flex; flex-direction: column; gap: 2px;
}
.p-railnav-i, .hub-rail-i {
  display: flex; align-items: center; gap: 8px; width: 100%; padding: 7px 9px;
  border: none; background: none; border-radius: 7px; font: inherit; font-size: 12.5px;
  font-weight: 500; color: var(--text-3); text-align: left; cursor: pointer;
}
.p-railnav-i:hover, .hub-rail-i:hover { background: var(--surface); color: var(--text); }
.p-railnav-i.active, .hub-rail-i.active { background: var(--brand-dim); color: var(--brand-dark); font-weight: 700; }
html.dark .p-railnav-i.active, html.dark .hub-rail-i.active { color: var(--brand); }
.p-railnav-i svg, .hub-rail-i svg { width: 14px; height: 14px; flex-shrink: 0; }
.p-railnav-n, .hub-rail-n {
  margin-left: auto; flex-shrink: 0; font-size: 10px; font-weight: 700; padding: 1px 6px;
  border-radius: 999px; background: var(--border-2); color: var(--text-2);
  font-variant-numeric: tabular-nums;
}
.p-railnav-i.active .p-railnav-n, .hub-rail-i.active .hub-rail-n { background: var(--brand); color: #fff; }

/* Grid */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.grid-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 14px; }
.grid-4 { display: grid; grid-template-columns: repeat(4,1fr); gap: 14px; }
/* Grid que decide o nº de colunas pelo espaço, não por um número fixo: cabem 2, viram 2; cabe 1,
   vira 1. Os `.grid-N` acima têm contagem CRAVADA e só colapsam nos breakpoints — então um card
   que precise de 340px pra não quebrar o rótulo é apertado em 1199px e nada na tela avisa.
   A largura mínima da coluna é `--col-min` (default 320px), definida inline por quem usa. */
.grid-auto { display: grid; grid-template-columns: repeat(auto-fit, minmax(var(--col-min, 320px), 1fr)); gap: 14px; }
.grid-auto > * { min-width: 0; }
/* Filho que ocupa a linha inteira do grid. Serve ao caso do nº ÍMPAR de itens num grid par: sem
   isso o último fica com meia largura e o resto da faixa some em branco, o que a tela não explica.
   Em 1 coluna (mobile) é inócuo, porque `1 / -1` já é a única coluna. */
.grid-full { grid-column: 1 / -1; }
/* Pilha vertical — o container de "vários blocos um embaixo do outro", com 14px, o MESMO gap dos
   `.grid-*` acima, pra pilha e grid na mesma tela não terem dois respiros diferentes.
   🚫 Não usar margin no filho: margem colapsa e duplica conforme o vizinho. */
.stack { display: flex; flex-direction: column; gap: 14px; min-width: 0; }

/* Layout de 2 colunas com colapso responsivo */
.col-layout-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; align-items: start; }

/* Caixa de gráfico — ALTURA FIXA, obrigatória em todo canvas do Chart.js.
   Com responsive:true (e maintainAspectRatio no default) o Chart.js usa width/height
   do <canvas> só como PROPORÇÃO, nunca como pixel: height="70" com width padrão 300
   vira 4,3:1, então num monitor largo o gráfico passa de 400px de altura e achata as
   curvas. Envolver o canvas aqui e passar maintainAspectRatio:false nas options.
   Altura por gráfico via --chart-h (barra horizontal: dimensionar pelo nº de itens). */
.chart-box { position: relative; height: var(--chart-h, 260px); }
@media (max-width: 768px) { .chart-box { height: var(--chart-h-sm, var(--chart-h, 220px)); } }
/* Tooltip de gráfico (p-charts.js): cartão claro, bolinha · nome · valor, período embaixo. */
.p-chart-tip {
  position: fixed; z-index: 10000; pointer-events: none; opacity: 0; transition: opacity .12s ease;
  min-width: 180px; max-width: 320px; padding: 10px 12px; display: grid; gap: 6px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md); font-size: 13px; color: var(--text-2);
}
.p-chart-tip.on { opacity: 1; }
.p-chart-tip-l { display: flex; align-items: center; gap: 8px; }
.p-chart-tip-l i { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.p-chart-tip-l span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.p-chart-tip-l b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; padding-left: 16px; }
.p-chart-tip-p { color: var(--text-3); font-size: 12px; text-align: center; }
.p-chart-tip-l + .p-chart-tip-p { margin-top: 2px; }

/* ===== Table ===== */
.table-wrap, .p-index-table-wrap { overflow-x: auto; }
table, .p-index-table { width: 100%; border-collapse: collapse; font-size: 13px; }
thead th, .p-index-table thead th {
  padding: 9px 16px; text-align: left;
  font-weight: 700; color: var(--text-4); font-size: 10.5px;
  text-transform: uppercase; letter-spacing: .6px;
  background: var(--surface-2); border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
tbody td, .p-index-table tbody td {
  padding: 11px 16px; border-bottom: 1px solid var(--border);
  vertical-align: middle; color: var(--text-2);
}
tbody tr, .p-index-table tbody tr { transition: background .08s; }
tbody tr:last-child td, .p-index-table tbody tr:last-child td { border-bottom: none; }
tbody tr:hover td, .p-index-table tbody tr:hover td { background: var(--surface-2); }
tbody tr.clickable, .p-index-table tbody tr { cursor: pointer; }
/* Célula de tabela NUNCA em negrito (15/10/2026, Nathan: "nada na tabela precisa estar em negrito, padronizada
   pra qualquer tabela"). O !important passa por cima do font-weight inline que as views têm aos montes.
   Selo e botão ficam em 500; iniciais do avatar e o título de grupo (tr.p-grupo) não são dado, seguem. */
tbody td, tbody td * { font-weight: 400 !important; }
tbody td .badge, tbody td .badge *, tbody td .btn, tbody td .btn * { font-weight: 500 !important; }
tbody td .u-avatar.is-ini, tbody tr.p-grupo td, tbody tr.p-grupo td * { font-weight: 700 !important; }
/* Estado da NF-e (partials/nf-ico): documento + marca, cor pelo estado. */
.nf-ico { display: inline-flex; flex-shrink: 0; width: 16px; height: 16px; }
.nf-ico svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.nf-ico.is-ok { color: var(--success); }
.nf-ico.is-pend { color: var(--warning); }
.nf-ico.is-bad { color: var(--danger); }
.nf-ico.is-none { color: var(--text-4); opacity: .7; }
/* menu de download (partials/download-menu): só formatos curtos, painel estreito */
.dl-menu .row-menu-pop { min-width: 110px; }

/* ===== Table compact =====
   O `compact` aperta a LINHA, não o cabeçalho: a faixa de títulos é a régua que separa o
   cabeçalho do corpo, e com o mesmo respiro das células ela sumia dentro da tabela. */
.p-index-table-wrap.compact .p-index-table td, .table-wrap.compact table td { padding-top: 5px !important; padding-bottom: 5px !important; }
.p-index-table-wrap.compact .p-index-table th, .table-wrap.compact table th { padding-top: 9px !important; padding-bottom: 9px !important; }
.p-index-table-wrap.compact .p-index-table td, .table-wrap.compact table td { font-size: 12px; }
.p-index-table-wrap.compact .p-index-table td div { font-size: 12px !important; }
.p-index-table-wrap.compact .p-index-table td [data-compact-hide] { display: none; }

/* ===== Tabela numérica (.p-num) =====
   Números à direita e alinhados (tabular), 1ª coluna = rótulo em destaque. `.is-center` centraliza
   (grade de meses com badge), `td.is-forte` = o número que importa na linha, `.is-opt` some no celular. */
table.p-num th, table.p-num td { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
table.p-num th:first-child, table.p-num td:first-child { text-align: left; white-space: normal; }
table.p-num td:first-child, table.p-num td.is-forte { color: var(--text); }
table.p-num.is-center th:not(:first-child), table.p-num.is-center td:not(:first-child) { text-align: center; }
table.p-num .badge { min-width: 46px; justify-content: center; }
@media (max-width: 640px) { table.p-num .is-opt { display: none; } }

/* ===== Comportamento de tabela =====
   O que uma tela precisa de DIFERENTE numa tabela é comportamento (rolar, ordenar, cortar), nunca
   aparência — e é por classe daqui, não por regra th/td na view (o npm test cobra).
   `is-clip`: com table-layout:fixed a célula segura o que é dela (td.is-solta escapa: menu "⋯").
   `is-sticky`: cabeçalho e TOTAL grudados; `--sticky-top` quando a página rola sob a topbar.
   Borda via box-shadow — border não acompanha position:sticky com border-collapse. */
table.is-clip th, table.is-clip td { overflow: hidden; text-overflow: ellipsis; }
table.is-clip td.is-solta { overflow: visible; }
table.is-nowrap td { white-space: nowrap; }
/* `is-linha`: todo registro com UMA linha de altura — o texto longo trunca e o inteiro vai no
   `title`. O teto de cada coluna de texto livre é `style="max-width:…"` no th e no td dela. */
table.is-linha td { white-space: nowrap; }
table.is-linha td > div, table.is-linha td > div > span, table.is-linha td > span {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
table.is-tab td { font-variant-numeric: tabular-nums; }
/* `tr.is-fixa`: linha de altura fixa numa fila que se lê na diagonal (o resto vai no `title`). */
tr.is-fixa > td { height: 42px; padding-top: 0; padding-bottom: 0; }
/* `is-densa`: matriz de muitas colunas estreitas (checkbox por papel × ação) — sem ela a grade
   ganha 20px por coluna e passa a rolar de lado. */
table.is-densa th, table.is-densa td { padding: 8px 8px; }
table.is-densa th:first-child, table.is-densa td:first-child { padding-left: 16px; }
table.is-sticky thead th { position: sticky; top: var(--sticky-top, 0); z-index: 3; box-shadow: inset 0 -1px 0 var(--border); }
table.is-sticky tfoot td { position: sticky; bottom: 0; z-index: 2; }
/* `is-col1-fixa`: a 1ª coluna (o rótulo da linha) gruda à esquerda numa tabela larga que rola de
   lado — sem ela o leitor rola até 10/26 e não sabe mais de qual empresa é a linha. Precisa de
   fundo OPACO próprio (a célula passa por baixo das outras) e de `z-index` acima do corpo mas
   abaixo do `thead` do `is-sticky`, senão o cabeçalho rolado passa por baixo dela no cruzamento.
   A borda é box-shadow: `border` não acompanha `position:sticky` com `border-collapse`. */
table.is-col1-fixa th:first-child, table.is-col1-fixa td:first-child {
  position: sticky; left: 0; z-index: 2; background: var(--surface);
  box-shadow: inset -1px 0 0 var(--border);
}
table.is-col1-fixa thead th:first-child { z-index: 4; background: var(--surface-2); }
table.is-col1-fixa tbody tr:hover td:first-child { background: var(--surface-2); }
table.is-col1-fixa tfoot td:first-child { z-index: 3; background: var(--surface-2); }
/* As marcas de estado também pintam a borda ESQUERDA por box-shadow na 1ª célula, então numa
   coluna fixa as duas sombras precisam vir na mesma declaração — senão a marca apaga a divisória
   da coluna grudada (ou o contrário, dependendo da ordem no arquivo). */
table.is-col1-fixa tbody tr.p-marca-ok td:first-child { box-shadow: inset 3px 0 0 var(--success), inset -1px 0 0 var(--border); }
table.is-col1-fixa tbody tr.p-marca-alerta td:first-child { box-shadow: inset 3px 0 0 var(--warning), inset -1px 0 0 var(--border); }
table.is-col1-fixa tbody tr.p-marca-off td:first-child { box-shadow: inset 3px 0 0 var(--border-2), inset -1px 0 0 var(--border); }
/* `.is-grupo-ini`: 1ª célula de um GRUPO de colunas (ex.: as 2 colunas de cada mês numa matriz
   mês × empresa). Sem a divisória, 12 pares de colunas viram 24 colunas soltas e o leitor perde
   onde um mês acaba. Vai na célula, não no grupo: `<colgroup>` não aceita borda com
   `border-collapse`, e box-shadow não vaza pra célula vizinha como `border-left` faria. */
th.is-grupo-ini, td.is-grupo-ini { box-shadow: inset 1px 0 0 var(--border-2); }
tfoot td {
  padding: 12px 16px; font-weight: 700; color: var(--text);
  background: var(--surface-2); box-shadow: inset 0 2px 0 var(--border);
}
th.is-sort { cursor: pointer; user-select: none; }
th.is-sort:hover { color: var(--brand); }
th.is-sort[data-dir="desc"]::after { content: ' ↓'; color: var(--brand); }
th.is-sort[data-dir="asc"]::after { content: ' ↑'; color: var(--brand); }
/* Linha de filtro por coluna, dentro do <thead>, logo abaixo dos títulos. */
tr.p-filtro-col th { padding: 7px 8px; text-transform: none; letter-spacing: 0; border-bottom: 2px solid var(--border); }
/* Linha-título de grupo no meio do corpo (ex.: módulos por área na tela de permissões). */
tbody tr.p-grupo td, tbody tr.p-grupo td:first-child {
  background: var(--surface-2); padding: 8px 16px; font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .8px; color: var(--brand); border-top: 2px solid var(--border); cursor: default;
}
tbody tr.p-grupo:first-child td { border-top: none; }
/* Marca de estado na borda esquerda da linha. */
tr.p-marca-ok td:first-child { box-shadow: inset 3px 0 0 var(--success); }
tr.p-marca-alerta td:first-child { box-shadow: inset 3px 0 0 var(--warning); }
tr.p-marca-off td:first-child { box-shadow: inset 3px 0 0 var(--border-2); }
/* Árvore na tabela: a linha-mãe leva `.p-abre` (seta) e abre as filhas `tr.p-nivel-2`/`p-nivel-3`,
   recuadas e em `--surface-2`. Filha fechada é `hidden` (o JS troca), nunca removida do DOM.
   `.p-abre.is-vazio` guarda o lugar da seta em linha sem filha, pra coluna do nome não pular. */
tbody tr.p-nivel-2 > td, tbody tr.p-nivel-3 > td { background: var(--surface-2); font-size: 12.5px; }
tbody tr.p-nivel-2 > td:first-child { padding-left: 44px; }
tbody tr.p-nivel-3 > td:first-child { padding-left: 76px; }
/* Nome longo de empresa/produto não alarga a matriz: reticências, nome inteiro no title. */
tbody tr.p-nivel-2 > td:first-child .ellipsis { display: block; max-width: 180px; }
tbody tr.p-nivel-3 > td:first-child .ellipsis { display: block; max-width: 148px; }
.p-abre {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 22px; height: 22px; padding: 0; border: 0; border-radius: 6px;
  background: transparent; color: var(--text-3); cursor: pointer;
}
.p-abre:hover { background: var(--surface-3); color: var(--brand); }
.p-abre svg { width: 14px; height: 14px; transition: transform .15s; }
.p-abre[aria-expanded="true"] svg { transform: rotate(90deg); }
.p-abre.is-vazio { visibility: hidden; cursor: default; }
/* Minigráfico de linha numa célula: UMA série, sem eixo nem rótulo; o valor vai no `<title>`.
   SVG puro (polyline) — um Chart.js por linha de tabela trava a tela com 40+ linhas. */
.p-spark-cel { display: block; width: 96px; height: 26px; margin-left: auto; color: var(--brand); overflow: visible; }
.p-spark-cel polyline { fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; }
.p-spark-cel circle { fill: currentColor; }
/* Coluna secundária que sai em tela estreita (vai no th E no td dela; o dado segue no detalhe). */
@media (max-width: 1760px) { .p-oculta-1760 { display: none; } }
@media (max-width: 1100px) { .p-oculta-1100 { display: none; } }
@media (max-width: 860px) { .p-oculta-860 { display: none; } }
/* `body.p-print-densa`: relatório que vai pro PDF — tabela enxuta só no papel. */
@media print {
  body.p-print-densa th, body.p-print-densa td { padding: 4px 6px !important; font-size: 9.5px !important; white-space: normal; word-break: break-word; }
  body.p-print-densa th { font-size: 8.5px !important; }
}

/* ===== Badges ===== */
.badge {
  display: inline-flex; align-items: center;
  padding: 2px 8px; border-radius: 4px;
  font-size: 11px; font-weight: 600;
  letter-spacing: .1px; line-height: 18px;
  white-space: nowrap; border: 1px solid transparent;
}
.badge-success  { background: var(--success-bg);  color: var(--success);  border-color: var(--success-border); }
.badge-warning  { background: var(--warning-bg);  color: var(--warning);  border-color: var(--warning-border); }
.badge-danger   { background: var(--danger-bg);   color: var(--danger);   border-color: var(--danger-border); }
.badge-info     { background: var(--info-bg);     color: var(--info);     border-color: var(--info-border); }
.badge-purple   { background: var(--purple-bg);   color: var(--purple);   border-color: var(--purple-border); }
.badge-neutral  { background: var(--surface-2);   color: var(--text-3);   border-color: var(--border); }
.badge-brand    { background: var(--brand-dim);   color: var(--brand-dark); border-color: var(--brand-border); }
html.dark .badge-brand { color: var(--brand); }

/* Status badges */
.badge-delivered           { background: var(--success-bg);  color: var(--success);  border-color: var(--success-border); }
.badge-forwarded           { background: var(--info-bg);     color: var(--info);     border-color: var(--info-border); }
.badge-in_transit          { background: var(--info-bg);     color: var(--info);     border-color: var(--info-border); }
.badge-posted_object       { background: #e0f2fe; color: #0369a1; border-color: #bae6fd; }
html.dark .badge-posted_object { background: rgba(3,105,161,.12); color: #38bdf8; border-color: rgba(56,189,248,.2); }
.badge-delivering          { background: var(--purple-bg);   color: var(--purple);   border-color: var(--purple-border); }
.badge-out_for_delivery    { background: var(--purple-bg);   color: var(--purple);   border-color: var(--purple-border); }
.badge-recipient_not_found { background: var(--warning-bg);  color: var(--warning);  border-color: var(--warning-border); }
.badge-delivery_attempt    { background: var(--warning-bg);  color: var(--warning);  border-color: var(--warning-border); }
.badge-returned            { background: var(--danger-bg);   color: var(--danger);   border-color: var(--danger-border); }
.badge-returning           { background: #fce7f3; color: #9d174d; border-color: #fbcfe8; }
html.dark .badge-returning { background: rgba(236,72,153,.12); color: #f472b6; border-color: rgba(244,114,182,.2); }
.badge-waiting_client      { background: #fef9c3; color: #854d0e; border-color: #fef08a; }
html.dark .badge-waiting_client { background: rgba(234,179,8,.12); color: #fbbf24; border-color: rgba(251,191,36,.2); }
.badge-overdue             { background: var(--brand-dim);   color: var(--brand-dark); border-color: var(--brand-border); }
html.dark .badge-overdue   { color: var(--brand); }
.badge-wrong_address       { background: var(--danger-bg);   color: var(--danger);   border-color: var(--danger-border); }
.badge-delivery_problem    { background: var(--warning-bg);  color: var(--warning);  border-color: var(--warning-border); }
.badge-pending             { background: var(--surface-2);   color: var(--text-3);   border-color: var(--border); }
.badge-no_tracking         { background: var(--surface-2);   color: var(--text-4);   border-color: var(--border); }
.badge-tracking_delayed    { background: var(--danger-bg);   color: var(--danger);   border-color: var(--danger-border); }

/* ===== Buttons ===== */
.btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px; border-radius: var(--radius-md);
  border: 1px solid transparent; font-size: 13px; font-weight: 600;
  font-family: var(--font); transition: all .1s;
  white-space: nowrap; cursor: pointer; line-height: 1.4;
}
.btn svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.btn-primary { background: var(--brand); color: #fff; border-color: var(--brand); box-shadow: 0 1px 3px rgba(232,120,32,.3); }
.btn-primary:hover { background: var(--brand-dark); border-color: var(--brand-dark); }
.btn-secondary { background: var(--surface); color: var(--text-2); border-color: var(--border-2); box-shadow: var(--shadow-xs); }
.btn-secondary:hover { background: var(--surface-2); color: var(--text); border-color: var(--border-3); }
/* Hierarquia alinhada com o portal-gestão (28/09/2026):
   - .btn-ghost: ação neutra/de fluxo (Cancelar, Limpar, Filtros). Borda cinza de verdade: sem ela
     o botão virava texto solto. Ícone só (fechar de modal/drawer) usa .btn-icon, não ghost.
   - .btn-danger-ghost: o GATILHO destrutivo na página/linha/rodapé (Excluir, Remover, Recusar).
   - .btn-danger: vermelho SÓLIDO, SÓ o botão de confirmar dentro do modal destrutivo
     (inclusive o okClass do showConfirm). Nunca como gatilho. */
.btn-ghost { background: transparent; color: var(--text-2); border: 1px solid var(--border); }
.btn-ghost:hover { background: var(--surface-2); color: var(--text); }
.btn-danger-ghost { background: transparent; color: var(--danger); border: 1px solid var(--danger-border); }
.btn-danger-ghost:hover { background: var(--danger-bg); border-color: var(--danger); }
.btn-danger { background: var(--danger-solid); color: #fff; border-color: transparent; }
.btn-danger:hover { background: var(--danger-solid-hover); color: #fff; }
/* Ação que ABRE algo fora da tela (boleto, checkout, documento). Azul CHEIO, não tingido: dentro
   de uma célula cheia de texto o fundo claro sumia igual ao link de texto que ele veio substituir
   (20/08/2026 — "o botão Ver boleto precisa estar mais destacado"). Azul sólido não disputa com o
   .btn-primary laranja (a ação da página): são cores diferentes, não duas intensidades da mesma. */
.btn-info { background: var(--info); color: #fff; border-color: var(--info); font-weight: 600; }
.btn-info:hover { filter: brightness(.93); color: #fff; }
/* Mesma função do .btn-info (abrir algo fora da tela), em GRAFITE — para linha de tabela, onde a
   cor já é do dado: a situação da cobrança é badge colorida e o azul cheio do lado dela disputava
   a leitura da linha (21/08/2026, decisão do Nathan). Neutro destaca sem competir. */
.btn-dark { background: var(--graphite); color: #fff; border-color: var(--graphite); font-weight: 600; }
.btn-dark:hover { background: var(--graphite-dark); border-color: var(--graphite-dark); color: #fff; }
/* Confirmação POSITIVA de peso (Aprovar, Contratar, Concluir): verde sólido. Mesmo papel do
   .btn-danger do lado destrutivo, então fica restrito ao botão que confirma, não ao gatilho. */
.btn-success { background: var(--success-solid); color: #fff; border-color: transparent; }
.btn-success:hover { background: var(--success-solid-hover); color: #fff; }
.btn-sm  { padding: 5px 10px; font-size: 12px; }
.btn-xs  { padding: 3px 8px;  font-size: 11px; }
/* Desabilitado: igual em toda variante (antes cada botão ficava com a cara normal e só o cursor
   mudava, então parecia clicável). Sem pointer-events:none: o `title` que explica o bloqueio
   precisa continuar aparecendo. */
.btn:disabled, .btn[disabled] { opacity: .55; cursor: not-allowed; }

/* Faixa de "você está vendo pelos olhos de outra pessoa" no topo (partials/topbar): a
   impersonação do admin e o "Ver como" do CRM (docs/crm-recuperacao-venda.md 6.2.Q). UMA classe
   pras duas, e sem botão de fechar: a faixa só some saindo do modo. */
.p-modo-faixa { position: sticky; top: 0; z-index: 200; display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 7px 20px; background: var(--purple-solid); color: var(--on-cor); font-size: 12px; }
.p-modo-faixa-txt { display: flex; align-items: center; gap: 8px; min-width: 0; }
.p-modo-faixa-txt strong { margin: 0 3px; }
.p-modo-faixa-btn { flex-shrink: 0; padding: 3px 12px; border-radius: 6px; cursor: pointer; font-size: 12px; font-weight: 600; white-space: nowrap; color: var(--on-cor); background: color-mix(in srgb, var(--on-cor) 20%, transparent); border: 1px solid color-mix(in srgb, var(--on-cor) 30%, transparent); }
.p-modo-faixa-btn:hover { background: color-mix(in srgb, var(--on-cor) 30%, transparent); }
@media (max-width: 640px) { .p-modo-faixa { padding: 6px 12px; flex-wrap: wrap; } }
.btn:disabled:active, .btn[disabled]:active { transform: none; }
/* Contador DENTRO de um botão ("Filtros 3"). 🚫 Nunca usar `.badge` aqui: a badge tem
   `line-height:18px` + padding + borda = 24px de altura, e como ela é o filho mais alto do botão
   ela ESTICA o botão de ~29px para ~36px — só quando há filtro ligado. Era isso que fazia o
   "Filtros" da aba de Cobranças geradas pender na faixa das abas enquanto o da aba Casos, que
   usava uma pílula própria, ficava certo (25/08/2026). Esta pílula herda a linha do botão, então
   o botão tem a MESMA altura com e sem contador, e igual em toda aba. */
.btn-count {
  display: inline-flex; align-items: center;
  padding: 1px 6px; border-radius: 99px; margin-left: 2px;
  font-size: 11px; font-weight: 700; line-height: 1;
  background: rgba(255, 255, 255, .28); color: inherit;
}
/* Botão de fundo claro: o branco translúcido some. */
.btn-secondary .btn-count, .btn-ghost .btn-count { background: var(--surface-2); color: var(--text-2); }
.btn-danger-ghost .btn-count { background: var(--danger-bg); color: var(--danger); }
.btn-icon {
  padding: 6px; border-radius: var(--radius-md); color: var(--text-3);
  border: 1px solid transparent;
  display: inline-flex; align-items: center; justify-content: center; transition: all .1s;
}
.btn-icon:hover { background: var(--surface-2); color: var(--text); }
.btn-icon svg { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
/* Excluir só com ícone (lixeira na linha): `btn-icon btn-danger-ghost`. O .btn-icon vem depois no
   arquivo e pintaria de cinza sem borda; o seletor composto devolve o contorno vermelho. */
.btn-icon.btn-danger-ghost { color: var(--danger); border-color: var(--danger-border); }
.btn-icon.btn-danger-ghost:hover { color: var(--danger); background: var(--danger-bg); border-color: var(--danger); }
/* Tamanhos do botão só-ícone: quadrado, mesma altura do .btn-sm/.btn-xs de texto ao lado.
   O .btn-icon vem depois do .btn-sm no arquivo e zeraria o tamanho; o composto devolve. */
.btn-icon.btn-sm { padding: 5px; }
.btn-icon.btn-xs { padding: 3px; }
.btn-icon.btn-xs svg { width: 13px; height: 13px; }
/* Fechar (×) de modal, drawer e popup. Um só desenho no portal: antes cada tela tinha o seu
   (font-size 18/20/22px inline, .btn-icon com o × em 13px), então o × mudava de tamanho de
   um modal pro outro. Quadrado de 28px com hover igual ao .btn-icon. Posição (margin-left:auto)
   continua no lugar de uso. */
.btn-close {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 28px; height: 28px; padding: 0; border-radius: var(--radius-md);
  border: 1px solid transparent; background: transparent; color: var(--text-3);
  font-size: 20px; line-height: 1; font-family: var(--font); cursor: pointer; transition: all .1s;
}
.btn-close:hover { background: var(--surface-2); color: var(--text); }
.btn-close:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
/* Ação de texto pequena dentro de um bloco (Limpar, Trocar): cor do brand, sem caixa. Não é
   ação de página; essa usa .btn. */
.btn-link {
  display: inline; padding: 0; border: none; background: none; cursor: pointer;
  color: var(--brand); font: inherit; font-size: 12px; font-weight: 600;
}
.btn-link:hover { text-decoration: underline; }
.btn-link:disabled { opacity: .55; cursor: not-allowed; text-decoration: none; }



/* ===== Layout de ações (mesmos nomes e medidas do portal-gestão) =====
   .page-actions: grupo de botões do cabeçalho da página, irmão do bloco de título, à direita.
   .page-actions-sep: divisória vertical dentro dele (separa o Excluir das ações de fluxo).
   .panel-toolbar: barra no topo de um card/painel (busca + filtros à esquerda,
   .panel-toolbar-actions à direita). */
.page-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; flex-shrink: 0; }
.page-actions-sep { width: 1px; align-self: stretch; background: var(--border); margin: 2px 4px; }
.panel-toolbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; padding: 12px 16px; border-bottom: 1px solid var(--border); min-height: 58px; }
.panel-toolbar-actions { margin-left: auto; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* No cabeçalho: o legado .page-header não é flex (h1 e p empilham direto nele). Com um
   .page-actions como filho direto ele vira linha: título à esquerda, ações à direita. */
.page-header:has(> .page-actions) { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.page-header:has(> .page-actions) > :first-child { flex: 1 1 auto; min-width: 0; }
.page-header > .page-actions, .p-page-header > .page-actions { padding-top: 3px; max-width: 60%; }

/* Título de bloco FORA do .card-header (topo de seção, dentro de .panel-toolbar, painel sem
   header). Mesma tipografia do título de card no v2, para os dois lerem como o mesmo nível. */
.panel-title {
  font-family: var(--font-head, var(--font)); font-size: 14px; font-weight: 700;
  color: var(--brand-deeper); line-height: 1.3; letter-spacing: -.01em; margin: 0;
  display: flex; align-items: center; gap: 6px;
}

/* Faixa de itens selecionados com ações em massa (acima da tabela). Nasce escondida pelo JS da
   tela: `style="display:none"` no elemento e `el.style.display = 'flex'` ao selecionar, como já era.
   As ações vão num .panel-toolbar-actions dentro dela. */
.bulk-bar {
  display: flex; align-items: center; gap: var(--sp-2, 8px); flex-wrap: wrap;
  padding: 10px 16px; margin-bottom: var(--sp-3, 12px);
  background: var(--brand-dim); border: 1px solid var(--brand-border);
  border-radius: var(--radius-md);
}
.bulk-bar-count { font-size: 13px; font-weight: 600; color: var(--brand-dark); white-space: nowrap; }
html.dark .bulk-bar-count { color: var(--brand); }
.bulk-bar-sub { font-size: 13px; opacity: .6; white-space: nowrap; }
/* Barra SEMPRE visível (aba KB de Automação): neutra sem seleção, escura (invertida) com seleção.
   Os controles de dentro seguem currentColor, então a mesma regra serve no tema claro e no escuro. */
.bulk-bar.is-idle { background: var(--surface); border-color: var(--border); }
.bulk-bar.is-idle .bulk-bar-count { color: var(--text-3); font-weight: 500; }
.bulk-bar.is-dark { background: var(--text); border-color: var(--text); color: var(--bg-2); }
.bulk-bar.is-dark .bulk-bar-count, .bulk-bar.is-dark .form-label { color: inherit; }
.bulk-bar.is-dark .form-label { opacity: .75; }
.bulk-bar.is-dark .btn-secondary, .bulk-bar.is-dark .form-select {
  background-color: transparent; color: inherit; border-color: color-mix(in srgb, currentColor 28%, transparent);
}
.bulk-bar.is-dark .form-select option { color: var(--text); background: var(--bg-2); }
.bulk-bar.is-dark .btn-ghost { color: inherit; border-color: transparent; background: transparent; }
.bulk-bar.is-dark .p-ptab-divider { background: currentColor; opacity: .25; }
.card.is-selected { border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand); }

/* Copy button — sempre visível, discreto */
.copy-btn {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 3px 4px; border-radius: 4px; border: none; background: none;
  cursor: pointer; color: var(--text-4); transition: color .12s, background .12s;
  flex-shrink: 0;
}
.copy-btn:hover { color: var(--brand); background: var(--brand-dim); }
.copy-btn svg { stroke: currentColor; fill: none; stroke-linecap: round; stroke-linejoin: round; }

/* ===== Forms ===== */
/* 🚫 O `[hidden]` TEM que vir junto: `display:flex` numa CLASSE vence o `display:none` que o
   navegador dá ao atributo `hidden` (regra de user-agent, especificidade menor). Sem esta linha,
   `el.hidden = true` num `.form-group` não esconde nada e não avisa — o campo Duração e o aviso
   "a central preenche" apareceram LADO A LADO na bancada depois de discar (print de 24/09).
   Vale para todo `.form-group` do portal, não só o do CRM. */
.form-group { display: flex; flex-direction: column; gap: 5px; }
.form-group[hidden] { display: none; }
/* Linha de campos lado a lado que empilha sozinha quando não cabe. Existe como CLASSE porque
   `style="display:grid"` escrito na tag vence ATÉ o `[hidden]` — inline é a especificidade mais
   alta que há, então o elemento não some nem com `el.hidden = true`. Foi o caso do par
   Objeção/Retorno da bancada, que aparecia mesmo quando a ligação não foi atendida (24/09). */
.form-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--sp-2); }
.form-row[hidden] { display: none; }
.form-label { font-size: 12px; font-weight: 600; color: var(--text-2); }
.form-input, .form-select, .form-textarea {
  padding: 8px 12px; border: 1px solid var(--border);
  border-radius: var(--radius-md); font-size: 13px; font-family: var(--font);
  color: var(--text); background: var(--surface);
  outline: none; transition: border-color .12s, box-shadow .12s, background .2s;
}
.form-input:focus, .form-select:focus, .form-textarea:focus {
  border-color: var(--brand-border);
  box-shadow: 0 0 0 3px var(--brand-dim2);
}
.form-input::placeholder { color: var(--text-4); }
.form-select option { background: var(--surface); color: var(--text); }
/* `textarea.form-input` é o uso real em ~90 lugares do portal (as views quase nunca
   escrevem `.form-textarea`). Sem esta regra ele herdava só o estilo de input de 1 linha:
   sem altura mínima e sem alça de redimensionar — é a "caixa de texto sempre reduzida". */
/* `width:100%` só no TEXTAREA: sem ele o navegador usa a largura intrínseca (`cols`, ~20
   caracteres) e a caixa nasce estreita no meio de um bloco largo — foi o que apertava a
   observação do ticket na bancada. Não vale para input/select de propósito: os filtros inline
   dependem de `minWidth` fixo dentro de flex, e esticá-los quebraria as toolbars. */
.form-textarea, textarea.form-input { width: 100%; box-sizing: border-box; }
.form-textarea, textarea.form-input:not([rows="1"]) { resize: vertical; min-height: 96px; line-height: 1.5; }
/* `rows="1"` fica de fora de propósito: é o compositor que cresce com o texto (chat da
   bancada, barra de bulk do hub). Piso de 96px nele empurraria o rodapé pra cima. */
textarea.form-input[rows="1"] { resize: none; line-height: 1.5; }

/* ===== Toolbar ===== */
.toolbar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 14px; background: var(--surface); border-radius: var(--radius-lg);
  border: 1px solid var(--border); margin-bottom: 14px;
}
.toolbar .form-input, .toolbar .form-select { padding: 6px 9px; font-size: 13px; }
.toolbar .form-select { max-width: 150px; }
.toolbar .search-input { flex: 1; min-width: 160px; max-width: none; }
.p-filters .form-select { max-width: 170px; font-size: 13px; padding: 6px 9px; }
.p-filters .form-input.search-input { flex: 1; min-width: 160px; max-width: none; }

/* ===== Pagination ===== */
.pagination { display: flex; gap: 3px; justify-content: center; margin-top: 0; }
.pagination a, .pagination span {
  padding: 5px 11px; border-radius: 99px;
  border: 1px solid var(--border); font-size: 12.5px; font-weight: 500;
  color: var(--text-3); transition: all .15s; background: var(--surface);
}
.pagination a:hover { background: var(--brand-dim); border-color: var(--brand-border); color: var(--brand-dark); }
html.dark .pagination a:hover { color: var(--brand-light); }
.pagination a.active { background: var(--brand); color: #fff; border-color: var(--brand); box-shadow: 0 1px 6px rgba(228,124,36,.35); font-weight: 600; }
.pagination .ellipsis { border: none; background: transparent; color: var(--text-4); }

/* Pagination bar — info + controls em linha */
.pagination-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 18px; border-top: 1px solid var(--border); background: var(--surface-2); flex-wrap: wrap; }
.pagination-info { font-size: 12.5px; color: var(--text-3); display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
.pagination-info strong { color: var(--brand-dark); font-weight: 600; }
html.dark .pagination-info strong { color: var(--brand-light); }
.pag-perpage-sel { font-size: 12px; padding: 3px 8px; border: 1px solid var(--border-2); border-radius: 99px; background: var(--surface); color: var(--text-2); cursor: pointer; margin-left: 4px; transition: border-color .15s; }
.pag-perpage-sel:hover, .pag-perpage-sel:focus { outline: none; border-color: var(--brand); color: var(--brand-dark); }
.pagination-controls { display: flex; align-items: center; gap: 16px; margin-left: auto; flex-wrap: wrap; justify-content: flex-end; }
.pagination-per { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text-3); white-space: nowrap; }
.pagination-per .pag-perpage-sel { margin-left: 0; }
/* Navegação (opção B, 16/10/2026): ‹ · Página [n] de N · › — partial e public/js/pag-nav.js */
.pag-nav { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text-3); white-space: nowrap; }
.pag-btn { width: 28px; height: 28px; padding: 0; display: inline-flex; align-items: center; justify-content: center; border: 1px solid var(--border-2); border-radius: var(--radius-md); background: var(--surface); color: var(--text-2); font-size: 16px; line-height: 1; cursor: pointer; transition: border-color .15s, color .15s; }
.pag-btn:hover:not(:disabled) { border-color: var(--text-3); color: var(--text-1); }
.pag-btn:disabled { opacity: .4; cursor: default; }
.pag-page { display: inline-flex; align-items: center; gap: 6px; }
.pag-page-in { width: 46px; height: 28px; padding: 0 4px; text-align: center; font: inherit; font-size: 12.5px; font-weight: 600; border: 1px solid var(--border-2); border-radius: var(--radius-md); background: var(--surface); color: var(--text-1); }
.pag-page-in:focus { outline: none; border-color: var(--brand); }
.pag-sep { width: 1px; height: 18px; background: var(--border); }
.pag-nav-slot { display: contents; }
/* o design-v2.js troca o <select> por .ms-btn (min-width 160px): na barra fica do tamanho do ‹ › */
.pagination-per .ms-btn { min-width: 0; height: 28px; padding: 0 8px; font-size: 12.5px; gap: 8px; }
@media (max-width: 560px) { .pag-sep { display: none; } .pagination-controls { gap: 10px; } }

/* IA/robô = foto da Lina, nunca 🤖 (docs/design-system.md) */
.lina-ico { width: 1.15em; height: 1.15em; border-radius: 99px; object-fit: cover; display: inline-block; vertical-align: -0.2em; flex-shrink: 0; }

/* ===== Tab group buttons (.p-ptab / .p-ttab) ===== */
.p-ptab, .p-ttab {
  padding: 6px 12px; border: none; background: transparent;
  font-size: 12px; font-weight: 500; color: var(--text-3);
  cursor: pointer; white-space: nowrap; line-height: 1.4;
  display: inline-block; text-decoration: none;
}
.p-ptab:hover, .p-ttab:hover { background: rgba(0,0,0,.04); }
html.dark .p-ptab:hover, html.dark .p-ttab:hover { background: rgba(255,255,255,.06); }
.p-ptab.active, .p-ttab.active { background: var(--brand); color: #fff; }
.p-ptab:disabled, .p-ttab:disabled { opacity: .45; cursor: not-allowed; }
/* Caixa do grupo de .p-ptab (itens por página, período, visualização). Substitui o
   `<div style="display:flex;gap:1px;background:var(--surface-2);border:1px solid var(--border);
   border-radius:7px;overflow:hidden">` que cada tela copiava. Mesmo nome do portal-gestão. */
.p-ptab-group {
  display: inline-flex; vertical-align: middle; gap: 1px;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 7px; overflow: hidden;
}
/* Variante que ocupa a largura toda, botões divididos por igual (gaveta de filtros, modal). */
.p-ptab-group.full { display: flex; width: 100%; }
.p-ptab-group.full > .p-ptab, .p-ptab-group.full > .p-ttab { flex: 1; }
.p-ptab-label { font-size: 12px; color: var(--text-3); }
/* Rótulo EM CIMA do grupo, os dois como um bloco só (numa linha que quebra, o rótulo não fica órfão).
   A linha que junta vários usa align-items:flex-end pra os grupos ficarem na mesma base. */
.p-ptab-field { display: inline-flex; flex-direction: column; align-items: flex-start; gap: 5px; }
.p-ptab-field > .p-ptab-label { font-size: 10px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }
/* Separador vertical entre blocos de uma mesma linha de controles (ex: aba KB de Automação:
   "Selecionar visíveis" × filtros; na barra de seleção, "Marcar como" × downloads). */
.p-ptab-divider { width: 1px; align-self: stretch; min-height: 24px; background: var(--text-3); opacity: .35; }
/* Alternador de vista SÓ COM ÍCONE (Lista/Kanban no canto direito da faixa, /crm/leads). Ícone de
   15px + padding 6px + a borda do grupo = 29px, a altura do `.btn-sm` ao lado — o grupo não
   desalinha do "Filtros". 🚫 Sempre com `title` E `aria-label`: sem texto, o nome da vista mora lá. */
.p-ptab.is-icon { display: inline-flex; align-items: center; justify-content: center; padding: 6px 9px; text-decoration: none; }
.p-ptab.is-icon > svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* ===== Barra de abas de página (.tab-bar / .tab-btn / .tab-pane) =====
   Usada pela tela de Configurações e por qualquer página que SEJA uma aba dela
   (partials/config-tabs.ejs). Ficou aqui, e não na view, porque agora tem mais
   de um dono — duas cópias divergiriam no primeiro ajuste de espessura. */
.tab-bar { display: flex; flex-wrap: wrap; gap: 2px; border-bottom: 1.5px solid var(--border); margin-bottom: 24px; }
/* Canto direito (ajuda, ações): mesmo .p-tabs-actions da .p-tabs, já traz margin-left:auto + align-self:center. */
.tab-btn {
  padding: 9px 18px; font-size: 13px; font-weight: 600; cursor: pointer;
  background: none; border: none; border-bottom: 2.5px solid transparent;
  color: var(--text-3); transition: color .15s, border-color .15s;
  margin-bottom: -1.5px; letter-spacing: -.1px;
  text-decoration: none; display: inline-block; white-space: nowrap;
}
.tab-btn:hover { color: var(--text); }
.tab-btn.active { color: var(--brand); border-bottom-color: var(--brand); }
.tab-pane { display: none; }
.tab-pane.active { display: block; }

/* Sub-abas dentro de uma aba (pílulas) — hierarquia visual: a linha de cima é a
   navegação da página, esta é a navegação DENTRO dela. Duas barras sublinhadas
   iguais empilhadas não se leem. */
.tab-sub { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 18px; }
.tab-sub a {
  padding: 6px 14px; border-radius: 999px; font-size: 12.5px; font-weight: 600;
  color: var(--text-3); text-decoration: none; border: 1px solid var(--border);
  background: var(--surface); transition: background .15s, color .15s, border-color .15s;
}
.tab-sub a:hover { color: var(--text); background: var(--surface-2); }
.tab-sub a.active { background: var(--brand); border-color: var(--brand); color: #fff; }

/* ===== Custom calendar popup (.pcal-*) ===== */
.pcal-pop {
  position: fixed; z-index: 1000; /* acima do filter-drawer (901) — senão o calendário abre atrás do drawer */
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 12px; box-shadow: 0 10px 40px rgba(0,0,0,.14);
  padding: 16px; width: 268px; user-select: none;
}
.pcal-grid { display: grid; grid-template-columns: repeat(7,1fr); gap: 2px; text-align: center; margin-top: 8px; }
.pcal-day { padding: 5px 2px; border-radius: 5px; cursor: pointer; font-size: 12px; color: var(--text); line-height: 1.4; text-align: center; }
.pcal-day:hover { background: var(--surface-2); }
/* !important em color para sobrepor .is-today quando o dia selecionado é hoje */
.pcal-day.range-start, .pcal-day.range-end { background: var(--brand) !important; color: #fff !important; font-weight: 700; }
.pcal-day.in-range { background: var(--brand-dim); color: var(--brand); }
.pcal-day.is-today { border: 1px solid var(--brand); color: var(--brand); font-weight: 600; }
.pcal-day.other-month { color: var(--text-4); }
/* botões de navegação e cabeçalho */
.pcal-nav-btn { border: none; background: none; cursor: pointer; padding: 4px 8px; border-radius: 5px; font-size: 18px; color: var(--text-3); line-height: 1; }
.pcal-nav-btn:hover { background: var(--surface-2); }
.pcal-head-btn { border: none; background: none; cursor: pointer; padding: 3px 6px; border-radius: 5px; font-size: 13px; font-weight: 600; color: var(--text); }
.pcal-head-btn:hover { background: var(--surface-2); color: var(--brand); }
/* grade de meses e anos */
.pcal-month-btn { padding: 7px 4px; border-radius: 6px; cursor: pointer; font-size: 12px; color: var(--text); text-align: center; transition: background .1s; }
.pcal-month-btn:hover { background: var(--surface-2); }
.pcal-month-btn.pcal-sel { background: var(--brand) !important; color: #fff !important; font-weight: 700; }
.pcal-month-btn.pcal-dim { color: var(--text-4); }
/* atalhos de período: lista AO LADO do calendário (pcal.js `presets`), nunca fileira de botões na página */
.pcal-pop.pcal-has-pres { width: min(420px, calc(100vw - 16px)); padding: 0; }
.pcal-wrap { display: grid; grid-template-columns: 136px minmax(0,1fr); }
.pcal-pres { display: flex; flex-direction: column; gap: 1px; padding: 10px 6px; border-right: 1px solid var(--border); }
.pcal-pres-btn { border: none; background: none; cursor: pointer; text-align: left; padding: 6px 10px; border-radius: 6px; font-size: 12px; color: var(--text-2); white-space: nowrap; font-family: inherit; }
.pcal-pres-btn:hover { background: var(--surface-2); color: var(--text); }
.pcal-pres-btn.is-active { background: var(--brand-dim); color: var(--brand); font-weight: 600; }
.pcal-main { padding: 16px; min-width: 0; }
@media (max-width: 480px) {
  .pcal-wrap { grid-template-columns: minmax(0,1fr); }
  .pcal-pres { flex-direction: row; flex-wrap: wrap; gap: 2px; border-right: none; border-bottom: 1px solid var(--border); padding: 8px; }
  .pcal-pres-btn { padding: 4px 8px; font-size: 11.5px; }
}

/* ===== Campo de hora (public/js/ptime.js) — no lugar do <input type="time"> nativo ===== */
/* O campo é um .form-input comum com `data-ptime`; aqui só a lista de horários (vai no <body>).
   z-index acima de qualquer modal/drawer do portal: a lista só existe enquanto o campo tem foco. */
.ptime-pop {
  position: fixed; z-index: 10000; max-height: 220px; overflow-y: auto; padding: 4px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md);
  box-shadow: 0 10px 40px rgba(0,0,0,.14);
}
.ptime-opt { padding: 6px 12px; border-radius: 5px; cursor: pointer; font-size: 13px; color: var(--text); font-variant-numeric: tabular-nums; }
.ptime-opt:hover { background: var(--surface-2); }
.ptime-opt.sel { background: var(--brand); color: #fff; font-weight: 700; }

/* ===== Copy button inline (obrigatório em colunas com dados — ver CLAUDE.md) ===== */
.copy-btn-inline {
  background: transparent; border: 1px solid var(--border); border-radius: 4px;
  width: 20px; height: 20px; cursor: pointer; display: inline-flex;
  align-items: center; justify-content: center; color: var(--text-4);
  padding: 0; flex-shrink: 0; transition: background .12s, color .12s, border-color .12s;
}
.copy-btn-inline:hover { background: var(--surface-2); color: var(--brand); border-color: var(--brand); }

/* Linha/elemento navegável (padrão do portal — suporta clique do meio/Ctrl p/ nova guia via topbar.js) */
[data-href] { cursor: pointer; }

/* ===== Empty State ===== */
.empty-state { text-align: center; padding: 56px 20px; }
.empty-state svg { width: 40px; height: 40px; margin-bottom: 14px; opacity: .25; color: var(--text-3); }
.empty-state p { font-size: 13px; color: var(--text-3); font-weight: 500; }
.empty-sub { font-size: 12px; color: var(--text-4); margin-top: 4px; }

/* ===== Alert ===== */
.alert {
  padding: 11px 14px; border-radius: var(--radius-md); font-size: 13px;
  margin-bottom: 14px; display: flex; align-items: flex-start; gap: 10px; border: 1px solid;
}
.alert-success { background: var(--success-bg); color: var(--success); border-color: var(--success-border); }
.alert-warning { background: var(--warning-bg); color: var(--warning); border-color: var(--warning-border); }
.alert-danger  { background: var(--danger-bg);  color: var(--danger);  border-color: var(--danger-border); }
.alert-info    { background: var(--info-bg);    color: var(--info);    border-color: var(--info-border); }

/* ===== Polaris Tabs ===== */
/* Faixa de abas destacada (piloto aprovado em /gestao/vendas, 01/10/2026): cartão próprio, abas em
   pílula, a ativa sólida na marca. Dentro de um card a faixa perde a moldura (o card já desenha).
   `flex-wrap` em TODA largura: `.p-tab` é `nowrap`, então sem quebra a 9ª aba vazava o cartão (e
   saía do clique) em qualquer tela — /crm/relatorios chegou a 10 abas e rolava em 1440. Faixa que
   cabe numa linha não muda nada (medido em 13 telas, 07/10). Quando quebra, o `.p-tabs-actions`
   (margin-left:auto) vai pro fim da última linha, à direita — o mesmo desenho do celular abaixo. */
.p-tabs {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px; padding: 6px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm); margin-bottom: 14px;
}
.card .p-tabs, .p-card .p-tabs {
  border: none; border-bottom: 1px solid var(--border); border-radius: 0; box-shadow: none; margin: 0;
}
/* Faixa de abas que ACOMPANHA a rolagem: `.p-tabs.is-sticky` (Nathan, 29/10/2026, pedido no BI).
   Não é default porque a faixa carrega os controles da aba (Filtros, modo), e em tela de LISTA
   longa ela competiria com a barra de ações da própria tabela.
   `top` é a altura da topbar, que já é `sticky top:0` — somar as duas é o que impede a aba de
   passar POR CIMA do breadcrumb em vez de colar embaixo dele.
   ⚠️ `z-index` abaixo do 50 da topbar de propósito: a gaveta de filtros e o calendário abrem
   em `position:fixed` fora do `.page`, então não disputam; quem disputa é só a topbar.
   🚫 O `margin-bottom:14px` herdado não serve aqui: colada, a faixa precisa de fundo opaco e de
   um respiro próprio, senão o conteúdo aparece POR BAIXO dela na borda arredondada. */
.p-tabs.is-sticky {
  position: sticky; top: var(--topbar-h); z-index: 20;
  background: var(--surface); margin-bottom: 16px;
}
.p-tab {
  padding: 8px 16px; font-size: 13px; font-weight: 600; border-radius: var(--radius-md);
  color: var(--text-2); transition: background .1s, color .1s; cursor: pointer; white-space: nowrap; text-decoration: none;
}
button.p-tab { background: none; border: 0; font-family: inherit; }
.p-tab:hover { background: var(--surface-2); color: var(--text); }
.p-tab.active { background: var(--brand); color: #fff; box-shadow: var(--shadow-sm); }
/* Contador da aba ("Abertos 12"). Mesmo nome do portal-gestão. */
.p-tab-count {
  display: inline-block; margin-left: 6px; padding: 0 6px; border-radius: 99px;
  font-size: 11px; font-weight: 600; line-height: 17px; font-variant-numeric: tabular-nums;
  background: var(--surface-3); color: var(--text-3);
}
.p-tab.active .p-tab-count { background: rgba(255,255,255,.25); color: #fff; }
/* Canto direito da faixa de abas: total, botão "Filtros" e a ação primária da aba. A aba escolhe
   a lista e o filtro refina a lista escolhida — é um controle só, e como duas faixas empilhadas
   comiam duas linhas da tela dizendo respeito à mesma coisa.
   `align-self:center` aqui, e NÃO `align-items:center` no `.p-tabs`: as abas precisam esticar até
   o fundo da faixa, senão o sublinhado da ativa desgruda da borda. */
.p-tabs-actions { margin-left: auto; align-self: center; display: flex; align-items: center; gap: var(--sp-2, 8px); padding-right: 4px; }
.p-tabs-total   { font-size: 11.5px; color: var(--text-4); white-space: nowrap; }
/* Celular: abas + ações não cabem numa linha — as ações descem pra linha de baixo, à direita.
   🚫 Não repetir `flex-wrap: wrap` aqui: ele já vale em toda largura no `.p-tabs` acima, e a cópia
   fazia parecer que a quebra era só do celular — foi o que levou a procurar o ajuste duas vezes. */
@media (max-width: 640px) {
  .p-tabs-actions { margin-left: 0; flex-basis: 100%; flex-wrap: wrap; justify-content: flex-end; padding: 4px 0 0; }
}

/* ===== Polaris Filters ===== */
.p-filters {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 14px; border-bottom: 1px solid var(--border);
  background: var(--surface);
}
.p-filter-chips {
  display: flex; gap: 6px; flex-wrap: wrap; align-items: center;
  padding: 8px 14px; background: var(--surface-2); border-bottom: 1px solid var(--border);
}
/* Chip = cartão branco com rótulo apagado + valor forte (piloto aprovado em /gestao/vendas, 01/10/2026).
   `<span class="p-filter-chip-k">Empresa:</span> GMS`; ícone opcional antes, na cor da marca. */
.p-filter-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 6px 4px 10px; border-radius: var(--radius-md);
  background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow-sm);
  font-size: 12px; font-weight: 600; color: var(--text);
  white-space: nowrap;
}
.p-filter-chip > svg { width: 13px; height: 13px; color: var(--brand); flex-shrink: 0; }
.p-filter-chip-k { color: var(--text-3); font-weight: 500; }
.p-filter-chip-remove {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: var(--radius-sm, 4px); margin-left: 1px;
  color: var(--text-3); text-decoration: none; transition: background .15s, color .15s;
}
.p-filter-chip-remove:hover { background: var(--surface-2); color: var(--danger); }
/* "Limpar tudo" no fim da faixa de chips */
.p-filter-chips-clear { margin-left: auto; font-size: 12px; color: var(--text-3); text-decoration: none; white-space: nowrap; padding: 4px 6px; border-radius: var(--radius-md); }
.p-filter-chips-clear:hover { color: var(--danger); background: var(--surface); }
/* Faixa de chips SOLTA (fora de card, colada sob a faixa de abas): sem fundo próprio */
.p-filter-chips.solta { background: none; border: none; padding: 0; margin: -4px 0 14px; gap: 8px; }
.p-filter-chip-remove svg { width: 10px; height: 10px; stroke: currentColor; fill: none; stroke-width: 2.5; }

/* ===== Ranking (.p-rank) — top N com posição, barra relativa e valor (piloto de /gestao/vendas) =====
   Linhas de altura FIXA e `.p-rank-grid` com stretch: cartões lado a lado ficam do mesmo tamanho.
   Linha selecionável: `.is-click` (+ `.is-sel` na escolhida). Ver docs/design-system.md. */
.p-rank-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: stretch; margin-bottom: 14px; }
.p-rank-grid > .card { display: flex; flex-direction: column; margin: 0; }
.p-rank-grid > .card > .p-rank-body { flex: 1; }
@media (max-width: 1200px) { .p-rank-grid { grid-template-columns: 1fr; } }
.p-rank-sub { margin-left: auto; font-size: 11px; color: var(--text-3); white-space: nowrap; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.p-rank { list-style: none; margin: 0; padding: 6px 0; }
.p-rank-row {
  display: grid; grid-template-columns: 28px minmax(0, 1fr) auto; align-items: center; gap: 10px;
  height: 46px; padding: 0 16px; border-bottom: 1px solid var(--border);
}
.p-rank-row:last-child { border-bottom: none; }
.p-rank-row.is-click { cursor: pointer; }
.p-rank-row.is-click:hover { background: var(--surface-2); }
.p-rank-row.is-sel { background: var(--brand-dim); box-shadow: inset 3px 0 0 var(--brand); }
.p-rank-pos {
  width: 24px; height: 24px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 700; color: var(--text-3); background: var(--surface-2);
}
.p-rank-row:nth-child(1) .p-rank-pos { background: var(--brand); color: var(--on-cor); }
.p-rank-row:nth-child(2) .p-rank-pos, .p-rank-row:nth-child(3) .p-rank-pos { background: var(--brand-dim); color: var(--brand-deeper); border: 1px solid var(--brand-border); }
.p-rank-name { min-width: 0; }
.p-rank-name b { display: block; font-size: 13px; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Ranking de PESSOA: foto (.u-avatar) ao lado do nome + trilho — foto sempre (Nathan, 12/10/2026) */
.p-rank-pessoa { display: flex; align-items: center; gap: 10px; }
.p-rank-pessoa > div { min-width: 0; flex: 1; }
.p-rank-pessoa .u-avatar { width: 30px; height: 30px; }
.p-rank-meter { height: 4px; border-radius: 99px; background: var(--surface-2); margin-top: 5px; overflow: hidden; }
.p-rank-meter > span { display: block; height: 100%; background: var(--brand); border-radius: 99px; }
/* line-height curto: valor + subtítulo (2 linhas) precisam caber DENTRO da barra do .is-fill (46 − 2×5px);
   com o 1.6 do body o bloco dava 41px e o número/subtítulo vazavam pra fora da barra. */
.p-rank-val { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; line-height: 1.25; }
.p-rank-val small { display: block; }
.p-rank-val b { display: block; font-size: 13px; font-weight: 700; color: var(--brand-deeper); }
.p-rank-val small { font-size: 11px; color: var(--text-3); }
.p-rank-eye { opacity: 0; transition: opacity .15s; margin-left: 4px; vertical-align: middle; }
.p-rank-row:hover .p-rank-eye { opacity: 1; }
/* .is-fill: a própria linha enche de cor até o valor (--w), no lugar do trilho fino */
.p-rank.is-fill .p-rank-row { position: relative; }
.p-rank.is-fill .p-rank-row::before { content: ""; position: absolute; inset: 5px auto 5px 0; width: var(--w, 0); background: var(--brand-dim); border-right: 2px solid var(--brand-border); border-radius: 0 var(--radius-md) var(--radius-md) 0; pointer-events: none; }
.p-rank.is-fill .p-rank-row > * { position: relative; }
.p-rank.is-fill .p-rank-meter { display: none; }
.p-rank-empty { padding: 32px 16px; text-align: center; color: var(--text-3); font-size: 13px; }
/* Faixa "filtrando por X · Ver todos" quando uma linha do ranking recorta os outros cartões */
.p-rank-sel {
  display: flex; align-items: center; gap: 10px; padding: 10px 14px; margin-bottom: 14px;
  background: var(--brand-dim); border: 1px solid var(--brand-border); border-radius: var(--radius-md);
  font-size: 13px; color: var(--brand-deeper);
}
.p-rank-sel b { font-weight: 700; }
.p-rank-sel button { margin-left: auto; }

/* ===== KPI em card: número + variação + sparkline no rodapé (escolha do Nathan, 01/10/2026) =====
   Rodapé: .p-kpi-spark (canvas, série por dia) OU .p-kpi-meter (taxa, quando não há série).
   Nunca inventar série pra preencher o rodapé. */
.p-kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px; margin-bottom: 16px; }
/* 6 KPIs: 3+3 em vez de 4+2 com buraco; abaixo de 860px volta ao auto-fit */
@media (min-width: 861px) { .p-kpi-grid.is-3col { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.p-kpi { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; display: flex; flex-direction: column; min-width: 0; }
.p-kpi-body { padding: 16px 16px 10px; display: grid; gap: 4px; }
.p-kpi-label { font-size: 11px; font-weight: 600; color: var(--text-3); text-transform: uppercase; letter-spacing: .06em; }
.p-kpi-line { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.p-kpi-value { font-family: var(--font-head); font-size: 24px; font-weight: 700; line-height: 1.15; letter-spacing: -.02em; color: var(--text); font-variant-numeric: tabular-nums; }
.p-kpi-sub { font-size: 12px; color: var(--text-3); }
.p-kpi-sub.is-warn { color: var(--danger); }
.p-kpi-spark { margin-top: auto; height: 48px; position: relative; }
.p-kpi-meter { margin: auto 16px 16px; height: 6px; background: var(--surface-2); border-radius: 99px; overflow: hidden; }
.p-kpi-meter > i { display: block; height: 100%; width: 0; background: var(--brand); border-radius: 99px; transition: width .4s; }
.p-kpi-meter.is-danger > i { background: var(--danger); }
.p-kpi-meter.is-warn > i { background: var(--warning); }
/* Meter empilhado: cada <i> é uma fatia do total (ex.: SLA vencido + a vencer; o resto é o fundo) */
/* Número que é soma de fatias (SLA): anel no canto + 100 quadrados (1 = 1% dos ativos) no rodapé */
.p-kpi.has-ring { position: relative; }
.p-kpi.has-ring .p-kpi-body { padding-right: 84px; }
.p-kpi-ring { position: absolute; top: 14px; right: 14px; width: 60px; height: 60px; }
/* Na barra de resumo a coluna é estreita: com o anel fixo no canto e 88px reservados, o valor
   ("R$ 82.432,78") passava por baixo dele (Cobrança, 22/10/2026). O anel só fica ao lado do número
   quando o ITEM tem largura pra isso; estreito, ele desce pra linha de apoio e o número fica com a
   largura toda. */
.p-summary-item.has-ring { position: relative; display: flow-root; container-type: inline-size; }
.p-summary-item.has-ring .p-kpi-ring { position: static; float: right; width: 44px; height: 44px; margin: 6px 0 0 8px; }
.p-summary-item.has-ring .p-kpi-ring text { font-size: 15px; }
@container (min-width: 220px) {
  .p-summary-item.has-ring > :is(.p-summary-label, .p-summary-value) { margin-right: 70px; }
  .p-summary-item.has-ring .p-kpi-ring { position: absolute; float: none; margin: 0; width: 60px; height: 60px; }
  .p-summary-item.has-ring .p-kpi-ring text { font-size: 13px; }
}
.p-kpi-ring circle { fill: none; stroke-width: 7; }
.p-kpi-ring .is-track { stroke: var(--surface-2); }
.p-kpi-ring .is-brand { stroke: var(--brand); }
.p-kpi-ring .is-good { stroke: var(--success); }
.p-kpi-ring .is-danger { stroke: var(--danger); }
.p-kpi-ring .is-warn { stroke: var(--warning); }
.p-kpi-ring text { fill: var(--text); font-size: 13px; font-weight: 800; font-family: var(--font); }
/* Taxa com meta (escolha do Nathan, 04/10/2026): meter + traço na meta (--meta) + rótulo "meta X" encostado no traço */
.p-kpi-meter.has-meta { position: relative; overflow: visible; margin-bottom: 0; }
.p-kpi-meter.has-meta::after { content: ""; position: absolute; top: -4px; bottom: -4px; left: calc(var(--meta) - 1px); width: 2px; border-radius: 1px; background: var(--text-2); }
.p-kpi-escala { position: relative; height: 14px; margin: 5px 16px 12px; font-size: 10px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.p-kpi-escala > span { position: absolute; top: 0; left: var(--meta); padding-right: 4px; white-space: nowrap; transform: translateX(-100%); }
.p-kpi-waffle { margin: auto 16px 16px; display: grid; grid-template-columns: repeat(25, 1fr); gap: 2px; }
.p-kpi-waffle > i { aspect-ratio: 1; border-radius: 2px; background: var(--surface-2); }
.p-kpi-waffle > i.is-danger { background: var(--danger); }
.p-kpi-waffle > i.is-warn { background: var(--warning); }
/* KPI que NAVEGA (abre a lista filtrada no hub): o card inteiro é o `<a>`. Hover só na borda — o
   mesmo sinal do `.p-summary-item` clicável; KPI que só mostra número fica `<div>`, sem promessa. */
a.p-kpi { text-decoration: none; color: inherit; cursor: pointer; transition: border-color .15s, box-shadow .15s; }
a.p-kpi:hover { border-color: var(--brand-border); box-shadow: var(--shadow); }
.p-delta { display: inline-flex; align-items: center; gap: 3px; font-size: 11.5px; font-weight: 600; padding: 2px 7px; border-radius: 999px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.p-delta:empty { display: none; }
.p-delta.is-good { color: var(--success); background: var(--success-bg); }
.p-delta.is-bad { color: var(--danger); background: var(--danger-bg); }

/* ===== Table meta ===== */
.p-table-meta {
  display: flex; align-items: center; padding: 9px 16px;
  font-size: 12px; color: var(--text-3); background: var(--surface-2);
  border-bottom: 1px solid var(--border); gap: 10px;
}
.p-table-meta strong { color: var(--text-2); font-weight: 600; }

/* ===== Filter Toggle Panel ===== */
.filter-toggle-body {
  overflow: hidden;
  max-height: 0;
  transition: max-height 0.24s ease;
}
.filter-toggle-body.open { max-height: 900px; }
.filter-toggle-chevron { transition: transform 0.2s ease; flex-shrink: 0; }
.filter-toggle-card.open .filter-toggle-chevron { transform: rotate(180deg); }
#filterToggleHeader {
  cursor: pointer;
  user-select: none;
}
#filterToggleHeader:hover { background: var(--surface-2); }

/* ===== Filter Drawer ===== */
.filter-toolbar {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 14px; border-bottom: 1px solid var(--border);
  background: var(--surface); flex-wrap: wrap;
}
.filter-drawer-overlay {
  display: none; position: fixed; inset: 0;
  background: rgba(0,0,0,.35); z-index: 900;
}
.filter-drawer-overlay.open { display: block; }
.filter-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: 340px; max-width: 92vw;
  background: var(--surface); border-left: 1px solid var(--border);
  z-index: 901; display: flex; flex-direction: column;
  transform: translateX(100%); transition: transform .25s ease;
  box-shadow: -4px 0 24px rgba(0,0,0,.1);
}
.filter-drawer.open { transform: translateX(0); }
.filter-drawer-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px; border-bottom: 1px solid var(--border); flex-shrink: 0;
}
.filter-drawer-header h3 { font-size: 15px; font-weight: 600; margin: 0; color: var(--text); }
.filter-drawer-body {
  flex: 1; overflow-y: auto; padding: 16px;
  display: flex; flex-direction: column; gap: 16px;
}
.filter-drawer-section { display: flex; flex-direction: column; gap: 6px; }
.filter-drawer-section-label {
  font-size: 11px; font-weight: 600; color: var(--text-3);
  text-transform: uppercase; letter-spacing: .4px;
}
.filter-drawer-footer {
  padding: 12px 16px; border-top: 1px solid var(--border);
  display: flex; gap: 8px; flex-shrink: 0; background: var(--surface);
}

/* ===== Bancada (.p-work*) — tela de TRABALHAR um registro por vez =====
   Promovido ao design system em 18/09/2026, depois de a tela do CRM nascer com ~120 linhas de CSS
   próprio que duplicavam (mal) o que já existia aqui. O diagnóstico do Nathan na revisão foi o
   resumo exato do problema: "algumas ficam muito grandes, outras muito pequenas, algumas com
   quebra de linha — já não tem tudo isso definido no nosso design system?". Não tinha: existia o
   card, a aba e a linha de info, mas NÃO existia a casca que os arruma numa tela de trabalho.
   Sem ela, cada view inventa a sua, e é por isso que duas seções lado a lado nunca alinham.

   🚫 REGRA: tela de bancada (CRM, atendimento, auditoria) monta-se com estas classes. View que
   precisa de algo que não está aqui ACRESCENTA AQUI, nunca um `.xx-*` local — CSS de layout em
   view é sempre uma divergência esperando acontecer.

   A escala de espaçamento (--sp-*) é a correção de raiz: os containers do portal tinham cinco
   respiros diferentes para o mesmo nível (16/18, 14/18, 13/18, 12/13, 12/18) porque cada um foi
   escrito à mão numa data diferente. Componente novo usa o token, nunca um px solto. */
:root {
  --sp-1: 4px;   /* dentro de uma linha (ícone ↔ texto) */
  --sp-2: 8px;   /* entre irmãos de um grupo (botões, campos) */
  --sp-3: 12px;  /* entre grupos dentro de um bloco */
  --sp-4: 16px;  /* respiro interno padrão de bloco */
  --sp-5: 24px;  /* entre blocos de assunto diferente */
}

/* Faixa de identidade + ações do registro aberto. UMA faixa: quem trabalha o registro precisa do
   nome e das ações no mesmo lugar, sempre visíveis. Duas faixas empilhadas (uma com o título da
   página, outra com o do registro) dizem a mesma coisa duas vezes e empurram o conteúdo. */
.p-workbar {
  display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); margin-bottom: var(--sp-4);
}
.p-workbar-id { min-width: 0; flex: 1 1 260px; }
.p-workbar-title {
  font-family: var(--font-head); font-size: 17px; font-weight: 700;
  color: var(--text); line-height: 1.25; overflow-wrap: anywhere;
}
/* Linha de contexto: os dados que identificam o registro (origem, valor, quando). Separador por
   ::before, nunca "·" escrito na marcação — com um campo vazio o ponto fica órfão no começo. */
.p-workbar-meta {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  font-size: 12px; color: var(--text-3); margin-top: 3px;
}
.p-workbar-meta > * + *::before { content: '·'; color: var(--text-4); margin-right: var(--sp-2); }
.p-workbar-actions { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; margin-left: auto; }

/* Grade da bancada: fila | ficha | trabalho. Os três painéis que HubSpot chama de queue/preview/
   activity. O colapso é em 1400px porque o Odoo mede o mesmo limite em runtime (SIZES.XXL=1534)
   e a operação usa notebook de 1366–1440: a fila (o painel de contexto) sai primeiro, a ficha e o
   trabalho ficam até 980px. 🚫 Nunca esconder a FICHA antes da fila — é o dado da ligação.

   🚫 E o painel que sai da coluna vai para o FIM da grade, nunca `display:none`: conteúdo que só
   existe ali (contador, atalho, KPI) desapareceria da tela em notebook de 1366px sem nenhum aviso
   — foi o que o Nathan pegou em 18/09 ("em uma tela menor algumas coisas somem da tela"). O que
   muda com a largura é ONDE o painel está, não SE ele existe. */
.p-work { display: grid; grid-template-columns: 230px 340px minmax(0,1fr); gap: var(--sp-3); align-items: start; }
.p-work > * { min-width: 0; }
@media (max-width: 1400px) {
  .p-work { grid-template-columns: 320px minmax(0,1fr); }
  /* `order` só reposiciona: a fila desce para uma faixa cheia embaixo, inteira. */
  .p-work-aside { order: 9; grid-column: 1 / -1; }
  /* Na faixa, os cards da fila ficam lado a lado em vez de empilhados — deitada ela ocupa uma
     linha, não três. */
  .p-work-aside > * { flex-direction: row; flex-wrap: wrap; }
  .p-work-aside > * > .card { flex: 1 1 260px; }
  /* Sem isso o item da faixa cresce até o texto `nowrap` da lista e a página rola de lado no
     celular (Central de ajuda, 07/10). */
  .p-work-aside > * > * { min-width: 0; }
}
@media (max-width: 980px)  { .p-work { grid-template-columns: 1fr; } }

/* Variante de DUAS colunas: trilho/contexto + conteúdo, sem a ficha do meio. A base tem três
   (fila 230 + ficha 340 + trabalho) porque a bancada mostra o registro ao lado da fila; onde não
   existe ficha fixa — Meu Portal — o conteúdo tem de ocupar o resto, e não os 340px da coluna 2.
   ⚠️ Precisa do `min-width: 1401px`, não basta vir depois: `.p-work.duas` tem especificidade
   (0,2,0) contra (0,1,0) do `.p-work` dentro do media query de 1400px, e venceria em QUALQUER
   largura — o trilho ficaria preso a 230px no celular em vez de descer, e o media query pareceria
   simplesmente não funcionar. Quem colapsa continua sendo a base. */
@media (min-width: 1401px) { .p-work.duas { grid-template-columns: 230px minmax(0,1fr); } }
/* Abaixo de 1400px a base manda o trilho para a faixa de baixo (`grid-column: 1/-1`) e sobra UM
   filho para um grid de duas colunas — o conteúdo fica preso nos 320px da coluna 1 e o resto da
   tela fica vazio, com a tabela cortando o botão dentro de um card estreito. Na bancada de pedidos
   isso não acontece porque lá sobram DOIS filhos (ficha + trabalho) para as duas colunas; a
   variante `.duas` não tem ficha, então precisa dizer que o que sobrou ocupa a linha inteira. */
@media (max-width: 1400px) { .p-work.duas { grid-template-columns: minmax(0,1fr); } }
/* `.lista-antes`: no celular o trilho SOBE em vez de descer. Onde o trilho É o conteúdo (Notas),
   a base (`order: 9`) abria a tela num editor vazio, com a lista abaixo da dobra. Modificador
   opt-in de propósito: nas outras telas o trilho é contexto e descer é o certo. */
@media (max-width: 768px) { .p-work.duas.lista-antes > .p-work-aside { order: -1; } }

/* Variante ROTEIRO: fila estreita + TRABALHO no meio + consulta na direita. A base põe a ficha
   (340px fixos) na coluna 2 e o histórico no resto; na bancada do CRM é o inverso — o que ela faz
   (ler o resumo, discar, registrar) é o centro da tela, e a linha do tempo é consulta. Foi a
   inversão que o Nathan aprovou em 24/09: "esse deve ser o estilo de design do CRM".
   ⚠️ Mesma pegadinha da `.duas`: precisa do `min-width`, não basta vir depois. Sem ele, (0,2,0)
   vence o media query de baixo em QUALQUER largura e a fila ficaria presa a 200px no celular.

   ⚠️ O corte é 1200px, não os 1400px das outras variantes, e as DUAS regras abaixo mudam juntas —
   mexer numa só deixa uma faixa de larguras sem nenhuma regra (as 3 colunas descolapsam) ou com as
   duas (a de baixo ganha por ordem). Motivo do corte mais baixo: o Nathan trabalha em 1366px com o
   Chrome em 90% de zoom (~1517px CSS) e pediu "quero q caiba as 3 fileiras de seções numa tela
   pequena, com 90% qnd coloco no chrome funciona" — em 100% a mesma tela dá 1366px e caía na versão
   de 2 colunas, empurrando a fila pra faixa de baixo. As três colunas somam 200+320+min = 520px de
   fixo, que cabem com folga em 1200px. */
@media (min-width: 1201px) { .p-work.roteiro { grid-template-columns: 200px minmax(0,1fr) 320px; } }
/* Abaixo do corte a base já manda a `.p-work-aside` (a fila) para a faixa de baixo e sobram DOIS
   filhos — trabalho e consulta — para as duas colunas de 320px+resto. Só que aqui o estreito é o da
   DIREITA (consulta), não o da esquerda: sem inverter, o roteiro com o formulário de registro ficaria
   nos 320px e a linha do tempo levaria a tela inteira. */
/* ⚠️ Com piso em 981px: sem ele as 2 colunas valiam até no celular (400px = 320px de consulta + o
   roteiro espremido em ~50px). Abaixo disso a base (`max-width: 980px`) empilha numa coluna só. */
@media (min-width: 981px) and (max-width: 1200px) { .p-work.roteiro { grid-template-columns: minmax(0,1fr) 320px; } }
/* E a fila só desce para a faixa de baixo no MESMO corte. A base manda a `.p-work-aside` para lá a
   partir de 1400px (a bancada de pedidos tem uma coluna a mais de conteúdo), então entre 1201 e
   1400 o roteiro ficaria com 3 trilhas e só 2 filhos: a fila na faixa de baixo e a consulta na
   coluna que era dela, com 200px de branco na esquerda. Devolver a fila à coluna 1 nessa janela é o
   que fecha o item 1 — as 3 fileiras juntas na tela dele. */
@media (min-width: 1201px) and (max-width: 1400px) {
  .p-work.roteiro > .p-work-aside { order: 0; grid-column: auto; }
  .p-work.roteiro > .p-work-aside > * { flex-direction: column; flex-wrap: nowrap; }
  .p-work.roteiro > .p-work-aside > * > .card { flex: 0 1 auto; }
}
/* ROTEIRO SEM A FILA (item 7, 29/09): a coluna da fila saiu da bancada — a operadora não enxerga
   mais o que ainda vai ser distribuído. Sobram DOIS filhos (trabalho | consulta), e a variante
   existe porque sem ela o roteiro herdaria as 3 trilhas de `.roteiro`, cairia nos 200px da fila e a
   linha do tempo levaria o meio da tela.
   ⚠️ `min-width: 1201px` de novo, e depois da regra de cima: a especificidade é a mesma (0,3,0) da
   `.p-work.roteiro` dentro do media query, então quem ganha é a ORDEM — e sem o `min-width` esta
   regra venceria também o corte de baixo, onde as duas colunas já estão certas. */
@media (min-width: 1201px) { .p-work.roteiro.sem-fila { grid-template-columns: minmax(0,1fr) 320px; } }

/* Coluna de trabalho: aba rola, rodapé fica. Ancorado por flex — 🚫 nunca `position:sticky`, que
   depende do container de scroll certo e falha em silêncio quando alguém aninha um wrapper.
   `align-self: start` porque o filho de grid estica para a altura da linha por padrão (`stretch`):
   com 1 evento na linha do tempo o card descia até o fim da coluna mais alta e sobrava um branco
   enorme dentro da borda (visto em produção em 24/09). O card passa a ter a altura do conteúdo, e
   quem limita quando o conteúdo é grande continua sendo o `max-height` do `.p-work-scroll`. */
.p-work-main { display: flex; flex-direction: column; padding: 0; align-self: start; }
.p-work-scroll { overflow-y: auto; padding: var(--sp-4); max-height: min(52vh, 520px); }
.p-work-foot {
  border-top: 1px solid var(--border); background: var(--surface-2);
  padding: var(--sp-3) var(--sp-4); flex-shrink: 0;
}

/* Busca: campo que ESTICA + botão que não encolhe. O `min-width: 0` é o que impedia o botão de ser
   empurrado para fora da borda do card — input tem largura intrínseca e sem isso não cede. */
.p-busca-linha { display: flex; gap: var(--sp-2); align-items: center; }
.p-busca-linha > .form-input { flex: 1 1 auto; min-width: 0; }
.p-busca-linha > .btn { flex: 0 0 auto; }
/* Recado dentro de um card/painel: o texto de estado vazio e o aviso de só-leitura. */
.p-recado { color: var(--text-3); line-height: 1.6; }
.p-recado.pad { padding: var(--sp-4); }
/* Estado vazio de um painel ALTO (a conversa ainda não escolhida): centrado nos dois eixos. Sem
   isto a frase fica encostada no canto de cima de um retângulo vazio de 500px e a tela lê-se como
   quebrada, não como "falta escolher" (reprovado em 27/10). */
.p-recado.centro {
  height: 100%; display: flex; align-items: center; justify-content: center;
  text-align: center; padding: var(--sp-5);
}
/* Caixa de redigir: textarea que estica + botão alinhado à base dela. */
.p-redigir { display: flex; gap: var(--sp-2); align-items: flex-end; }
.p-redigir > textarea { flex: 1 1 auto; min-width: 0; resize: vertical; }
.p-redigir > .btn { flex: 0 0 auto; }
.p-redigir-dica { color: var(--text-4); margin-top: var(--sp-1); }
/* Faixa do anexo escolhido, ACIMA da caixa de redigir: o arquivo aparece antes de sair e tem como
   desistir. Mandar o arquivo errado pro cliente não tem desfazer no WhatsApp. */
.p-anexo {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3); margin-bottom: var(--sp-2);
  background: var(--bg-2); border: 1px solid var(--border); border-radius: var(--radius-md);
}
/* O nome do arquivo não empurra o botão "Tirar" pra fora: nome longo vira reticências. */
.p-anexo > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Trilho vertical de navegação (.mp-trilho) — lista de destinos dentro de uma `.p-work-aside`.
   Nasceu no Meu Portal: 10 destinos não cabem numa faixa de `.p-tabs` no notebook de 1366px da
   operação (viram scroll horizontal), e a coluna cabe. Use quando a tela TEM mais destinos do que
   uma faixa de abas comporta; com 2 ou 3, `.p-tabs` continua sendo o certo.
   O item é <a> de verdade (cada aba é uma URL): abre em nova guia e sobrevive ao F5. */
/* O trilho vem em FAIXAS: um `.p-sec` por grupo, com o `.p-sec-title` de sempre. Com 10 destinos
   soltos a pessoa varre a lista inteira toda vez; o agrupamento dá o atalho visual. Quem decide o
   conteúdo de cada faixa é `abasAgrupadas()` (src/utils/meu-portal-abas.js).
   🚫 A faixa é `.p-sec`, nunca `.card`: o `.card` tem `overflow:hidden` + `--radius-lg`, e a curva
   maior corta o filete de 3px do título em diagonal (sobra uma vírgula laranja no canto). O
   `.p-sec` existe pra isso — só o espaçamento entre faixas fica aqui. */
.mp-trilho-sec + .mp-trilho-sec { margin-top: var(--sp-2); }
.mp-trilho { display: flex; flex-direction: column; gap: 2px; }
.mp-trilho-i {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3); border-radius: 8px;
  font-size: 13px; color: var(--text-2); text-decoration: none;
}
.mp-trilho-i:hover { background: var(--surface-2); color: var(--text); }
/* Item ativo = --brand-dim + --brand-dark, o MESMO do `.p-railnav`/`.hub-rail`. 🚫 Sem filete na
   borda: o trilho usava `border-left` laranja, que é o único menu do portal fora do padrão. */
.mp-trilho-i.active { background: var(--brand-dim); color: var(--brand-dark); font-weight: 700; }
.mp-trilho-ic { display: flex; flex-shrink: 0; }
.mp-trilho-ic svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* O rótulo encolhe (min-width:0 + ellipsis) pra que o contador nunca seja empurrado pra fora do
   card: é ele que diz que há 13 holerites, e some justo na largura em que a coluna aperta. */
.mp-trilho-tx { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mp-trilho-n {
  flex-shrink: 0; min-width: 20px; padding: 1px 6px; border-radius: 10px;
  background: var(--surface-3); color: var(--text-3);
  font-size: 11px; font-weight: 600; text-align: center; font-variant-numeric: tabular-nums;
}
.mp-trilho-i.active .mp-trilho-n { background: var(--brand); color: #fff; }
/* Acima de 1400px o `.p-work-aside` é coluna lateral de verdade (a bancada de pedidos também some
   pra baixo só abaixo desse corte) — o trilho acompanha o scroll da página em vez de sair de vista
   assim que a pessoa desce a tela, mesmo com 10 destinos. `top` soma a topbar (sticky, `--topbar-h`)
   porque sem isso o trilho gruda sob ela e o primeiro item fica coberto. `max-height`+`overflow`
   evita que, em tela baixa, o trilho mais alto que a viewport fique com o fim inacessível (não tem
   pra onde a PÁGINA rolar mais uma vez o que já é o topo do sticky). */
@media (min-width: 1401px) {
  .p-work-aside:has(> .mp-trilho-sec) {
    /* `align-self: start`: filho de grid estica pra altura da linha por padrão (`stretch`), e um
       aside já com a altura da coluna vizinha não tem sobra de espaço pra `sticky` deslizar dentro
       — o efeito não aparece, sem erro nenhum (mesma pegadinha do `.p-work-main`, linha ~1074). */
    align-self: start;
    position: sticky; top: calc(var(--topbar-h) + var(--sp-4));
    max-height: calc(100vh - var(--topbar-h) - var(--sp-4) * 2);
    overflow-y: auto;
  }
}
/* Abaixo de 1400px o `.p-work-aside` já desce pra faixa de baixo (regra da base, linha ~1018) e
   ocupa a largura inteira: aqui o trilho continua em COLUNA (não deitado) — são até 2 faixas de
   10 destinos ao todo, e lado a lado num notebook de 1366px cada `<a>` teria uma fração de linha,
   cortando o rótulo pelo `ellipsis` do `.mp-trilho-tx`. Foi o "quebra" que o Nathan reportou em
   28/09 comparando as duas larguras. Deitado (`display:flex` na faixa) é certo pra fila de PEDIDOS
   (cards curtos, ver `.p-work-aside > * > .card` acima) — não pro trilho de navegação. */
@media (max-width: 1400px) {
  .mp-trilho-sec + .mp-trilho-sec { margin-top: var(--sp-2); }
}

/* Linha do tempo de eventos (.p-timeline). Histórico de ticket, de chat, de auditoria, tentativas
   do CRM: todas mostram "o que aconteceu, quando" em ordem, e até aqui cada tela desenhava a sua.
   O traço é ::before da LISTA, não de cada item — por item ele sobra abaixo do último e some entre
   os demais. `.on` marca o evento que deu certo (falou com o cliente, ticket resolvido). */
.p-timeline { position: relative; padding-left: 19px; }
.p-timeline::before { content: ''; position: absolute; left: 4px; top: 6px; bottom: 6px; width: 2px; background: var(--border); }
.p-timeline-item { position: relative; padding: var(--sp-2) 0; border-bottom: 1px solid var(--border); }
.p-timeline-item:last-child { border-bottom: none; }
.p-timeline-item::before {
  content: ''; position: absolute; left: -19px; top: 13px;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--surface); border: 2px solid var(--border);
}
.p-timeline-item.on::before { background: var(--success); border-color: var(--success); }
.p-timeline-head { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; font-size: 13px; color: var(--text-2); }
.p-timeline-when { font-size: 11px; color: var(--text-4); font-variant-numeric: tabular-nums; margin-left: auto; }
.p-timeline-body { font-size: 12px; color: var(--text-3); margin-top: 3px; overflow-wrap: anywhere; }

/* Botão com ação secundária no chevron (.btn-split). Uma unidade: a borda do meio é compartilhada
   (margin-left:-1px) e os cantos internos são retos, senão lê como dois botões encostados — foi
   exatamente o que o Nathan apontou ("a divisória não encaixa/engloba os 2"). */
.btn-split { display: inline-flex; }
.btn-split > .btn:first-child { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.btn-split > .btn:last-child {
  border-top-left-radius: 0; border-bottom-left-radius: 0;
  margin-left: -1px; padding-left: 9px; padding-right: 9px;
}
/* O chevron sobrepõe o irmão no hover/aberto pra borda ativa correr inteira, sem degrau. */
.btn-split > .btn:last-child:hover, .btn-split > .btn:last-child.open { position: relative; z-index: 1; }

/* ===== Bancada, 2ª geração: a linguagem visual aprovada em 24/09/2026 =====
   Nathan revisou a bancada do CRM em 5 opções e aprovou a nº 3 com a frase que virou regra:
   "esse deve ser o estilo de design do CRM". O brief dele: "divisões, menos respiro e mais
   agrupamentos, NADA DE ITENS SOLTOS ou botões, respiros inteligentes... principalmente não tire
   o foco e não nos faça perder produtividade".

   As classes abaixo são o que faltava para montar aquela tela SEM CSS de view (as 4 telas do CRM
   têm teto ZERO em test/views-css-proprio.test.js). O que já existia continua valendo e NÃO foi
   duplicado: `.p-sec`/`.p-sec-title` (faixa titulada), `.p-timeline`, `.mp-trilho` (lista de
   destinos com ícone e seta), `.btn-split`, `.info-row`, `.p-work*`, e o `.btn-danger-ghost` (gatilho destrutivo,
   contorno vermelho) para o "Encerrar lead", sem variante nova. O `.btn-danger` sólido é só o
   confirmar dentro do modal.

   A regra de leitura das quatro: SEGMENTO agrupa por assunto na faixa de cima; CHIP é dado de
   contexto que não pode ficar como texto solto; SWITCH é estado que a pessoa liga/desliga o dia
   inteiro; PASSO é a ordem do trabalho quando existe uma. */

/* 1. Faixa de cima SEGMENTADA (.p-workbar.seg). A `.p-workbar` base é uma faixa com identidade à
   esquerda e ações à direita; quando existe um TERCEIRO assunto no meio (o posto de quem trabalha:
   disponibilidade, ramal, placar do turno) ele ficava largado entre os dois — "solto, largado",
   nas palavras dele. Segmentos com divisória de verdade dizem onde cada assunto começa.
   O do meio tem fundo `--surface-2`: é o único que fala da PESSOA, não do registro. */
.p-workbar.seg { display: flex; align-items: stretch; gap: 0; padding: 0; overflow: hidden; flex-wrap: nowrap; }
.p-workbar.seg > .p-workbar-seg {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4); min-width: 0;
}
.p-workbar.seg > .p-workbar-seg + .p-workbar-seg { border-left: 1px solid var(--border); }
/* O 1º segmento (identidade) é o que cede largura; os outros dois têm conteúdo de largura fixa.
   ⚠️ O seletor precisa do `.p-workbar.seg >` na frente: sem ele são (0,2,0) contra (0,3,0) da regra
   de cima, que ganha e devolve `align-items: center` — era exatamente por isso que o nome do
   cliente e a etiqueta apareciam CENTRALIZADOS na faixa ("o nome do cliente ali está desalinhado",
   24/09) enquanto no mock estavam à esquerda. A marcação estava certa; o peso do seletor, não. */
.p-workbar.seg > .p-workbar-seg.id { flex: 1 1 auto; flex-direction: column; align-items: flex-start; gap: 5px; justify-content: center; }
.p-workbar-seg.posto { background: var(--surface-2); flex-shrink: 0; }
.p-workbar-seg.fim { flex-shrink: 0; margin-left: auto; }
/* Divisória interna curta, dentro de um segmento (entre o switch e os números do turno). Não é
   `border-left` de irmão porque separa PARES valor/rótulo, não blocos da faixa. */
.p-workbar-sep { width: 1px; align-self: stretch; margin: 2px 0; background: var(--border); flex-shrink: 0; }
/* Par valor+rótulo do placar do turno. `tabular-nums` porque o número muda a cada lead e sem isso
   a largura pula. */
.p-workbar-num { display: flex; flex-direction: column; line-height: 1.1; }
.p-workbar-num > b { font-size: 15px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.p-workbar-num > span { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: .5px; color: var(--text-3); }
/* Abaixo de 1100px a faixa empilha em vez de espremer: o placar do turno seria o primeiro a
   atravessar a borda, e ele é o que diz a ela quanto já fez hoje. */
@media (max-width: 1100px) {
  .p-workbar.seg { flex-wrap: wrap; }
  .p-workbar.seg > .p-workbar-seg { flex: 1 1 100%; }
  .p-workbar.seg > .p-workbar-seg + .p-workbar-seg { border-left: none; border-top: 1px solid var(--border); }
  .p-workbar-seg.fim { margin-left: 0; }
  /* ⚠️ Empilhar os SEGMENTOS não basta: o conteúdo DENTRO do `.posto` continua numa linha só
     (`flex-wrap` default é `nowrap`) e o `flex-shrink: 0` da :1825 impede de ceder, então abaixo de
     ~480px ele travava em 421px (ou 481px em pausa) e empurrava a PÁGINA INTEIRA pra fora da tela —
     rolagem horizontal, medida em 360/390/430px. Não era sobreposição, era estouro. Aqui ele
     embrulha em duas linhas (61px → 96px de altura) e nada é cortado.
     🚫 As divisórias somem porque separam blocos na HORIZONTAL: com o conteúdo em duas linhas elas
     viram risco no meio do nada — quem separa passa a ser o `row-gap`. */
  .p-workbar.seg > .p-workbar-seg.posto { flex-wrap: wrap; row-gap: var(--sp-2); flex-shrink: 1; }
  .p-workbar.seg > .p-workbar-seg.posto > .p-workbar-sep { display: none; }
}

/* 2. Chip de contexto (.p-chip). O dado que qualifica o registro — empresa, quando entrou, qual
   tentativa — em caixa própria com ícone. A `.p-workbar-meta` separa por "·" e serve pra resumo
   curto; a partir de ~3 dados ela lê como frase corrida e some no meio da faixa ("jogado ali,
   solto"). 🚫 Ícone é SVG inline de traço, nunca emoji.
   `.p-chip-set` é o container — ele, e não o chip, carrega o gap. */
.p-chip-set { display: flex; align-items: center; gap: var(--sp-1); flex-wrap: wrap; min-width: 0; }
/* ⚠️ `[hidden]` do navegador é `display:none` com especificidade ZERO: QUALQUER regra de classe
   que declare `display` passa por cima dele, e o elemento marcado como escondido DESENHA — sem
   erro no console e sem nada na tela que explique. Foi o que aconteceu com o chip de lead e o de
   resposta do /crm/chat (16/10/2026): dois botões "Tirar" soltos acima do compositor, sem
   mensagem nenhuma. A regra abaixo vale pro portal inteiro e é o lugar certo: cada view
   relembrar disso é o que já falhou. Quem precisar mostrar um elemento TIRA o atributo
   (`el.hidden = false`), nunca mexe no `style.display`. */
[hidden] { display: none !important; }
.p-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 8px; font-size: 11.5px; color: var(--text-2);
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius);
  max-width: 100%; min-width: 0;
}
.p-chip > svg { width: 12px; height: 12px; flex-shrink: 0; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; color: var(--text-4); }
.p-chip > b { font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.p-chip.alerta { background: var(--brand-dim); border-color: var(--brand-border); color: var(--brand-dark); }
.p-chip.alerta > svg { color: currentColor; }
/* Chip que FILTRA a lista logo abaixo (`<a class="p-chip filtro">`). Só aqui o chip é clicável —
   o `.p-chip` normal é informação, e dar cursor de mão a informação promete uma ação que não existe.
   O ponto de cor à esquerda identifica a origem sem aninhar um `.badge` dentro do chip, que
   empilharia duas caixas com borda na mesma linha. 🚫 A cor vem do MESMO `--c` que a `.p-evtag`
   recebe das classes `t-*` (ver item 6): chip e etiqueta falando da mesma origem com cores
   diferentes é a tela se contradizendo — por isso o ponto não tem paleta própria.
   ⚠️ Serve pra UMA linha curta de texto que leva a algum lugar. Link de filtro que carrega
   NÚMEROS (na fila / total / valor) é `.p-balde` logo abaixo — foi tentar isso aqui que quebrou
   as tags de /crm/leads em 25/09. */
a.p-chip.filtro { text-decoration: none; cursor: pointer; }
a.p-chip.filtro:hover { border-color: var(--border-3); background: var(--surface-3); }
a.p-chip.filtro.alerta:hover { background: var(--brand-dim); border-color: var(--brand); }
.p-chip > .p-chip-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; background: var(--c, var(--text-4)); }

/* 2b. Balde de origem (.p-balde). Atalho de FILTRO que carrega a etiqueta da origem + os números
   daquela origem. Nasceu porque o `.p-chip` não dá conta deste caso: o chip é uma linha só de
   texto curto, e aqui são quatro informações (origem, na fila, total, valor) — enfiadas num chip
   com `align-items:center`, o rótulo "Cartão recusado" quebrava em 3 linhas e desalinhava o resto
   (reprovado por ele em 25/09: "todas as tags ali estao bugadas").

   A ORIGEM é a `.p-evtag` — a mesma etiqueta da bancada, com a cor do tipo. 🚫 Os números NÃO
   entram dentro dela: ela tem `white-space:nowrap` e é o rótulo, não a caixa.

   `align-items: stretch` + coluna nos números: o valor encosta na direita e os baldes ficam com a
   mesma altura independente do tamanho do rótulo.

   🚫 O BALDE NÃO TEM LARGURA PRÓPRIA: é `flex: 1 1 0` numa faixa de 4 colunas iguais, nunca
   `inline-flex` do tamanho do conteúdo. Medido em 28/09: os quatro rótulos têm largura diferente
   ("PIX GERADO" ~109px, "CARRINHO ABANDONADO" ~174px) e com o conteúdo mandando na largura a faixa
   pede ~1460px. A coluna de conteúdo de `/crm/leads` dá ~1140px no notebook de 1440px e ~1070px no
   de 1366px que a operação usa — então o `flex-wrap` fazia o que foi mandado: três baldes na
   primeira linha, o quarto sozinho na segunda, cada um de uma largura. É o "estão ruins, quebrados,
   mal alocados" dele (28/09) e o mesmo defeito atinge o rodapé da `/crm/supervisao`, que usa esta
   MESMA marcação.
   🚫 NADA SE CORTA (15/10, "tá muito mal organizado… pode aumentar o espaço"): numa linha só,
   etiqueta + números + valor disputavam ~270px e quem cedia era a sub-linha, com reticências —
   "CARRINHO ABANDONADO 6 na…". Agora o balde é uma GRADE de duas linhas e cresce em ALTURA:
     1ª linha: o rótulo (a `.p-evtag`, ou `.p-balde-t` no nicho), sozinho, inteiro;
     2ª linha: a contagem grande + "na fila de N" à esquerda, o valor à direita.
   A hierarquia é a ordem de leitura dele: de quê → quantos esperando → de quantos → quanto vale. */
.p-balde-set { display: flex; align-items: stretch; gap: var(--sp-2); flex-wrap: wrap; min-width: 0; }
.p-balde {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: end;
  column-gap: var(--sp-3); row-gap: var(--sp-2);
  flex: 1 1 0; min-width: 0;
  padding: 10px 12px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface); text-decoration: none;
}
.p-balde:hover { border-color: var(--border-3); background: var(--surface-2); }
/* Selecionado = ESTE filtro está aplicado. A borda na cor da marca (e não a cor da origem) porque
   quem fala aqui é o ESTADO do filtro, não o tipo — a cor do tipo já está na etiqueta dentro. */
.p-balde.sel { border-color: var(--brand); background: var(--brand-dim); }
/* O rótulo ocupa a 1ª linha inteira e não estica (a etiqueta é do tamanho do texto). */
.p-balde > .p-evtag, .p-balde-t { grid-column: 1 / -1; justify-self: start; align-self: start; }
/* Rótulo LIVRE (nome de nicho, vem do catálogo e pode ser longo): quebra linha, nunca reticências. */
.p-balde-t { font-size: 12px; font-weight: 600; color: var(--text); line-height: 1.3; overflow-wrap: anywhere; }
.p-balde-n { display: flex; flex-direction: column; gap: 2px; line-height: 1.15; min-width: 0; }
.p-balde-n > b { font-size: 20px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
/* A sub-linha QUEBRA em vez de cortar: o balde pode crescer em altura, o texto não some. */
.p-balde-n > span { font-size: 11px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.p-balde-v {
  font-size: 14px; font-weight: 700; color: var(--text); white-space: nowrap; text-align: right;
  font-variant-numeric: tabular-nums;
}
/* Abaixo de ~1200px de coluna de conteúdo os quatro baldes não cabem em 4 colunas sem comer o
   valor — aí a faixa vira 2×2, que é uma grade legível, e não três-e-um desalinhado. O limite é a
   LARGURA DA JANELA porque é o que o CSS sabe medir: 1200px de janela ≈ 900px de coluna (menos a
   sidebar de 220px e os respiros), que é onde o valor começava a truncar na medição de 28/09. */
@media (max-width: 1200px) {
  .p-balde { flex: 1 1 calc(50% - var(--sp-2)); }
}
@media (max-width: 768px) {
  /* No telefone o balde ocupa a linha inteira: quatro informações em 4 colunas dentro de ~360px
     truncariam o valor, que é justamente o que a gestão olha. */
  .p-balde { flex: 1 1 100%; }
}

/* Baldes como COLUNA LATERAL da tabela (/crm/leads — opção A6, Nathan, 15/10/2026). Mesma marcação
   do balde; aqui só muda a casca: dentro do card, cartão arredondado aninhado é ruído, então o item
   é chapado (só a linha de baixo) e o selecionado é fundo da marca + barra de 2px à esquerda. Os
   números ficam numa linha só — "N na fila de M · R$" —, o valor mora DENTRO do .p-balde-n. */
/* Grade 2×2: o rótulo de cima do trilho e a faixa das abas dividem a MESMA linha da grade, então a
   linha de baixo dos dois cai no mesmo pixel sem altura escrita à mão (altura fixa desalinhava assim
   que a faixa ganhava um botão). */
.p-leads-layout { display: grid; grid-template-columns: 240px minmax(0, 1fr); grid-template-rows: auto 1fr; }
.p-leads-layout > .p-leads-rail-h.is-top { grid-column: 1; grid-row: 1; display: flex; align-items: center; padding: 0 14px; background: var(--surface-2); border-right: 1px solid var(--border); }
.p-leads-layout > .p-tabs { grid-column: 2; grid-row: 1; }
.p-leads-layout > .p-leads-rail { grid-column: 1; grid-row: 2; }
.p-leads-layout > .p-leads-main { grid-column: 2; grid-row: 2; }
.p-leads-rail { min-width: 0; background: var(--surface-2); border-right: 1px solid var(--border); }
.p-leads-rail-h {
  padding: 12px 14px 8px; font-size: 10.5px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text-3); border-bottom: 1px solid var(--border);
}
.p-balde-set + .p-leads-rail-h { margin-top: var(--sp-3); border-top: 1px solid var(--border); }
.p-leads-main { min-width: 0; transition: opacity .12s; }
.p-leads-main[aria-busy="true"], .p-leads-rail[aria-busy="true"] { opacity: .55; pointer-events: none; }
.p-balde-set.is-rail { flex-direction: column; flex-wrap: nowrap; gap: 0; }
.p-balde-set.is-rail > .p-balde {
  flex: 0 0 auto; grid-template-columns: minmax(0, 1fr); row-gap: 6px;
  padding: 10px 14px; border: 0; border-bottom: 1px solid var(--border); border-radius: 0;
  background: transparent;
}
.p-balde-set.is-rail > .p-balde:hover { background: var(--surface); }
.p-balde-set.is-rail > .p-balde.sel { background: var(--brand-dim); box-shadow: inset 2px 0 0 var(--brand); }
.p-balde-set.is-rail .p-balde-n { flex-direction: row; flex-wrap: wrap; align-items: baseline; column-gap: 5px; row-gap: 2px; }
.p-balde-set.is-rail .p-balde-n > b { font-size: 15px; }
.p-balde-set.is-rail .p-balde-v { font-size: 12.5px; text-align: left; }
.p-balde-set.is-rail .p-balde-v::before { content: '· '; font-weight: 400; color: var(--text-4); }
/* Abaixo de 980px não sobra largura pra tabela ao lado do trilho: ele volta a ser faixa em cima,
   os baldes lado a lado (dois por linha), ainda chapados. */
@media (max-width: 980px) {
  .p-leads-layout { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; }
  .p-leads-layout > .p-tabs { grid-column: 1; grid-row: 1; }
  .p-leads-layout > .p-leads-rail-h.is-top { grid-column: 1; grid-row: 2; padding: 10px 14px 8px; border-right: 0; }
  .p-leads-layout > .p-leads-rail { grid-column: 1; grid-row: 3; }
  .p-leads-layout > .p-leads-main { grid-column: 1; grid-row: 4; }
  .p-leads-rail { border-right: 0; border-bottom: 1px solid var(--border); }
  .p-balde-set.is-rail { flex-direction: row; flex-wrap: wrap; }
  .p-balde-set.is-rail > .p-balde { flex: 1 1 calc(50% - 1px); border-right: 1px solid var(--border); }
}
@media (max-width: 560px) {
  .p-balde-set.is-rail > .p-balde { flex-basis: 100%; border-right: 0; }
}

/* Régua do funil na coluna Situação (/crm/leads — opção 3, Nathan, 15/10/2026). Pequena de
   propósito: etapa 12px, nota 11px, régua de 3px. Nada quebra linha — a nota corta com reticências. */
.p-funil { --c: var(--text-3); display: grid; gap: 4px; min-width: 0; max-width: 220px; }
.p-funil.is-warning { --c: var(--warning); }
.p-funil.is-info { --c: var(--info); }
.p-funil.is-success { --c: var(--success); }
.p-funil-top { display: flex; align-items: baseline; gap: 6px; min-width: 0; white-space: nowrap; }
.p-funil-top > b { flex: none; font-size: 12px; font-weight: 600; color: var(--c); }
.p-funil-top > small { min-width: 0; margin-left: auto; overflow: hidden; text-overflow: ellipsis; font-size: 11px; color: var(--text-3); }
.p-funil-bar { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 2px; }
.p-funil-bar > i { height: 3px; border-radius: 2px; background: var(--border); }
.p-funil-bar > i.on { background: var(--c); }

/* Números do topo em DOIS blocos compactos: quantidade × valor (/crm/leads — opção D, Nathan,
   15/10/2026). Os 6 .p-kpi grandes ocupavam a dobra e quebravam linha; a nota vai no title. */
/* Status como ponto colorido + texto, sem caixa (Atendimento em /relatorios/cobranca) */
.p-dot { --c: var(--text-4); display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; font-size: 12.5px; font-weight: 600; color: var(--text); }
.p-dot::before { content: ''; width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--c); }
.p-dot.is-success { --c: var(--success); } .p-dot.is-danger { --c: var(--danger); } .p-dot.is-warning { --c: var(--warning); } .p-dot.is-info { --c: var(--info); }
.p-kpi-duo { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 8px; margin-bottom: 12px; }
.p-kpi-duo > section { min-width: 0; display: grid; gap: 4px; padding: 8px 12px 10px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md); }
.p-kpi-duo-h { font-size: 10.5px; font-weight: 600; color: var(--text-4); }
.p-kpi-duo-row { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 12px; }
.p-kpi-duo-row > * { min-width: 0; display: grid; gap: 1px; color: inherit; text-decoration: none; }
.p-kpi-duo-row .p-kpi-label { font-size: 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.p-kpi-duo-row > a:hover .p-kpi-label { color: var(--brand); }
.p-kpi-duo-v {
  display: flex; align-items: center; gap: 6px; white-space: nowrap;
  font-family: var(--font-head); font-size: 16px; font-weight: 700; line-height: 1.25;
  color: var(--text); font-variant-numeric: tabular-nums;
}
.p-kpi-duo-v > small { font-family: var(--font); font-size: 11px; font-weight: 600; color: var(--text-3); }
.p-kpi-duo-v .p-kpi-ring { position: static; width: 18px; height: 18px; flex: none; }
.p-kpi-duo-v .p-kpi-ring circle { stroke-width: 10; }
.p-kpi-duo-v .p-kpi-ring text { display: none; }
@media (max-width: 860px) { .p-kpi-duo { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 480px) { .p-kpi-duo-row { grid-auto-flow: row; grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* 3. Interruptor (.p-switch). Estado que a pessoa liga e desliga o tempo todo — "Disponível" no
   CRM. Era um `.btn` que trocava de rótulo, e botão não mostra estado: ela não sabia, olhando, se
   estava recebendo lead ou não (pedido dele: "o botão de Disponível pode ter um SWITCH de ON OFF").
   É um <label> com <input type=checkbox> dentro, escondido mas presente: teclado e leitor de tela
   continuam funcionando, e o estado é o do próprio input, não uma classe que o JS precisa lembrar. */
.p-switch { display: inline-flex; align-items: center; gap: 9px; cursor: pointer; min-width: 0; }
.p-switch > input { position: absolute; opacity: 0; width: 0; height: 0; }
.p-switch-track {
  position: relative; display: inline-flex; flex-shrink: 0;
  width: 36px; height: 20px; border-radius: 10px;
  background: var(--border-3); transition: background .18s;
}
.p-switch-track::after {
  content: ''; position: absolute; top: 2px; left: 2px;
  width: 16px; height: 16px; border-radius: 50%;
  background: #fff; transition: left .18s;
}
.p-switch > input:checked + .p-switch-track { background: var(--success); }
.p-switch > input:checked + .p-switch-track::after { left: 18px; }
.p-switch > input:focus-visible + .p-switch-track { outline: 2px solid var(--brand); outline-offset: 2px; }
.p-switch > input:disabled + .p-switch-track { opacity: .5; }
.p-switch > input:disabled ~ .p-switch-tx { opacity: .6; }
.p-switch-tx { display: flex; flex-direction: column; line-height: 1.15; min-width: 0; }
.p-switch-tx > b { font-size: 12.5px; font-weight: 600; color: var(--text); }
.p-switch-tx > span { font-size: 10.5px; color: var(--text-3); }
.p-switch-tx > span > b { color: var(--text-2); font-weight: 600; font-variant-numeric: tabular-nums; }

/* 4. Passo numerado (.p-step). Para a tela cujo trabalho TEM uma ordem: no CRM, ler antes de
   discar → discar → registrar. Card por passo, número no cabeçalho, e a ação primária do passo
   dentro DELE — era isso que estava errado na bancada antiga: o telefone num card e o botão
   "Ligar" no canto oposto da tela.
   🚫 Não é decoração: numerar só vale quando a ordem carrega informação (regra do design system).
   Tela sem ordem natural continua usando `.p-sec`. */
.p-steps { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.p-step {
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--surface); overflow: hidden; min-width: 0;
}
.p-step-head {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 8px var(--sp-4); background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.p-step-n {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 19px; height: 19px; border-radius: 50%;
  background: var(--graphite); color: #fff;
  font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.p-step-t { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .6px; color: var(--text-3); }
/* Tudo o que vier depois do título encosta na direita (aviso do passo, contador). */
.p-step-head > .p-step-t + * { margin-left: auto; }
/* ⚠️ Exceção: a etiqueta do EVENTO fica JUNTO do título, não na direita. Ela qualifica o passo
   ("informações DE QUÊ"), então lê como parte do rótulo — jogada pro canto oposto ela volta a ser
   o "mal posicionado" que ele reprovou na faixa. Precisa da regra porque a de cima pega `+ *`, ou
   seja, QUALQUER elemento depois do título, e a etiqueta é o primeiro. O que vier depois dela
   (badge, contador) continua indo pra direita — por isso o `+ *` repetido abaixo. */
.p-step-head > .p-step-t + .p-evtag { margin-left: 0; }
.p-step-head > .p-step-t + .p-evtag + * { margin-left: auto; }
.p-step-body { padding: var(--sp-3) var(--sp-4); min-width: 0; }
/* Linha extra dentro do passo, separada por divisória — endereço embaixo do contato, por exemplo.
   Mesma banda, assunto vizinho: um card novo aqui quebraria o agrupamento do passo. */
.p-step-row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-4); min-width: 0;
  border-top: 1px solid var(--border); background: var(--surface-2);
}
/* O passo ATIVO (aquele cuja ação é a da vez) veste a marca: borda e cabeçalho da cor dela, e o
   número preenchido. Um passo em destaque, nunca dois — senão nenhum é. */
.p-step.on { border-color: var(--brand-border); }
.p-step.on > .p-step-head { background: var(--brand-dim); border-bottom-color: var(--brand-border); }
.p-step.on .p-step-n { background: var(--brand); }
/* Grade de fatos dentro de um passo: células com divisória, não cards soltos. `auto-fit` some com
   a coluna quando não cabe, em vez de espremer (regra de responsividade do design system). */
.p-step-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.p-step-grid > * { padding: var(--sp-3) var(--sp-4); min-width: 0; border-left: 1px solid var(--border); }
.p-step-grid > *:first-child { border-left: none; }
.p-step-cel-t { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .6px; color: var(--text-3); margin-bottom: var(--sp-1); }
/* Atalho do WhatsApp: SÓ o ícone, maior, sem fundo nem contorno — pedido dele em 24/09 ("aumente o
   tamanho do botão do WhatsApp e remova o background e bordas envolta dele, deixe só o ícone").
   Não é `.btn` de propósito: a caixa do `.btn-secondary` competia com o "Discar", que é a ação
   primária da faixa. O alvo de clique continua com 40px (o glifo tem 30) porque tirar a moldura não
   pode tirar a área clicável — é o que faria o ícone-só virar alvo pequeno no touch. */
.p-wa {
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  width: 40px; height: 40px; border-radius: var(--radius); background: none; border: 0; padding: 0;
  cursor: pointer; transition: opacity .12s ease, background-color .12s ease;
}
.p-wa > img { display: block; width: 30px; height: 30px; }
.p-wa:hover { background: var(--surface-2); }
.p-wa:active { opacity: .7; }
/* Desligado (19/10/2026): o CRM mostra o ícone apagado enquanto o nosso WhatsApp não está integrado,
   em vez de sumir com ele — sumir faria a vendedora procurar o botão achando que a tela quebrou.
   É um <span>, não <a>: sem href não há o que clicar.
   🚫 Sem `pointer-events:none`: ele mataria o `title`, que é justamente onde está escrito POR QUE o
   botão está apagado — o ícone cinza sem explicação vira chamado pra supervisão. */
.p-wa.is-off { opacity: .35; filter: grayscale(1); cursor: not-allowed; }
.p-wa.is-off:hover { background: none; }

/* 4b. ETAPA DE SEQUÊNCIA (.p-seq / .p-seq-i). Card por canal de contato, lado a lado, cada um com um
   de quatro estados: a vez dela, já feita (repetível), travada. Nasce do item A do CRM 2.0 — a
   sequência liga → liga por WhatsApp → mensagem.
   🚫 NÃO é `.p-balde` nem `.p-chip`: balde é filtro de lista (clicar filtra a tela), chip é rótulo.
      Aqui cada card É UMA AÇÃO e tem estado próprio — reaproveitar o balde faria "travado" e
      "não selecionado" virarem o mesmo cinza, e é justamente a diferença que a tela precisa dizer.
   🚫 É `<button>`, nunca `div onclick`: estado travado precisa de `disabled` de verdade (o leitor de
      tela anuncia, e o Tab pula), e o `:disabled` abaixo pendura o visual nele em vez de numa classe
      que alguém esquece de trocar.
   A hierarquia dos estados é só DUAS cores: a marca para a etapa da vez (é a ação primária da tela)
   e o verde de sucesso para o que já foi feito. Travado não ganha cor nenhuma — some pro fundo.
   ⚠️ O artefato pinta cada canal com uma cor própria (laranja, verde-WhatsApp, verde-claro). Aqui
   não: cor por canal competiria com a cor de ESTADO, que é a informação que ela usa. O canal se
   distingue pelo ícone e pelo rótulo. */
.p-seq { display: flex; flex-wrap: wrap; gap: var(--sp-2); min-width: 0; }
.p-seq-i {
  position: relative; flex: 1 1 190px; min-width: 0;
  display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
  text-align: left; font-family: inherit; color: var(--text);
  padding: var(--sp-3); padding-top: 26px;
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--surface); cursor: pointer;
  transition: border-color .12s ease, background-color .12s ease;
}
.p-seq-i:hover:not(:disabled) { border-color: var(--brand-border); }
.p-seq-ic {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 38px; height: 38px; border-radius: var(--radius);
  background: var(--surface-2); color: var(--text-2);
}
.p-seq-ic > svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round; }
.p-seq-t { font-size: 13px; font-weight: 600; }
/* A legenda troca de texto por estado ("grava sozinho" / "2 tentativas" / "libera na sequência"), e
   é ela que explica POR QUE o card está travado — sem isso o cinza é só um botão quebrado. */
.p-seq-s { font-size: 11px; color: var(--text-3); line-height: 1.3; }
/* Selo no canto: o estado em uma palavra. Absoluto porque o rótulo do canal precisa começar na mesma
   altura nos três cards — selo no fluxo empurraria o texto pra baixo só onde o selo é maior. */
.p-seq-b {
  position: absolute; top: var(--sp-2); right: var(--sp-2);
  font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .5px;
  padding: 2px 7px; border-radius: 999px;
  background: var(--surface-2); color: var(--text-3); border: 1px solid var(--border);
}
/* A VEZ DELA: veste a marca, igual ao `.p-step.on` — é o mesmo significado ("a ação é esta"), então
   é a mesma cor. Dois cards nunca têm `.agora` ao mesmo tempo. */
.p-seq-i.agora { border-color: var(--brand); background: var(--brand-dim2); }
.p-seq-i.agora .p-seq-ic { background: var(--brand-dim); color: var(--brand-dark); }
.p-seq-i.agora .p-seq-b { background: var(--brand); color: #fff; border-color: var(--brand); }
/* FEITA: verde de sucesso, e continua clicável — repetir é o trabalho bem feito, não exceção. */
.p-seq-i.feita { border-color: var(--success-border); background: var(--success-bg); }
.p-seq-i.feita .p-seq-ic { background: var(--success-bg); color: var(--success); }
.p-seq-i.feita .p-seq-s { color: var(--success); }
.p-seq-i.feita .p-seq-b { background: var(--success); color: #fff; border-color: var(--success); }
/* TRAVADA: `:disabled`, nunca uma classe. Sem cor, sem sombra e sem cursor de clique. */
.p-seq-i:disabled { cursor: not-allowed; opacity: .55; background: var(--surface-2); }
.p-seq-i:disabled .p-seq-ic { background: var(--surface); }

/* 5. Selo de ORIGEM na linha do tempo (.p-timeline-selo). Nasce da decisão de 24/09: as quatro
   abas da bancada (tentativas, chamadas da central, histórico no CRM) viraram UMA linha do tempo
   filtrada por multiselect, porque são todas evento datado do mesmo cliente. Misturadas sem selo,
   porém, a tela apagaria de quem cada linha veio — e é justamente a DISCORDÂNCIA entre o que a
   vendedora registrou e o que a central gravou que a supervisão precisa ver. */
.p-timeline-selo {
  font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: .4px;
  color: var(--text-3); background: var(--surface-2);
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 1px 6px; white-space: nowrap;
}

/* 6. Etiqueta do EVENTO (.p-evtag). O que aconteceu na venda — cartão recusado, pix gerado, pix
   vencido, boleto vencido, carrinho abandonado — é o dado que muda o roteiro da ligação inteira:
   quem teve cartão recusado quer pagar e não conseguiu; quem abandonou carrinho nunca tentou. Por
   isso é etiqueta com cor e ícone próprios, e não um `.p-chip` cinza igual aos outros. Ficou no
   cabeçalho do passo 1 por decisão dele em 24/09: "coloque essa tag no passo 1 INFORMAÇÕES DO LEAD
   e troque o nome só para INFORMAÇÕES, assim enxugamos" — na faixa de cima ela competia com o nome
   do cliente e ele a reprovou quatro vezes.

   🚫 A cor entra por classe de TIPO (`.t-recusa`…), que seta as três variáveis; a etiqueta só as
   consome. Variante ou tela nova NÃO redefine paleta — é o que garante a mesma cor do evento na
   bancada, na fila e no kanban.

   ⚠️ O rótulo não sai de `TIPO_LABEL`: são 5 etiquetas para 4 tipos, porque `pix_nao_pago` lê
   GERADO ou VENCIDO conforme o prazo real do QR. Quem decide é `etiquetaEvento()` em
   `src/services/crm-leads.js` — fonte única, nunca um `if` no EJS. */
:root {
  --e-recusa: #b03127;  --e-recusa-dim: #fdecea;  --e-recusa-line: #f0c9c4;
  /* Pix GERADO é azul, não verde: verde leria como "pago", e o lead existe justamente porque não
     foi pago (pedido dele em 24/09: "só mude a cor do PIX GERADO"). */
  --e-pixger: #1f5f8c;  --e-pixger-dim: #e9f2f8;  --e-pixger-line: #bcd6e6;
  --e-pixvenc: #9a6410; --e-pixvenc-dim: #fdf3e3; --e-pixvenc-line: #ecd8ae;
  --e-boleto: #8a4aa3;  --e-boleto-dim: #f7effb;  --e-boleto-line: #e0c8ea;
  --e-aband: #4a5560;   --e-aband-dim: #eef0f2;   --e-aband-line: #d4d9de;
}
.p-evtag {
  display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto;
  padding: 3px 9px 3px 8px; border-radius: 5px; white-space: nowrap;
  background: var(--c-dim); color: var(--c); border: 1px solid var(--c-line);
  font-size: 10.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  line-height: 15px;
}
.p-evtag > svg {
  width: 13px; height: 13px; flex: 0 0 auto;
  fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round;
}
/* As classes `t-*` são declaradas SEM prefixo de elemento de propósito: quem veste a cor da origem
   é a `.p-evtag` (etiqueta do evento) e também o `.p-chip-dot` do chip de filtro. Amarrá-las a
   `.p-evtag` faria o chip cair no fallback cinza e a mesma origem aparecer de duas cores na tela. */
.t-recusa  { --c: var(--e-recusa);  --c-dim: var(--e-recusa-dim);  --c-line: var(--e-recusa-line); }
.t-pixger  { --c: var(--e-pixger);  --c-dim: var(--e-pixger-dim);  --c-line: var(--e-pixger-line); }
.t-pixvenc { --c: var(--e-pixvenc); --c-dim: var(--e-pixvenc-dim); --c-line: var(--e-pixvenc-line); }
.t-boleto  { --c: var(--e-boleto);  --c-dim: var(--e-boleto-dim);  --c-line: var(--e-boleto-line); }
.t-aband   { --c: var(--e-aband);   --c-dim: var(--e-aband-dim);   --c-line: var(--e-aband-line); }
/* Lead pago (upsell) é a OUTRA fila e não tem cor de evento perdido: veste a marca. */
.t-pago    { --c: var(--brand-dark); --c-dim: var(--brand-dim);    --c-line: var(--brand-border); }
/* Lead de lista importada (Bloco 12): também não é evento perdido — mesma família da marca. */
.t-lista   { --c: var(--brand-dark); --c-dim: var(--brand-dim);    --c-line: var(--brand-border); }

/* 7. Segmented control (.p-seg). Duas ou três VISTAS da mesma lista, dentro de um card estreito.

   🚫 Não é `.p-tabs`: aquilo é navegação de PÁGINA — sublinhado, largura toda, altura de faixa. Num
   card de 200px o componente de página pesa mais que a lista que ele governa, e foi exatamente o que
   ele reprovou em 24/09 ("toggle entre LEAD e ORIGEM tá feio"). A regra que separa os dois: `.p-tabs`
   troca o CONTEÚDO da tela, `.p-seg` troca o RECORTE de uma lista que já está na tela.

   O estado ativo é `aria-pressed="true"`, não uma classe: o controle é um grupo de botões que
   alternam, e o leitor de tela precisa ouvir qual está pressionado. Estilo e acessibilidade saem do
   mesmo atributo — com classe, os dois divergem no primeiro toggle escrito à mão.

   ⚠️ O seletor vale pra `button` E pra `a` (`> button, > a`). Quando cada vista é um DESTINO
   (troca a URL, dá pra abrir em outra aba, o back volta), o elemento certo é `<a>` — e com o
   seletor só em `button` os links ficavam SEM padding, sem separador e sem estado, virando três
   palavras coladas dentro de uma caixa cinza. Era o "header tá bem feio" de /crm/leads (25/09):
   não faltava regra de estilo, faltava o seletor casar com a marcação. */
.p-seg {
  display: inline-flex; background: var(--surface-3); border: 1px solid var(--border);
  border-radius: 8px; padding: 3px; gap: 3px; max-width: 100%;
}
.p-seg > button,
.p-seg > a {
  font: inherit; font-size: 12px; font-weight: 600; line-height: 1.4;
  padding: 4px 12px; border: 0; border-radius: 5px;
  background: none; color: var(--text-3); cursor: pointer; white-space: nowrap;
  text-decoration: none; display: inline-flex; align-items: center;
}
.p-seg > button:hover,
.p-seg > a:hover { color: var(--text); }
.p-seg > button[aria-pressed="true"],
.p-seg > a[aria-pressed="true"] {
  background: var(--surface); color: var(--text); box-shadow: 0 1px 2px rgba(0,0,0,.09);
}
/* O contador vive DENTRO do botão e herda a cor dele — um `.badge` aqui reintroduziria a caixa que
   o segmented control existe pra tirar. */
.p-seg > button > span,
.p-seg > a > span { font-variant-numeric: tabular-nums; opacity: .75; margin-left: 4px; }

/* 7b. Variação contra um período base (.p-var). O número ao lado do valor numa célula de tabela:
   ▲/▼ + a diferença, em verde/vermelho. A cor fica SÓ aqui — o valor da célula segue na tinta do
   texto, senão a tabela inteira vira semáforo. Sem base (vendedora nova, divisão por zero): `.is-na`
   com "—", nunca 0%. A seta vai no texto, então a direção não depende só da cor. */
.p-var {
  display: block; margin-top: 2px; font-size: 11px; font-weight: 600; line-height: 1.2;
  font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--text-4);
}
.p-var.is-up { color: var(--success); }
.p-var.is-down { color: var(--danger); }

/* 8. Matriz de números (.p-matriz). Contadores do MESMO tipo lidos de uma olhada.

   Em lista rótulo/valor (`.info-row`) são linhas altas que a vista varre de cima a baixo pra somar
   uma resposta — e foi por isso que o "Meu dia" pareceu solto na coluna. Em grade o bloco inteiro é
   uma leitura só. As divisórias são o `gap` sobre o fundo `--border`, não bordas por célula: borda
   em cada uma dobraria a linha do meio.

   🚫 A contagem de colunas NÃO é do chamador: quem chama não sabe quantos pixels a coluna
   dele tem. Em 200px (a coluna da fila do CRM) três colunas dão ~55px por célula e o rótulo vira
   "Aten…" / "Recu…" / "Pulad…" — três reticências que não dizem nada, e o `text-overflow` esconde
   o estrago sem erro nenhum (print do Nathan, 24/09). Por isso as colunas vêm de `auto-fit` com
   largura MÍNIMA em ch: onde o rótulo não cabe, a matriz empilha sozinha em vez de cortar. */
.p-matriz {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(11ch, 1fr)); gap: 1px;
  background: var(--border); border: 1px solid var(--border);
  border-radius: 8px; overflow: hidden;
}
.p-matriz > div { background: var(--surface-2); padding: 7px 9px; min-width: 0; }
.p-matriz b { display: block; font-size: 16px; font-weight: 700; line-height: 1.15; font-variant-numeric: tabular-nums; }
/* Sem `nowrap`/ellipsis: rótulo de contador é uma palavra ("Atendidos", "Recuperados") e, se a
   célula apertar, quebrar a linha diz a verdade — cortar em "Recu…" não. */
.p-matriz span { display: block; font-size: 10.5px; color: var(--text-3); margin-top: 1px; }

/* 9. Filtro discreto (.ms-btn.ms-funil). Modificador do multiselect para o filtro que nasce com
   TUDO marcado.

   O `.has-selection` (laranja) significa FILTRO ATIVO, e num filtro que já abre com todas as opções
   marcadas ele nasce aceso permanentemente, dizendo "está filtrado" quando nada foi escondido — o
   mesmo engano que `.ms-field` corrigiu no formulário em 26/08. Aqui o estado de repouso é neutro:
   ele acende só quando ALGUMA opção foi desmarcada, e quem decide isso é o chamador (a classe entra
   e sai por JS), porque só ele sabe quantas opções são "todas".

   🚫 O funil é `background` do botão, NUNCA um `<svg>` filho: `msSyncLabel()` reescreve o rótulo com
   `btn.textContent = …`, o que apagaria qualquer elemento dentro do botão no primeiro clique. */
.ms-btn.ms-funil {
  min-width: 0; padding: 5px 9px 5px 27px; font-size: 12px;
  background-repeat: no-repeat; background-position: 8px center; background-size: 13px 13px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23697586' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolygon points='22 3 2 3 10 12.5 10 19 14 21 14 12.5'/%3E%3C/svg%3E");
}
.ms-btn.ms-funil:not(.has-selection) { border-color: var(--border); background-color: var(--surface); color: var(--text-2); font-weight: 400; }
.ms-btn.ms-funil:not(.has-selection):hover { border-color: var(--brand); color: var(--text); }

/* Menu de ações da LINHA de uma tabela (.row-menu). Uma coluna "Ações" com 4-5 botões lado a lado
   estoura a largura da tabela e obriga a rolar na horizontal pra alcançar a última — e o que fica
   fora da dobra deixa de existir para quem não arrasta (Usuários, 22/09/2026). Um botão "⋯" só, e
   as ações dentro.

   🚫 O painel é `position: fixed`, posicionado por JS, nunca `absolute`: a `.table-wrap` tem
   `overflow-x: auto`, que **recorta** filho absoluto — o menu abriria cortado pela borda do card,
   ou simplesmente invisível na última linha. É o mesmo motivo do `createPortal` no FilterDrawer.

   Marcação: `.row-menu` > `.row-menu-btn` + `.row-menu-pop` > (`.row-menu-i` | `.row-menu-sep`).
   O item destrutivo leva `.danger` e vem depois de um `.row-menu-sep` — clique errado aqui remove
   acesso de gente. */
.row-menu { position: relative; display: inline-flex; }
.row-menu-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 26px; padding: 0; border-radius: var(--radius);
  border: 1px solid var(--border); background: var(--surface);
  color: var(--text-3); cursor: pointer; transition: all .1s;
}
.row-menu-btn:hover, .row-menu-btn.open { background: var(--surface-2); color: var(--text); border-color: var(--border-2); }
.row-menu-pop {
  position: fixed; z-index: 1000; min-width: 190px; padding: var(--sp-1);
  background: var(--surface); border: 1px solid var(--border-2);
  border-radius: var(--radius-md); box-shadow: var(--shadow-md);
  display: none;
}
.row-menu-pop.open { display: block; }
.row-menu-i {
  display: flex; align-items: center; gap: var(--sp-2); width: 100%;
  padding: 7px 10px; border: none; border-radius: var(--radius);
  background: none; font: inherit; font-size: 13px; color: var(--text-2);
  text-align: left; cursor: pointer; white-space: nowrap; text-decoration: none;
}
.row-menu-i:hover { background: var(--surface-2); color: var(--text); }
.row-menu-i svg { flex-shrink: 0; }
/* O estado ligado usa fundo, igual ao resto do portal — 🚫 nunca só a cor do texto, que num item
   de menu lê como "desabilitado" em vez de "ativo". */
.row-menu-i.on { background: var(--brand-dim); color: var(--brand-dark); font-weight: 600; }
.row-menu-i.danger { color: var(--danger); }
.row-menu-i.danger:hover { background: var(--danger-bg); color: var(--danger); }
.row-menu-sep { height: 1px; margin: var(--sp-1) 0; background: var(--border); }

/* 10. Coluna de contexto (.p-split). Tabelas à esquerda, contadores à direita — a supervisão lê
   linha por linha na tabela e usa a coluna estreita como placar de referência, sem rolar.

   É OUTRO papel que `.p-work` (bancada de 3 colunas, com `.p-work-scroll` de rolagem interna) e que
   `.col-layout-2` (duas metades iguais): aqui a coluna da direita é uma FAIXA FIXA, o conteúdo dela
   não rola separado e a largura não acompanha o conteúdo — 268px é o que cabe uma `.p-matriz` de
   duas colunas sem cortar rótulo.

   🚫 `align-items: start` não é enfeite: sem ele a coluna estreita ESTICA até a altura das tabelas e
   o último card fica com 300px de fundo vazio, sem erro nenhum. */
.p-split { display: grid; grid-template-columns: minmax(0, 1fr) 268px; gap: var(--sp-3); align-items: start; }
.p-split > * { min-width: 0; }
/* A coluna vira faixa horizontal antes de apertar a tabela: com 268px reservados, abaixo de ~1150px
   a tabela de 8 colunas da supervisão começa a rolar na horizontal — e tabela que rola esconde a
   última coluna de quem não arrasta (mesmo estrago do `.row-menu`, 22/09). */
@media (max-width: 1150px) {
  .p-split { grid-template-columns: minmax(0, 1fr); }
  .p-split > .p-split-lado { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: flex-start; }
  .p-split > .p-split-lado > * { flex: 1 1 240px; }
}

/* 11. Barra de proporção em CÉLULA (.p-prop). Mede uma razão (contato eficaz / tentativas) dentro da
   linha da tabela, que já é a comparação — um Chart.js por linha seriam 12 canvas pra dizer o mesmo.

   Marcação: `<div class="p-prop"><i style="width:NN%"></i></div>`, logo abaixo do número. O `.ok`
   pinta de `--success` a razão que é DESFECHO (recuperado), pra distinguir da de esforço (tentativa).
   🚫 Nunca sem o número escrito ao lado: barra sozinha não diz de quanto é a base. */
.p-prop { height: 6px; border-radius: 3px; background: var(--border); overflow: hidden; margin-top: 4px; }
.p-prop > i { display: block; height: 100%; background: var(--brand); }
.p-prop.ok > i { background: var(--success); }

/* 12. Ponto de presença (.p-vivo). Verde = a pessoa está com o "Disponível" ligado AGORA; cinza =
   não está. É estado de PESSOA, ao vivo — 🚫 não usar `.badge`, que é situação de REGISTRO e no meio
   de uma coluna de nomes viraria uma segunda palavra por linha.

   Sempre com `title` dizendo desde quando: a bolinha sozinha não tem legenda em lugar nenhum. */
.p-vivo { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--success); flex-shrink: 0; }
.p-vivo.off { background: var(--border-2); }

/* 13. Linha de lista compacta (.p-lista-i). Itens que a pessoa varre em busca de UM (o retorno que
   passou da hora) e abre: badge + nome + quando + ação, em linha, dentro de um card estreito.

   Não é `.info-row` (rótulo/valor de ficha, sem ação) nem `<table>` (que pede cabeçalho e alinha
   colunas entre linhas — aqui o nome é a única coluna que importa). `.p-lista-q` é o dado secundário
   e `.atraso` o pinta de `--danger`: é ele que faz o retorno atrasado saltar numa lista de 30. */
.p-lista-i {
  display: flex; align-items: center; gap: 9px; padding: 9px 0;
  border-bottom: 1px solid var(--border); font-size: 12.5px;
}
.p-lista-i:last-child { border-bottom: none; }
.p-lista-i > .p-lista-nome { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.p-lista-q { color: var(--text-4); font-size: 11.5px; flex-shrink: 0; }
.p-lista-q.atraso { color: var(--danger); font-weight: 600; }
/* `.is-sel` — o item ABERTO, quando a lista fica ao lado do que ela abriu (bancada de conversas).
   Mesma marcação visual de `.p-rank-row.is-sel`: fundo `--brand-dim` + barra à esquerda. 🚫 Não
   pintar no JS com `el.style.background`: estado visual vive no CSS, senão o dark mode e qualquer
   ajuste de cor passam ao largo dele. A maioria das listas não tem seleção — por isso é opt-in. */
.p-lista-i.is-sel {
  background: var(--brand-dim); box-shadow: inset 3px 0 0 var(--brand);
  padding-left: var(--sp-2); margin-left: calc(var(--sp-2) * -1);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
}

/* 13a-bis. Conversa de mensagens (.p-conversa / .p-msg). O fio de mensagens entre NÓS e o CLIENTE:
   bancada do CRM (`/crm/conversas`, o WhatsApp da vendedora) e, quando migrar, a caixa do
   atendimento — que trouxe estas medidas, provadas em produção como `.ch-msg` local.

   🚫 Nasce aqui e não na view porque JÁ EXISTE mais de um balão desenhado à mão no portal
   (`atendimento-caixa`, `cliente-area`, `admin-ia`): cada um com raio, largura e tom próprios. A
   conversa é o mesmo objeto nas três telas e precisa ler igual — e a bancada do CRM tem teto ZERO
   de CSS de view, então sem componente ela não existiria.

   O que o alinhamento diz: NOSSA mensagem à direita com a cor da marca, a do cliente à esquerda em
   cinza. 🚫 Não trocar por ícone ou rótulo "você/cliente" — quem varre a conversa lê o lado, não o
   texto, e o canto reto (`border-bottom-*-radius:4px`) é o que amarra o balão ao seu lado.

   Marcação:
   <div class="p-conversa">
     <div class="p-dia">HOJE</div>
     <div class="p-msg deles">texto<div class="p-msg-h">14:38</div></div>
     <div class="p-msg nossa">texto<div class="p-msg-h">14:40 · pelo celular</div></div>
   </div>

   `.p-msg-h` (a hora) é OBRIGATÓRIA e não é enfeite: sem ela "e aí, consegue hoje?" lê-se como
   recém-chegada mesmo com uma semana — e numa fila ordenada por espera a idade da mensagem é
   metade da informação. `tabular-nums` para a hora não dançar de linha em linha.
   `.p-msg-cit` é a citação de resposta; `.p-msg.apagada` é a revogada pelo remetente, que CONTINUA
   no nosso histórico (o registro não se apaga) mas o cliente não vê mais. */
.p-conversa { display: flex; flex-direction: column; gap: var(--sp-2); }
.p-msg {
  max-width: min(74%, 640px); padding: 9px 13px; border-radius: 14px;
  font-size: 13.5px; line-height: 1.5; white-space: pre-wrap; word-break: break-word;
  min-width: 0;
}
.p-msg.deles { align-self: flex-start; background: var(--surface-2); color: var(--text); border-bottom-left-radius: 4px; }
.p-msg.nossa { align-self: flex-end; background: var(--brand); color: var(--on-cor); border-bottom-right-radius: 4px; }
.p-msg-h { font-size: 10px; opacity: .6; text-align: right; margin-top: 3px; font-variant-numeric: tabular-nums; }
/* A citação herda o tom do balão em que está: no nosso (fundo da marca) um cinza fixo sumiria. */
.p-msg-cit {
  border-left: 3px solid currentColor; padding-left: var(--sp-2); margin-bottom: 3px;
  font-size: 12px; opacity: .72;
}
.p-msg.apagada { font-style: italic; opacity: .7; }
/* "Responder" de uma mensagem. Aparece ao passar o mouse no balão e some depois — visível sempre,
   ele vira ruído em cada linha de uma conversa de meses. 🚫 Mas NÃO é só `:hover`: num tablet não
   existe hover, então o `:focus-within` mantém o botão alcançável pelo teclado e pelo toque. */
.p-msg-acao {
  opacity: 0; transition: opacity .12s ease;
  font-size: 10.5px; margin-top: 2px; text-align: right;
}
.p-msg:hover .p-msg-acao, .p-msg:focus-within .p-msg-acao { opacity: .85; }
.p-msg-acao button {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: currentColor; font: inherit; text-decoration: underline;
}
/* Resultado da busca DENTRO da conversa: lista de atalhos sobre o fio, não um segundo fio. */
.p-busca-res { display: flex; flex-direction: column; gap: var(--sp-1); }
.p-busca-res > button {
  display: block; width: 100%; text-align: left; cursor: pointer;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-md);
  padding: var(--sp-2) var(--sp-3); font: inherit; color: var(--text);
  font-size: 13px; line-height: 1.5;
}
.p-busca-res > button:hover { border-color: var(--brand); }
.p-busca-res .q { display: block; font-size: 10.5px; color: var(--text-4); margin-top: 2px; }
/* A mensagem alvo, quando a busca leva até ela: o realce apaga sozinho, senão a conversa fica
   marcada para sempre e a próxima busca não se distingue da anterior. */
.p-msg.achada { outline: 2px solid var(--brand); outline-offset: 2px; }
/* Anexo dentro do balão. Imagem respeita a largura do balão; o resto é link. */
.p-msg-mid { margin-bottom: 3px; font-size: 13px; }
.p-msg-mid img { max-width: 100%; border-radius: 8px; display: block; }
/* Separador de dia, no meio da conversa. Mesma pílula do `.ch-dia` que ele substitui. */
.p-dia {
  align-self: center; font-size: 10.5px; font-weight: 600; letter-spacing: .3px;
  text-transform: uppercase; color: var(--text-4); background: var(--surface-2);
  border-radius: 99px; padding: 3px 11px; margin: 2px 0;
}

/* 13b. Item SELECIONÁVEL de duas linhas (.p-lista-sel). Lista em que a pessoa escolhe UM item e o
   conteúdo dele abre AO LADO (mestre/detalhe): o caderno de notas do CRM é o primeiro uso.

   Não é `.p-lista-i` (uma linha, sem seleção — a pessoa clica e NAVEGA pra outra tela) nem
   `.mp-trilho-i` (trilho de navegação de uma linha, com ícone, onde cada item é uma URL). O que
   pede regra própria é a segunda linha: título em cima, prévia embaixo, e o item ATIVO destacado
   enquanto o detalhe está aberto. `.p-lista-i` é `align-items:center` e empilhar dentro dele
   desalinha o resto da lista.

   Marcação: `<button class="p-lista-sel [active]"><span class="p-lista-sel-t">título</span>
   <span class="p-lista-sel-p"><strong>quando</strong> prévia</span></button>`.
   🚫 É `<button>`, não `<div onclick>`: a lista se percorre por Tab e abre no Enter — e o caderno é
   tela de digitar, onde a mão não está no mouse.

   Ativo = `--brand-dim` + `--brand-dark`, o MESMO par do `.mp-trilho-i.active` e do `.p-railnav`.
   🚫 Nunca `border-left` colorido: é o desvio que o trilho já corrigiu em 28/09. */
.p-lista-sel {
  display: flex; flex-direction: column; gap: 3px; width: 100%; min-width: 0;
  padding: var(--sp-2) var(--sp-3); border: 0; border-radius: 8px;
  background: transparent; color: var(--text-2); text-align: left; cursor: pointer; font: inherit;
}
a.p-lista-sel { text-decoration: none; }
.p-lista-sel:hover { background: var(--surface-2); color: var(--text); }
.p-lista-sel.active { background: var(--brand-dim); color: var(--brand-dark); }
/* As duas linhas cortam com ellipsis em vez de quebrar: numa coluna estreita um título longo viraria
   três linhas e o item ficaria mais alto que os vizinhos, desalinhando a lista inteira. */
.p-lista-sel-t,
.p-lista-sel-p { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.p-lista-sel-t { font-size: 13px; font-weight: 600; color: inherit; }
.p-lista-sel-p { font-size: 11.5px; color: var(--text-4); }
/* No item ativo a prévia herda o tom do destaque — `--text-4` sobre `--brand-dim` perde contraste. */
.p-lista-sel.active > .p-lista-sel-p { color: var(--brand-dark); opacity: .8; }
.p-lista-sel-p > strong { color: var(--text-3); font-weight: 600; }
.p-lista-sel.active > .p-lista-sel-p > strong { color: inherit; }

/* 13c. Feed de avisos (.p-avisos > .p-aviso). Alertas e recados que CHEGAM pra pessoa: ícone do tipo,
   título + chip do tipo, uma linha de contexto, quando, e as ações à direita (abrir onde resolve +
   "✓ Lido"). Nasce do artboard Alertas da diretoria (15/10/2026): ali é um feed de cartões, não tabela.

   Não é `<table>` (não há coluna a comparar entre linhas: cada aviso tem um formato) nem `.p-lista-i`
   (uma linha só, sem descrição). A cor do tipo vem de `--c` no próprio item (`style="--c:var(--success)"`):
   pinta o ícone, o ponto do chip (`.p-chip-dot` já lê `--c`) e, só enquanto NÃO lido (`.novo`), um
   fundo e borda tingidos. Lido volta a superfície neutra: o tingido é o "não lido", nunca decoração. */
.p-avisos { display: flex; flex-direction: column; gap: var(--sp-2); }
.p-aviso {
  --c: var(--text-4);
  display: grid; grid-template-columns: 36px minmax(0, 1fr) auto; gap: var(--sp-3); align-items: start;
  padding: var(--sp-3) var(--sp-4); border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--surface);
}
.p-aviso.novo { background: color-mix(in srgb, var(--c) 6%, var(--surface)); border-color: color-mix(in srgb, var(--c) 30%, var(--border)); }
.p-aviso-ico {
  width: 36px; height: 36px; border-radius: var(--radius-md); display: grid; place-items: center;
  background: color-mix(in srgb, var(--c) 14%, transparent); color: var(--c);
}
.p-aviso-ico > svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.p-aviso-corpo { min-width: 0; }
.p-aviso-tit { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; font-size: 13.5px; font-weight: 500; color: var(--text-2); }
.p-aviso.novo .p-aviso-tit { font-weight: 600; color: var(--text); }
.p-aviso-ponto { width: 7px; height: 7px; border-radius: 50%; background: var(--c); flex-shrink: 0; }
.p-aviso-desc { font-size: 12.5px; color: var(--text-3); margin-top: 3px; overflow-wrap: anywhere; }
.p-aviso-quando { font-size: 11.5px; color: var(--text-4); margin-top: 4px; font-variant-numeric: tabular-nums; }
.p-aviso-acoes { display: flex; align-items: center; justify-content: flex-end; gap: var(--sp-2); flex-wrap: wrap; }
@media (max-width: 640px) {
  .p-aviso { grid-template-columns: 36px minmax(0, 1fr); }
  .p-aviso-acoes { grid-column: 2; justify-content: flex-start; }
}


/* Avatar de LINHA — a foto do usuário/pessoa numa célula de tabela ou item de lista (.u-avatar).
   O `.avatar` do portal é escopado em `.sidebar-user` e traz 34px + tamanho de fonte de rodapé;
   reusar aqui puxaria aquele contexto. Este é o tamanho de célula (24px).

   Marcação: `<span class="u-avatar"><img src=…> | <svg…></span>`. Sem foto, entra o ícone genérico
   de pessoa (decisão de 22/09/2026) — nunca deixar o `<img>` quebrado, que renderiza o alt cru. */
.u-avatar {
  width: 24px; height: 24px; border-radius: 50%; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  overflow: hidden; background: var(--surface-2); border: 1px solid var(--border);
  color: var(--text-4);
}
.u-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ===== Misc ===== */
.divider { border: none; border-top: 1px solid var(--border); margin: 14px 0; }
/* Linha rótulo/valor de ficha. `.info-row` (label e valor na MESMA linha, separados) serve a
   resumo curto; `.info-row.stacked` empilha, para valor longo — e-mail, produto, mensagem de
   erro — que numa linha só espremeria o rótulo até quebrar. Mesma borda e mesmo respiro nos dois,
   que é o que faz duas fichas lado a lado alinharem. */
/* ⚠️ A variante `.stacked` vem DEPOIS da base: `.info-row .label` e `.info-row.stacked .label`
   têm a MESMA especificidade (0,2,0), então quem estiver por último vence. Declarar a variante
   antes deixa o rótulo empilhado com a cor e o corpo da base, em silêncio. */
.info-row { display: flex; justify-content: space-between; align-items: center; padding: 8px 0; border-bottom: 1px solid var(--border); font-size: 13px; }
.info-row:last-child { border-bottom: none; }
.info-row .label { color: var(--text-3); font-size: 12px; }
.info-row .value { font-weight: 600; color: var(--text); }
.info-row.stacked { display: block; }
.info-row.stacked .label {
  display: block; font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .5px; color: var(--text-4); margin-bottom: 2px;
}
.info-row.stacked .value { display: flex; align-items: center; gap: var(--sp-1); font-weight: 500; min-width: 0; }
/* Texto que não pode empurrar o container (e-mail, produto, código). Só funciona dentro de um pai
   com `min-width:0` — que é o que `.info-row.stacked .value` já garante. */
.ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.code { font-family: 'SF Mono', 'Fira Code', monospace; font-size: 11.5px; font-weight: 600; background: var(--surface-2); padding: 1px 5px; border-radius: 4px; color: var(--text-2); border: 1px solid var(--border); }
.text-muted { color: var(--text-3); font-size: 12px; }
.text-sm    { font-size: 12px; }
.text-xs    { font-size: 11px; }
.fw-500     { font-weight: 500; }
.fw-600     { font-weight: 600; }
.fw-700     { font-weight: 700; }
.mt-2 { margin-top: 8px; }
.mt-4 { margin-top: 16px; }
.mb-2 { margin-bottom: 8px; }
.mb-4 { margin-bottom: 16px; }
.mb-6 { margin-bottom: 24px; }

/* ===== Notifications ===== */
.notif-dropdown {
  position: absolute; right: 0; top: 44px;
  width: 340px; max-height: 400px; overflow-y: auto;
  background: var(--surface); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md); border: 1px solid var(--border-2); z-index: 999; display: none;
}
.notif-dropdown.open { display: block; }
.notif-header { padding: 12px 14px; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; }
.notif-item { display: block; padding: 10px 14px; border-bottom: 1px solid var(--border); transition: background .1s; }
.notif-item:hover { background: var(--surface-2); }
.notif-item.unread { background: var(--brand-dim2); }
.notif-item:last-child { border-bottom: none; }
@keyframes bellRing {
  0%,100% { transform: rotate(0); }
  15% { transform: rotate(15deg); }
  30% { transform: rotate(-12deg); }
  45% { transform: rotate(10deg); }
  60% { transform: rotate(-8deg); }
  75% { transform: rotate(5deg); }
  90% { transform: rotate(-3deg); }
}

/* ===== Sidebar collapse ===== */
html.sidebar-collapsed { --sidebar-w: 56px; }

/* Botão toggle na área da logo */
.sidebar-brand-logo-wrap {
  position: relative; flex-shrink: 0; cursor: pointer;
}
.sidebar-collapsed-indicator {
  display: none;
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--brand-dark);
  position: absolute; bottom: -3px; right: -5px;
  align-items: center; justify-content: center;
}
.sidebar-collapsed-indicator svg { width: 8px; height: 8px; stroke: #fff; fill: none; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
html.sidebar-collapsed .sidebar-collapsed-indicator { display: flex; }

.sidebar-toggle-btn {
  margin-left: auto; display: flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: var(--radius-md);
  color: var(--text-4); transition: background .1s, color .1s; flex-shrink: 0; cursor: pointer;
  border: none; background: none;
}
.sidebar-toggle-btn:hover { background: var(--surface-2); color: var(--text-3); }
.sidebar-toggle-btn svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
html.sidebar-collapsed .sidebar-toggle-btn { display: none; }
html.sidebar-collapsed .sidebar-brand .brand-name,
html.sidebar-collapsed .sidebar-brand .brand-tag { display: none; }
html.sidebar-collapsed .sidebar-brand { padding: 0; justify-content: center; cursor: pointer; }


/* Nav no modo colapsado: só ícone, centralizado, tooltip nativo via title */
html.sidebar-collapsed .sidebar-nav .nav-item {
  justify-content: center; padding: 7px;
}
html.sidebar-collapsed .nav-label { display: none; }
html.sidebar-collapsed .nav-badge { display: none; }
html.sidebar-collapsed .sidebar-section-label { display: none; }

/* Footer colapsado: só avatar */
html.sidebar-collapsed .sidebar-user .user-info,
html.sidebar-collapsed .sidebar-user .btn-logout,
html.sidebar-collapsed .theme-toggle { display: none; }
html.sidebar-collapsed .sidebar-user { justify-content: center; }
html.sidebar-collapsed .sidebar-footer { padding: 8px 0; }

/* ===== Seções retráteis ===== */
.sidebar-section-header {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%; padding: 6px 12px 6px 10px;
  background: none; border: none; cursor: pointer;
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 1px;
  color: var(--text-3); border-radius: var(--radius); transition: color .15s, background .15s;
  font-family: var(--font);
}
.sidebar-section-header:hover { color: var(--text); background: var(--surface-2); }
.sidebar-section-header svg {
  width: 11px; height: 11px; stroke: currentColor; fill: none; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform .2s; flex-shrink: 0;
}
.sidebar-section[data-collapsed] .sidebar-section-header svg { transform: rotate(-90deg); }

/* Esconde itens quando seção está recolhida (só no modo expandido) */
html:not(.sidebar-collapsed) .sidebar-section[data-collapsed] .nav-item { display: none; }
/* Esconde sub-seções inteiras quando a seção pai está recolhida */
html:not(.sidebar-collapsed) .sidebar-section[data-collapsed] .sidebar-section--sub { display: none; }

/* Sub-seções aninhadas dentro de uma sidebar-section */
.sidebar-section--sub { margin: 2px 0 0 0; }
.sidebar-section--sub .sidebar-section-header {
  font-size: 9.5px; font-weight: 700; padding: 4px 12px 4px 18px;
  text-transform: uppercase; letter-spacing: 0.8px;
}
.sidebar-section--sub .nav-item { padding-left: 22px; }
html:not(.sidebar-collapsed) .sidebar-section--sub[data-collapsed] .nav-item { display: none; }

/* No modo ícone-only, seções não se ocultam — todos os ícones aparecem sempre */
html.sidebar-collapsed .sidebar-section-header { display: none; }

/* ===== Sidebar — Orange Theme ===== */
/* Fundo laranja via variável — dark mode sobrescreve --sidebar-bg automaticamente */
.sidebar {
  background: var(--sidebar-bg);
  border-right: 1px solid var(--sidebar-border);
}

.sidebar-brand { border-bottom: 2px solid var(--brand); height: var(--topbar-h); position: relative; padding-right: 40px; }
.sidebar-brand .brand-logo { background: rgba(0,0,0,0.18); box-shadow: none; }
.sidebar-brand .brand-name { color: #fff; }
.sidebar-brand .brand-tag  { color: var(--sidebar-text-muted); }

/* Toggle absoluto — logo usa toda a largura */
.sidebar .sidebar-toggle-btn { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); margin-left: 0; color: rgba(255,255,255,0.65); }
.sidebar .sidebar-toggle-btn:hover { background: var(--sidebar-hover-bg); color: #fff; }

/* Marca Paytcall OS (partials/marca.ejs): chama branca num tile em degradê + "PAYTCALL" em Exo 2
   com o "OS" numa pílula. No menu laranja o tile e a pílula viram brancos, senão somem no fundo;
   no menu grafite (v2 dark) e no claro (sb-light) voltam ao degradê, em global-v2.css. */
:root { --marca-deg-a: #f7941d; --marca-deg-b: #ed1c24; --marca-degrade: linear-gradient(180deg, var(--marca-deg-a), var(--marca-deg-b)); }
.marca { display: block; width: 100%; height: 100%; }
.marca-solido { fill: var(--marca-solido, transparent); }
.marca-chama { fill: var(--marca-chama, #fff); }
.marca-nome { font-family: 'Exo 2', sans-serif; font-weight: 800; letter-spacing: .02em; text-transform: uppercase; line-height: 1; white-space: nowrap; display: inline-flex; align-items: center; gap: .28em; }
.marca-nome i { font-style: normal; font-size: .62em; letter-spacing: .04em; padding: .26em .42em; border-radius: .6em; line-height: 1; background: var(--marca-os-fundo, var(--marca-degrade)); color: var(--marca-os-cor, #fff); }
.sidebar-brand { --marca-solido: #fff; --marca-chama: var(--sidebar-bg); --marca-os-fundo: #fff; --marca-os-cor: var(--sidebar-bg); }
.sidebar-brand .brand-lockup { flex: 1; min-width: 0; display: flex; align-items: center; gap: 9px; }
.sidebar-brand .brand-mark { width: 26px; height: 26px; flex-shrink: 0; }
.sidebar-brand .brand-word { font-size: 16px; color: var(--sidebar-text); }
html.sidebar-collapsed .sidebar-brand .brand-lockup { display: none; }
.sidebar-brand .sidebar-brand-logo-wrap { display: none; }
html.sidebar-collapsed .sidebar-brand .sidebar-brand-logo-wrap { display: block; }

/* Seletor de sistema "Operação | CRM" (partials/sys-switch.ejs, 15/10/2026). O CRM é um site à parte:
   o menu do portal não lista as telas dele, entra-se por aqui — e o mesmo seletor fica no menu do CRM.
   "Na linha da marca" (opção 6, Nathan 15/10): só os ícones, ao lado do nome e antes do ‹ — não ocupa
   altura; o nome fica no tooltip e no texto para leitor de tela. Recolhido, sai junto com o nome. */
.sys-switch { display: flex; gap: 2px; padding: 3px; flex-shrink: 0; border-radius: 999px; background: var(--sys-trilho); }
.sys-switch a { display: grid; place-items: center; width: 28px; height: 24px; border-radius: 999px; color: var(--sys-crm); text-decoration: none; transition: background .15s, color .15s; }
.sys-switch a svg { width: 14px; height: 14px; }
.sys-switch a.is-on { background: var(--sys-ink); color: var(--sys-on-cor); }
.sys-switch a:not(.is-on):hover { background: var(--sys-crm-bg); }
.sys-switch a:focus-visible { outline: 2px solid var(--sys-crm); outline-offset: 1px; }
.sys-switch-tx { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* O menu do portal tem 220px (o desenho tinha 260): a marca encolhe um pouco para caber o seletor. */
html .sidebar-brand:has(.sys-switch) { gap: 6px; padding: 0 32px 0 12px; }
.sidebar-brand:has(.sys-switch) .brand-lockup { gap: 6px; }
.sidebar-brand:has(.sys-switch) .brand-mark { width: 22px; height: 22px; }
.sidebar-brand:has(.sys-switch) .brand-word { font-size: 12.5px; }
.sidebar-brand .sys-switch a { width: 24px; height: 22px; }
html.sidebar-collapsed .sidebar-brand .sys-switch { display: none; }
html.sidebar-collapsed .sidebar-brand:has(.sys-switch) { padding: 0; }
@media (max-width: 768px) {
  html.sidebar-collapsed .sidebar-brand .sys-switch { display: flex; }
  html.sidebar-collapsed .sidebar-brand:has(.sys-switch) { padding: 0 32px 0 12px; }
}

/* Scrollbar fina com o acento da marca (estilo importado do portal-gestão) */
::-webkit-scrollbar { width: 5px; height: 5px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(var(--brand-rgb), .35); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: rgba(var(--brand-rgb), .55); }

.sidebar-nav { scrollbar-color: rgba(255,255,255,0.25) transparent; }
.sidebar-nav::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.25); border-radius: 99px; }

.nav-item { color: var(--sidebar-text); }
.nav-item:hover { background: var(--sidebar-hover-bg); color: #fff; }
.nav-item.active, html.dark .nav-item.active {
  background: var(--sidebar-active-bg);
  color: var(--sidebar-active-text);
  font-weight: 600;
}
.nav-icon { color: rgba(255,255,255,0.65); }
.nav-item:hover .nav-icon, .nav-item.active .nav-icon { color: #fff; }

.sidebar-section-header {
  background: rgba(0,0,0,0.18);
  color: #fff;
  font-weight: 800;
  margin: 6px 6px 2px;
  width: calc(100% - 12px);
  border-radius: var(--radius);
}
.sidebar-section-header:hover { background: rgba(0,0,0,0.26); color: #fff; }
.sidebar-section--sub .sidebar-section-header {
  background: rgba(0,0,0,0.10);
  margin: 2px 6px 1px 12px;
  width: calc(100% - 18px);
  font-weight: 700;
}
.sidebar-section--sub .sidebar-section-header:hover { background: rgba(0,0,0,0.20); }

.sidebar-footer { border-top: 1px solid var(--sidebar-divider); }
.sidebar-user:hover { background: var(--sidebar-hover-bg); }
.sidebar-user .avatar { background: rgba(255,255,255,0.22); color: #fff; border-color: rgba(255,255,255,0.30); }
.sidebar-user .user-name { color: #fff; }
.sidebar-user .user-role { color: rgba(255,255,255,0.65); }
.sidebar-user .btn-logout { color: rgba(255,255,255,0.65); }
.sidebar-user .btn-logout:hover { background: var(--sidebar-hover-bg); color: #fff; }

.sidebar .theme-toggle {
  color: rgba(255,255,255,0.65);
  background: none;
  border-color: rgba(255,255,255,0.25);
}
.sidebar .theme-toggle:hover { background: var(--sidebar-hover-bg); color: #fff; border-color: rgba(255,255,255,0.40); }

.sidebar-collapsed-indicator { background: rgba(0,0,0,0.30); }

/* ===== Multi-select (padrão do design system) =====
   Uso: <%- include('partials/multiselect', { name, options:[[v,l],…], selected:[…], placeholder }) %> */
.ms { position: relative; display: inline-block; }
.ms-btn {
  font-size: 13px; padding: 6px 10px; min-width: 160px;
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--surface); color: var(--text);
  cursor: pointer; text-align: left;
  display: inline-flex; align-items: center; gap: 6px; justify-content: space-between;
}
.ms-btn:hover { border-color: var(--brand); }
.ms-btn.has-selection { border-color: var(--brand); background: var(--brand-dim); color: var(--brand-dark); font-weight: 600; }
.ms-btn::after { content: '▾'; font-size: 10px; color: var(--text-3); }
/* .has-selection (laranja) quer dizer FILTRO ATIVO. O auto-enhancer do design v2 usa a MESMA
   maquina do multiselect em <select> de formulario, que tem valor sempre — entao o campo nascia
   laranja permanente, como se fosse filtro ligado (caixa Status NF da gaveta do caso, 26/08/2026).
   Campo de formulario (.ms-field) fica neutro, igual ao .form-select que ele substitui. */
.ms-btn.ms-field.has-selection { border-color: var(--border); background: var(--surface); color: var(--text); font-weight: 400; }
.ms-btn.ms-field.has-selection:hover { border-color: var(--brand); }
.ms-pop {
  display: none; position: fixed; z-index: 9999;
  background: rgba(255,255,255,0.94);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 8px 28px rgba(0,0,0,.12);
  min-width: 220px; max-height: 320px; overflow-y: auto; padding: 4px;
}
.dark .ms-pop { background: rgba(44,44,46,0.94); }
.ms-pop.open { display: block; }
/* 🚫 O radio TEM que entrar aqui junto do checkbox: o modo `single: true` do partial escondia
   o radio por `style` inline montado com `<%=`, que ESCAPA o atributo (`style=&#34;…&#34;`) —
   ou seja, nunca escondeu nada, e a bolinha nativa aparecia ao lado do rótulo em ~20 telas.
   No CSS a regra também alcança a opção que o JS insere depois (ex.: `nichoAplicar`). */
.ms-pop input[type="checkbox"], .ms-pop input[type="radio"] { display: none; }
.ms-pop label {
  display: flex; align-items: center;
  padding: 7px 12px; font-size: 13px; cursor: pointer;
  color: var(--text); border-radius: 6px; transition: background .1s;
}
.ms-pop label:hover { background: var(--surface-2); }
.ms-pop label:has(input:checked) { background: var(--brand-dim); color: var(--brand-dark); font-weight: 500; }
/* "Limpar seleção" do multiselect de múltipla escolha: só aparece com algo marcado */
.ms-clear {
  display: flex; align-items: center; width: 100%; padding: 7px 12px; margin-bottom: 2px;
  border: 0; border-radius: 6px; background: none; cursor: pointer; font: inherit; font-size: 12.5px; font-weight: 600; color: var(--brand);
}
.ms-clear:hover { background: var(--surface-2); }
.ms-pop:not(:has(input:checked)) .ms-clear { display: none; }
.ms-pop label:has(input:checked)::after { content: ''; display: inline-block; width: 6px; height: 6px; background: var(--brand); border-radius: 50%; margin-left: auto; flex-shrink: 0; }
/* Ação simples dentro de um .ms-pop (ex: "Mais ações" da barra de seleção em lote) —
   mesmo visual do label de filtro, sem o círculo de seleção (não é filtro). */
.bulk-pop-action {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 7px 12px; font-size: 13px; cursor: pointer; white-space: nowrap;
  color: var(--text); background: none; border: none; border-radius: 6px;
  text-align: left; transition: background .1s;
}
.bulk-pop-action:hover { background: var(--surface-2); }

/* ── Kanban ─────────────────────────────────────────── */
.view-toggle { display:flex; gap:2px; border:1px solid var(--border); border-radius:6px; padding:2px; background:var(--surface); }
.view-toggle-btn { padding:4px 8px; border-radius:4px; border:none; background:transparent; cursor:pointer; color:var(--text-3); display:flex; align-items:center; transition:background .15s,color .15s; }
.view-toggle-btn.active { background:var(--brand); color:#fff; }
.view-toggle-btn:hover:not(.active) { background:var(--surface-2,#f0f0f0); color:var(--text); }

.kanban-wrap { overflow-x:auto; padding-bottom:20px; margin:0 -4px; }
.kanban-board { display:flex; gap:12px; align-items:flex-start; width:max-content; min-height:200px; padding:4px; }
.kanban-col { width:280px; flex-shrink:0; background:var(--surface-2,#f1f2f4); border-radius:12px; display:flex; flex-direction:column; }
.kanban-col-header { padding:12px 14px 10px; display:flex; align-items:center; justify-content:space-between; gap:8px; }
.kanban-col-header-title { font-size:13px; font-weight:700; color:var(--text); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.kanban-col-count { background:rgba(0,0,0,.12); color:var(--text); border-radius:20px; padding:2px 9px; font-size:11px; font-weight:700; flex-shrink:0; }
.kanban-cards { padding:0 8px 8px; display:flex; flex-direction:column; gap:6px; max-height:calc(100vh - 300px); overflow-y:auto; min-height:40px; }
.kanban-card { background:var(--bg); border-radius:8px; padding:10px 12px; cursor:grab; box-shadow:0 1px 3px rgba(0,0,0,.12); transition:box-shadow .15s,transform .1s; user-select:none; }
.kanban-card:active { cursor:grabbing; }
.kanban-card:hover { box-shadow:0 4px 12px rgba(0,0,0,.15); transform:translateY(-1px); }
.kanban-card-title { font-size:13px; font-weight:600; color:var(--text); margin-bottom:6px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.kanban-card-row { font-size:12px; color:var(--text-3); margin-bottom:2px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; display:flex; align-items:center; gap:4px; }
.kanban-empty { text-align:center; padding:16px 8px; color:var(--text-4); font-size:12px; font-style:italic; }
.kanban-card-dragging { opacity:.4; transform:rotate(1.5deg) scale(1.02); box-shadow:0 8px 24px rgba(0,0,0,.18); cursor:grabbing; }
.kanban-col-over { outline:2px dashed var(--brand); outline-offset:-2px; background:color-mix(in srgb, var(--brand) 8%, var(--surface-2)); }

/* ── Toggle switch ───────────────────────────────────────── */
.sw { position:relative; display:inline-flex; align-items:center; cursor:pointer; line-height:1; }
.sw input { opacity:0; width:0; height:0; position:absolute; }
.sw-track { width:34px; height:18px; background:var(--border-2); border-radius:9px; transition:background .2s; display:flex; align-items:center; padding:0 2px; flex-shrink:0; }
.sw input:checked + .sw-track { background:var(--success); }
.sw-thumb { width:14px; height:14px; background:#fff; border-radius:50%; transition:transform .2s; box-shadow:0 1px 3px rgba(0,0,0,.25); }
.sw input:checked + .sw-track .sw-thumb { transform:translateX(16px); }
.sw input:disabled + .sw-track { opacity:.5; cursor:not-allowed; }

/* ── Modal overlay (global) ──────────────────────────────── */
.modal-overlay { display:none; position:fixed; inset:0; background:rgba(0,0,0,.45); z-index:300; align-items:center; justify-content:center; }
.modal-overlay.open { display:flex; }
.modal-inner { width:100%; max-width:520px; max-height:90vh; overflow-y:auto; margin:16px; }

/* ===== Responsive ===== */
@media (max-width: 1200px) {
  .grid-2, .col-layout-2 { grid-template-columns: 1fr; }
  .grid-3 { grid-template-columns: 1fr 1fr; }
  .grid-4 { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 1024px) {
  /* ⚠️ auto-fit com minmax, NUNCA `repeat(4,1fr)` fixo. A track `1fr` é `minmax(auto,1fr)`, que
     se recusa a ficar menor que o conteúdo: com 4 colunas impostas numa tela estreita o valor
     ("0 de 103 (0%)") estourava a divisória e a barra inteira ficava torta. Com auto-fit o número
     de colunas cai sozinho conforme o espaço, e o `minmax` garante o piso de legibilidade. */
  /* `.p-summary-fixo` junto de propósito: sem repetir aqui, as colunas fixas dela continuariam
     valendo na tela estreita (mesma especificidade, e ela vem depois no arquivo) e espremeriam
     os cards — exatamente o que este breakpoint existe para evitar. */
  .p-summary, .p-summary.p-summary-fixo { grid-template-columns: repeat(auto-fit, minmax(128px,1fr)); }
}
@media (max-width: 768px) {
  /* Sidebar vira gaveta: some pra fora da tela em vez de sumir do DOM —
     o botão hamburguer na topbar (.mobile-menu-btn) e o backdrop
     (.sidebar-mobile-overlay) abrem/fecham (achado da Ingrid, 17/09/2026:
     sidebar com display:none não tinha NENHUM jeito de abrir os módulos
     pelo celular). */
  .sidebar { transform: translateX(-100%); box-shadow: 4px 0 24px rgba(0,0,0,.18); }
  .sidebar.mobile-open { transform: translateX(0); }
  .sidebar-mobile-overlay.open { display: block; }
  button.mobile-menu-btn { display: flex; }
  .main { margin-left: 0; }
  .stats-grid { grid-template-columns: repeat(2,1fr); }
  .grid-2, .grid-3, .grid-4, .col-layout-2 { grid-template-columns: 1fr; }
  .page { padding: 14px; }
  /* O lado direito tem `flex-shrink:0`: sem quebrar linha, um grupo largo (as abas de período do
     Meu painel) espremia o título numa coluna de uma palavra por linha. Com `wrap` e piso de 220px
     no título, o que não cabe ao lado desce pra baixo; botão pequeno continua do lado. */
  .p-page-header { flex-wrap: wrap; }
  .p-page-header-left { flex: 1 1 220px; min-width: 0; }
  /* Descido pra linha própria, o lado direito ainda não encolhia (`flex-shrink:0`) e vazava a tela
     quando período + Filtros somam mais que a largura (/atendimento/dashboard): agora quebra dentro. */
  .p-page-header-right, .p-page-header > .page-actions { flex-shrink: 1; min-width: 0; max-width: 100%; }
}

/* ===== Painel de resultado: hero, faixa de números, barras e demonstrativo (10/2026) =====
   Nasceram no /automacao/dashboard, mas são componentes do portal inteiro. Marcação de cada um em docs/design-system.md › "Painel de resultado". */

/* Grade: cartão hero à esquerda, cartões menores empilhados (.p-stack) à direita; uma coluna < 1100px */
.p-hero-grid { display: grid; grid-template-columns: minmax(0, 1.65fr) minmax(280px, 1fr); gap: 16px; align-items: stretch; margin-bottom: 16px; }
.p-hero-grid > .card, .p-stack > .card, .p-stack > .p-kpi { margin: 0; }
.p-stack { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.p-stack > :last-child { flex: 1; }
/* .is-igual: cartões curtos (só número) dividem a altura do hero por igual, conteúdo no meio — sem um último esticado vazio */
.p-stack.is-igual > * { flex: 1; }
.p-stack.is-igual > .p-kpi { justify-content: center; }
@media (max-width: 1100px) { .p-hero-grid { grid-template-columns: minmax(0, 1fr); } }

/* Cartão hero: rótulo (.p-kpi-label) → número grande → variação + contexto → gráfico → .p-kstrip */
.p-hero { display: flex; flex-direction: column; overflow: hidden; }
.p-hero-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; padding: 20px 22px 6px; }
.p-hero-top > :first-child { flex: 1 1 300px; min-width: 0; }
.p-hero-value { font-family: var(--font-head, inherit); font-size: 40px; font-weight: 700; line-height: 1.05; letter-spacing: -.03em; font-variant-numeric: tabular-nums; color: var(--text); margin: 8px 0 6px; white-space: nowrap; }
.p-hero-value.is-neg { color: var(--danger); }
.p-hero-sub { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 12.5px; color: var(--text-3); }
.p-hero-chart { position: relative; height: 190px; margin: 6px 12px 10px; }
/* Faixa fina embaixo do gráfico do hero, mesmo eixo X: uma medida de outra escala (ex.: %) sem segundo eixo Y */
.p-hero-chart.is-faixa { height: 56px; margin-top: 2px; }
/* Botão de COMPARAÇÃO do hero (.p-cmp): soma ao gráfico uma base de fora (ex.: clientes no /bi). Não é série
   da métrica, então fica numa linha própria acima do gráfico, longe dos .p-ptab, com a bolinha da cor da série.
   aria-pressed="true" = ligado; o <span> é a linha de contexto (ex.: "Paytcall = 7,7% deles"). */
.p-hero-cmp { padding: 4px 22px 0; }
.p-cmp { display: inline-flex; align-items: center; gap: 8px; padding: 6px 14px 6px 11px; border: 1px dashed var(--info-border); border-radius: 999px; background: var(--surface); color: var(--text-2); font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer; transition: background .15s, border-color .15s, color .15s; }
.p-cmp::before { content: ''; flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--info); }
.p-cmp > span { font-weight: 500; color: var(--text-3); }
.p-cmp:hover { border-color: var(--info); color: var(--text); }
.p-cmp:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.p-cmp[aria-pressed="true"] { border-style: solid; border-color: var(--info-border); background: var(--info-bg); color: var(--info); }
.p-cmp[aria-pressed="true"] > span { color: var(--info); font-weight: 700; }
/* Legenda de gráfico com 2+ séries que nenhum .p-ptab nomeia: marca + nome. Marca `i.is-line` (cheia),
   `i.is-dash` (tracejada), `i.is-dot` (ponto); cor --brand, ou `.is-mute`/`.is-warn`/`.is-danger`. */
.p-chart-leg { display: flex; flex-wrap: wrap; gap: 4px 14px; font-size: 11.5px; color: var(--text-3); }
.p-chart-leg > span { display: inline-flex; align-items: center; gap: 6px; }
.p-chart-leg i { flex: none; color: var(--brand); }
.p-chart-leg i.is-mute { color: var(--text-3); }
.p-chart-leg i.is-warn { color: var(--warning); }
.p-chart-leg i.is-danger { color: var(--danger); }
.p-chart-leg i.is-line { width: 14px; border-top: 2px solid currentColor; border-radius: 2px; }
.p-chart-leg i.is-dash { width: 14px; border-top: 2px dashed currentColor; }
.p-chart-leg i.is-dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; }

/* Cartão de equipe do /bi: faturamento grande + números de apoio, legenda, acumulado do mês e a top 1 no rodapé */
.p-eq { padding: 0; display: flex; flex-direction: column; }
.p-eq-meta { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 700; color: var(--text-2); white-space: nowrap; }
/* .p-anel-cel = o mesmo anel pequeno ao lado de um % dentro de célula de tabela (/bi/clientes) */
.p-anel-cel { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.p-eq-meta .p-kpi-ring, .p-anel-cel .p-kpi-ring { position: static; width: 18px; height: 18px; flex: none; }
.p-eq-meta .p-kpi-ring circle, .p-anel-cel .p-kpi-ring circle { stroke-width: 10; }
.p-eq-meta .p-kpi-ring text, .p-anel-cel .p-kpi-ring text { display: none; }
.p-eq-top { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 14px 24px; padding: 16px 20px 6px; }
.p-eq-top > :first-child { flex: none; display: grid; gap: 2px; }
.p-eq-top > .p-kpi-duo-row { flex: 1 1 320px; }
.p-eq-valor { font-family: var(--font-head); font-size: 28px; font-weight: 700; line-height: 1.1; letter-spacing: -.02em; color: var(--text); font-variant-numeric: tabular-nums; white-space: nowrap; }
.p-eq > .p-chart-leg { padding: 6px 20px 0; }
/* Rodapé da top 1: foto + nome à esquerda, os números dela (.p-kpi-duo-row) à direita */
.p-eq-top1 { margin-top: auto; border-top: 1px solid var(--border); display: flex; flex-wrap: wrap; align-items: center; gap: 12px 24px; padding: 12px 20px; }
.p-eq-top1 > .p-rank-pessoa { flex: 0 1 190px; }
.p-eq-top1 > .p-kpi-duo-row { flex: 1 1 320px; }
/* Número de apoio do cartão: uma linha só — o texto longo vai no title, nunca quebra */
.p-eq .p-kpi-duo-row .p-kpi-sub { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.p-hero > .p-kstrip { margin-top: auto; }
@media (max-width: 768px) { .p-hero-value { font-size: 32px; } }

/* Faixa de números: células coladas, separadas por 1px (o fundo aparece no gap — quebra de linha
   no celular continua com divisória). Solta, é `.card.p-kstrip`; dentro do hero, vai no rodapé.
   Cada célula reusa .p-kpi-label / .p-kpi-line / .p-kpi-value / .p-kpi-sub. */
.p-kstrip { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1px; background: var(--border); overflow: hidden; }
.card.p-kstrip { margin-bottom: 16px; }
.p-hero > .p-kstrip { border-top: 1px solid var(--border); }
.p-kcell { display: grid; gap: 4px; align-content: start; min-width: 0; padding: 14px 20px 16px; background: var(--surface); }
.p-kcell .p-kpi-value { font-size: 20px; }

/* Trilho de proporção: `<div class="p-track"><i style="width:N%"></i></div>`. Cor do <i> por classe. */
.p-track { height: 6px; border-radius: 99px; background: var(--surface-2); overflow: hidden; }
.p-track.is-thin { height: 4px; }
.p-track > i { display: block; height: 100%; border-radius: inherit; background: var(--brand); }
.p-track > i.is-success { background: var(--success); }
.p-track > i.is-danger { background: var(--danger); }
.p-track > i.is-warn { background: var(--warning); }
.p-track > i.is-info { background: var(--info); }
.p-track > i.is-mute { background: var(--text-4); opacity: .45; }
/* Mapa de calor na célula de matriz: `<td class="p-calor" style="--p-calor:0..1">` (valor ÷ maior da tabela)
   O teto é 56% da brand, não 18%: a 18% a matriz inteira lia como uma mancha só (Nathan, 29/10).
   O piso de 8% existe pra a célula com a MENOR venda ainda se distinguir da célula vazia — sem ele,
   "vendeu pouco" e "não vendeu" têm a mesma cor, e o buraco da matriz é metade da informação.
   ⚠️ O teto é 56% porque é CONTRASTE, não gosto: a brand é laranja CLARO (luminância alta), então
   o texto do tema escuro (#f2f2f2) cai abaixo de 4.5:1 a partir de ~90% da rampa antiga (teto 70%)
   — ali o número desaparecia no próprio destaque. 🚫 E não existe variante de "célula forte com
   texto branco": branco sobre a brand cheia dá 2.1:1, pior que o texto normal, que nunca quebra
   4.5:1 nesta rampa. Inverter a cor do texto aqui PIORA a leitura do pico. */
table tbody tr td.p-calor { background: color-mix(in srgb, var(--brand) calc(8% + var(--p-calor, 0) * 48%), transparent); }

/* Lista de barras: rótulo · valor (· % com .has-pct) em cima, trilho embaixo, legenda opcional.
   Serve a "custo em % do lucro", "período × anterior" e funil de canal (Enviados → Entregues → …). */
.p-bars { display: grid; gap: 12px; }
.p-bars + .p-kpi-label, .p-bars-gap { margin-top: 6px; }
.p-bar-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; gap: 5px 10px; font-size: 12.5px; color: var(--text-2); }
.p-bars.has-pct .p-bar-row { grid-template-columns: minmax(0, 1fr) auto 48px; }
.p-bar-row > b { font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
.p-bar-row > em { font-style: normal; font-size: 11.5px; color: var(--text-3); font-variant-numeric: tabular-nums; text-align: right; }
.p-bar-row > .p-track, .p-bar-row > small { grid-column: 1 / -1; }
.p-bar-row > small { font-size: 11px; color: var(--text-4); margin-top: -2px; }
.p-bar-row.is-head > b { font-family: var(--font-head, inherit); font-size: 15px; font-weight: 700; }
.p-bar-row.is-sub > span { padding-left: 12px; color: var(--text-3); }
.p-bar-row.is-danger > b { color: var(--danger); }
.p-bar-row.is-warn > b { color: var(--warning); }

/* Demonstrativo (DRE): seções, linhas rótulo · valor · variação, dedução recuada em vermelho,
   subtotal em faixa afundada; coluna lateral opcional (.p-stmt-side) que desce abaixo de 700px. */
.p-stmt-wrap { container-type: inline-size; }
/* Lateral larga de propósito (380px): "Custo em % do resultado líquido" tem rótulo + R$ + % na MESMA linha
   (.p-bars.has-pct), e a 280px o nome do custo quebrava. O demonstrativo cede o espaço sem perder
   nada — as linhas dele são rótulo curto + valor + variação. */
.p-stmt { display: grid; grid-template-columns: minmax(0, 1fr) 380px; }
.p-stmt-list { padding: 2px 0 12px; min-width: 0; }
.p-stmt-sec { padding: 14px 22px 4px; }
/* Legenda da seção: diz a BASE daquele bloco. Sem ela, "Vendas intermediadas" em cima de uma DRE
   lê como se fosse receita nossa — e é faturamento do cliente, que não entra na conta. */
.p-stmt-sec small { display: block; margin-top: 2px; font-size: 11px; color: var(--text-4); }
/* Divisor entre o bloco que NÃO é da conta (vendas) e a DRE: a borda é o que impede a leitura de
   que as linhas de cima somam com as de baixo. */
.p-stmt-split { margin: 10px 22px 2px; border-top: 1px solid var(--border); }
.p-stmt-row { display: grid; grid-template-columns: minmax(0, 1fr) auto 64px; gap: 12px; align-items: baseline; padding: 8px 22px; font-size: 13.5px; color: var(--text); }
.p-stmt-row > :nth-child(2) { text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.p-stmt-row > :nth-child(3) { text-align: right; }
.p-stmt-row small { display: block; font-size: 11px; font-weight: 400; color: var(--text-4); }
.p-stmt-row.is-ded { color: var(--text-2); padding-left: 38px; }
.p-stmt-row.is-ded > :nth-child(2) { color: var(--danger); font-weight: 500; }
.p-stmt-row.is-tot { margin: 4px 12px; padding: 10px; border-radius: var(--radius-md); background: var(--surface-2); font-weight: 600; }
.p-stmt-row.is-tot > :nth-child(2) { font-family: var(--font-head, inherit); font-weight: 700; }
.p-stmt-row.is-final > :nth-child(2) { font-size: 17px; }
/* Linha simulável do demonstrativo: o % é um input no meio da legenda, do tamanho da legenda —
   campo de formulário aqui roubaria a atenção da linha, que é um número de resultado, não um filtro. */
/* Campo de simulação da DRE (alíquota, IOF, spread). O "%" fica DENTRO da borda, não solto ao lado:
   solto, a caixa lia como um input cortado no meio e o rótulo encostava nela (Nathan, 03/11/2026).
   A borda é do `.p-stmt-chip`, o input por dentro é transparente e sem borda própria, e o foco
   acende o chip inteiro — por isso o `:focus-within` aqui e o `outline:none` no input. */
.p-stmt-sim { display: flex; align-items: center; gap: 6px; margin-top: 3px; }
.p-stmt-chip { display: inline-flex; align-items: center; gap: 1px; padding: 2px 7px; line-height: 1.4;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-md); }
.p-stmt-chip:focus-within { border-color: var(--brand); box-shadow: 0 0 0 2px color-mix(in srgb, var(--brand) 22%, transparent); }
.p-stmt-chip.is-bad { border-color: var(--danger); box-shadow: 0 0 0 2px color-mix(in srgb, var(--danger) 22%, transparent); }
.p-stmt-chip em { font-style: normal; color: var(--text-3); }
.p-stmt-sim input { width: 38px; padding: 0; font: inherit; font-size: 11px; font-weight: 600;
  text-align: right; font-variant-numeric: tabular-nums; color: var(--text); background: none; border: 0; }
.p-stmt-sim input:focus { outline: none; }
.p-stmt-sim input::-webkit-outer-spin-button, .p-stmt-sim input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.p-stmt-sim button { padding: 0; font: inherit; font-size: 11px; color: var(--brand); background: none; border: 0; cursor: pointer; text-decoration: underline; }
.p-stmt-side { display: flex; flex-direction: column; gap: 12px; padding: 18px 22px; border-left: 1px solid var(--border); }
@container (max-width: 700px) {
  .p-stmt { grid-template-columns: minmax(0, 1fr); }
  .p-stmt-side { border-left: 0; border-top: 1px solid var(--border); }
}

/* Leitura do período: o cartão que abre uma página de análise dizendo a CONCLUSÃO em texto, antes
   do primeiro gráfico — os gráficos abaixo passam a ser a prova dela, não quatro quadros soltos
   (Nathan, 29/10/2026). `.p-leitura-tese` é a frase única; `.p-leitura-corpo` sustenta com os
   números; o rodapé é um `.p-kstrip` com as medidas que a frase cita.
   🚫 O texto é MONTADO do dado, nunca escrito na view: frase fixa envelhece calada no dia em que
   a série vira. `<b>` dentro dele marca o número, e a cor vem de .is-up/.is-down. */
.p-leitura-tese { font-family: var(--font-head, inherit); font-size: 19px; font-weight: 700; line-height: 1.35; letter-spacing: -.01em; color: var(--text); margin: 0; }
.p-leitura-corpo { font-size: 13.5px; line-height: 1.6; color: var(--text-2); margin: 10px 0 0; max-width: 72ch; }
.p-leitura-corpo b { font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.p-leitura-corpo b.is-up { color: var(--success); }
.p-leitura-corpo b.is-down { color: var(--danger); }
@media (max-width: 768px) { .p-leitura-tese { font-size: 16.5px; } }

/* Corpo em duas colunas (número + gráfico | lista). Uma coluna abaixo de 768px. */
.p-duo { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(220px, 1fr); gap: 12px 28px; align-items: center; }
@media (max-width: 768px) { .p-duo { grid-template-columns: minmax(0, 1fr); } }

/* Iniciais de empresa/cliente no lugar da foto: `<span class="u-avatar is-ini">FN</span>`, ao lado
   do nome num `.p-cell-id`. Quadrado arredondado (pessoa = círculo com foto; empresa = monograma). */
.u-avatar.is-ini { width: 28px; height: 28px; border-radius: 8px; border-color: transparent; background: var(--brand-dim); color: var(--brand-dark); font-size: 10.5px; font-weight: 700; letter-spacing: .02em; }
.p-cell-id { display: flex; align-items: center; gap: 10px; min-width: 0; }
.p-cell-id > span:last-child { min-width: 0; }
/* Cabeçalho de página de UMA empresa: monograma grande antes do h1. */
.u-avatar.is-ini.is-lg { width: 44px; height: 44px; border-radius: 12px; font-size: 15px; flex-shrink: 0; }
.p-page-ident { display: flex; align-items: center; gap: 14px; min-width: 0; }
.p-page-ident > div { min-width: 0; }


/* ===== Grupo de cards da página (decisão 3B, 10/2026) =====
   A faixa .p-sec-title (a mesma da bancada do Hub) titulando um conjunto de cards que se leem
   juntos (ex.: os canais WhatsApp · E-mail · SMS). O grupo NÃO é caixa: sem borda, fundo nem
   padding — caixa em volta de card com cabeçalho próprio vira "seção dentro de seção" (Nathan,
   12/10/2026). A faixa fica sozinha, como separador, e os cards seguem soltos embaixo dela.
   Marcação em docs/design-system.md › "Grupo de cards". */
.p-sec.grupo { border: none; background: none; padding: 0; margin-bottom: 22px; }
.p-sec.grupo > .p-sec-title {
  display: flex; align-items: center; gap: 10px;
  margin: 4px 0 12px; padding: 0; font-size: 11px; color: var(--text-3);
  background: none; border: none; border-radius: 0;
}
.p-sec.grupo > .p-sec-title::after { content: ''; flex: 1; height: 1px; background: var(--border); }
.p-sec.grupo > :last-child, .p-sec.grupo .card:last-child { margin-bottom: 0; }

/* ===== Gráfico | Tabela no mesmo card (decisão 4B, 10/2026) =====
   .p-ptab-group[data-p-vista] no .card-actions troca qual [data-p-pane] aparece no card.
   O clique é tratado em /js/p-charts.js. */
[data-p-pane][hidden] { display: none !important; }

/* ===== Campo numérico com unidade (%, dias, R$) =====
   `<span class="p-campo-un"><input class="form-input" type="number"><span class="p-un">%</span></span>`
   O campo é ESTREITO de propósito: percentual ocupando a largura do cartão parece caixa de texto
   livre. A unidade fica FORA do input — dentro do `value` ela seria enviada no POST. */
.p-campo-un { display: inline-flex; align-items: center; gap: 6px; }
/* `line-height: 1.4` + 6px travam a altura na MESMA do `.btn` que fica ao lado (32px). O
   `.form-input` sozinho não declara `line-height` e herda o `normal` da fonte, dando 35px — ao
   lado de um botão de 32 a caixa fica 3px mais alta, e é isso que faz o bloco não parecer do
   portal (Nathan, 28/10: "essa caixa ainda esta fora do design system"). 🚫 Fica no
   `.p-campo-un`, nunca no `.form-input`: lá mexeria em todo campo do portal, e os 35px são a
   altura que as outras telas já assumem. */
.p-campo-un > .form-input { width: 92px; text-align: right; padding: 6px 10px; line-height: 1.4; }
.p-campo-un > .p-un { font-size: 12px; font-weight: 600; color: var(--text-3); }
