/* =============================================================================
   USECLUBE · Leads — estilos globais (mobile-first)

   Dois temas, em cinza neutro com acento azul: o escuro no :root e o claro em
   :root[data-tema="claro"]. Componentes não usam cor literal, só as variáveis —
   trocar a paleta é mexer só nos dois blocos do topo.

   Não há @media (prefers-color-scheme) aqui de propósito: js/tema.js resolve a
   preferência do sistema antes da primeira pintura e escreve data-tema já
   resolvido. Assim a paleta clara existe uma vez só, em vez de aparecer
   duplicada — uma dentro do @media e outra para a escolha manual, que é onde
   esse tipo de CSS costuma sair do lugar.

   As exceções deliberadas à regra "só variáveis", todas fora daqui:
     · .wa-*            simulação da tela do WhatsApp — tem a paleta do WhatsApp
     · .btn-whatsapp    verde da marca
     · .imprimindo-*    impressão é sempre preto no branco
     · scrims de modal  véu escuro sobre o conteúdo vale nos dois temas
     · lupa da busca    SVG em data URI, onde custom property não entra
   ============================================================================= */
:root {
  /* superfícies — cinza neutro, sem tingimento azul */
  --bg: #1e1e1e;
  --surface: #262626;
  --surface-2: #303030;
  --sidebar-bg: #171717;
  --border: #383838;
  --border-strong: #4a4a4a;

  /* texto — o --faint segue a mesma regra do tema claro: 4.5:1 sobre o cartão,
     porque é a cor dos rótulos de 11px em caixa alta e do "há 2 h" dos
     cartões. #767676 dava 3.6 sobre --surface. */
  --text: #e9e9e9;
  --muted: #a6a6a6;
  --faint: #8f8f8f;

  /* ação — o azul é o acento do tema */
  --primary: #4493f8;
  --primary-hover: #58a6ff;
  --primary-ink: #10151a;
  --primary-soft: #26333f;

  /* semânticas */
  --danger: #f85149;
  --danger-soft: #35211f;
  --success: #3fb950;
  --success-soft: #1c2f21;
  --warning: #d29922;
  --warning-soft: #332c18;
  --info: #4493f8;
  --info-soft: #1f2c3a;
  --purple: #a371f7;
  --purple-soft: #2b2438;
  --gray-soft: #2e2e2e;

  /* Ritmo. Um degrau de 4px e nomes para os saltos que se repetem: o que
     separa um cartão do vizinho numa lista (--gap-lista) e o que separa um
     bloco do seguinte na página (--gap-bloco). Antes cada lista escolhia o seu
     (.5, .55, .6, .7, .85, 1rem) e cada tela tinha uma respiração diferente. */
  --sp-1: .25rem; --sp-2: .5rem; --sp-3: .75rem; --sp-4: 1rem;
  --sp-5: 1.25rem; --sp-6: 1.5rem; --sp-8: 2rem;
  --gap-lista: .75rem;
  --gap-bloco: 1.25rem;

  /* forma */
  --radius: 14px;
  --radius-sm: 10px;
  --shadow: none;
  --shadow-md: 0 4px 16px rgba(0, 0, 0, .35);
  --shadow-lg: 0 20px 48px rgba(0, 0, 0, .55);
  --sidebar-w: 16.5rem;
  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --ring: rgba(68, 147, 248, .35);
  --chart-1: #4493f8;
  /* trilho do spinner: cinza puro, porque ele roda tanto sobre botão azul
     quanto sobre fundo claro — branco a 40% some no tema claro */
  --spinner-track: rgba(255, 255, 255, .4);

  /* wordmark branca, para fundo escuro */
  --logo-useclube: url('../assets/logo-useclube.png');

  color-scheme: dark;
}

/* ---------------------------------------------------------------------------
   Tema claro. Mesma estrutura de variáveis, nenhuma regra de componente muda.

   O escuro veio do Primer escuro do GitHub (#4493f8, #f85149, #3fb950, #d29922,
   #a371f7 são de lá), então o claro usa o Primer claro: são desenhados como par,
   já vêm com contraste conferido e evitam inventar cor a olho.
   --------------------------------------------------------------------------- */
:root[data-tema="claro"] {
  /* superfícies — branco no cartão, cinza no fundo, para o cartão descolar */
  --bg: #f6f7f8;
  --surface: #ffffff;
  --surface-2: #f0f1f3;
  --sidebar-bg: #ffffff;
  --border: #e2e4e8;
  --border-strong: #c5c9d0;

  /* texto — o --faint precisa de 4.5:1 sobre --bg, senão a linha em caixa alta
     do cabeçalho (.eyebrow, .7rem) fica ilegível; #818b96 dava só 3.2 */
  --text: #1c2024;
  --muted: #59636e;
  --faint: #656d76;

  /* ação */
  --primary: #0969da;
  --primary-hover: #0860ca;
  --primary-ink: #ffffff;
  --primary-soft: #ddf4ff;

  /* semânticas — os -soft aqui são tintas claras, não sombras */
  --danger: #cf222e;
  --danger-soft: #ffebe9;
  --success: #1a7f37;
  --success-soft: #dafbe1;
  --warning: #9a6700;
  --warning-soft: #fff8c5;
  --info: #0969da;
  --info-soft: #ddf4ff;
  --purple: #8250df;
  --purple-soft: #fbefff;
  --gray-soft: #eff1f3;

  /* No escuro a borda já separa o cartão do fundo e --shadow é none. No claro
     a borda é quase invisível, então a sombra é que dá o relevo. */
  --shadow: 0 1px 2px rgba(28, 32, 36, .06);
  --shadow-md: 0 4px 16px rgba(28, 32, 36, .10);
  --shadow-lg: 0 20px 48px rgba(28, 32, 36, .16);
  --ring: rgba(9, 105, 218, .3);
  --chart-1: #0969da;
  --spinner-track: rgba(28, 32, 36, .22);

  /* wordmark escura — a branca sumia no fundo claro. O arquivo já existia no
     repositório desde o começo, sem nenhum uso. */
  --logo-useclube: url('../assets/logo-useclube-dark.png');

  color-scheme: light;
}

/* No celular as listas apertam um degrau: a tela é uma coluna só, e o que
   separa um cartão do outro já é a borda dele. */
@media (max-width: 899px) {
  :root { --gap-lista: .625rem; --gap-bloco: 1rem; }
}

/* Trocar de tema não é uma animação. Botões, cartões e chips têm transição de
   cor para o hover; sem isto, a troca dispara todas ao mesmo tempo e a tela
   inteira faz um borrão de 150ms. js/tema.js não precisa saber disso — quem
   marca a classe é a própria troca, e ela sai no quadro seguinte. */
.trocando-tema, .trocando-tema *, .trocando-tema *::before, .trocando-tema *::after {
  transition: none !important;
}


/* ---------------------------------------------------------------------------
   Rótulos em caixa alta: dois degraus, uma família só.

   · de SEÇÃO — abre um bloco (Status, Anotações, Equipe, Últimos meses).
   · de CAMPO — nomeia um valor ou um grupo pequeno (cabeçalho de tabela,
     rótulo de KPI, grupo da barra lateral, sobrelinha do título).

   Já foram cinco estilos convivendo — metade em fonte monoespaçada, com até
   .15em entre as letras —, e toda tela misturava dois ou três. Era boa parte
   do "embolado": o olho lia cada rótulo como uma coisa diferente. Aqui eles
   vivem num lugar só; as regras dos componentes cuidam só de margem e posição.
   A monoespaçada ficou para os números, que é onde alinhar dígito ajuda.
   --------------------------------------------------------------------------- */
.section-title, .section-label, .secao-mat {
  font-family: var(--font); font-size: .75rem; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--muted);
}
.eyebrow, .nav-label, .kpi .label, th, .dep-rotulo {
  font-family: var(--font); font-size: .6875rem; font-weight: 650;
  letter-spacing: .06em; text-transform: uppercase; color: var(--faint);
}

.eyebrow { display: flex; align-items: center; gap: .5rem; }
.eyebrow .dot { width: 0.375rem; height: 0.375rem; border-radius: 50%; background: var(--success); flex: none; }

/* ---------- Ícones (js/icons.js) ----------
   icon() escreve o tamanho em rem na variável --i (16px = 1rem); aqui ela vira
   largura e altura, e o ícone acompanha a escala da interface. Os atributos em
   px do SVG ficam só de reserva: a regra de classe vence o atributo. */
.ico { flex: none; vertical-align: -.15em; width: var(--i, 1rem); height: var(--i, 1rem); }
.icon-tile {
  width: 2rem; height: 2rem; border-radius: 9px; display: inline-grid; place-items: center;
  background: var(--gray-soft); color: var(--muted); flex: none;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
/* O Safari do iPhone aumenta a letra sozinho quando o aparelho vira de lado. Com
   a escala escolhida pela pessoa, isso somaria por cima dela sem ninguém pedir. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

/* ---------------------------------------------------------------------------
   Escala da interface (Tamanho: 100% · 125% · 150%, no menu do usuário).
   js/tema.js escreve data-escala no <html> antes da primeira pintura; aqui a
   fonte da raiz cresce, e com ela tudo que está em rem. Por isso o resto da
   folha mede em rem o que deve crescer (texto, espaçamento, botões, ícones,
   larguras de modal e da barra lateral) e em px só o que não deve (bordas de
   1px, sombras, breakpoints). Porcentagem, e não px, para somar com o tamanho
   de fonte que a pessoa já tenha escolhido no navegador ou no celular.
   --------------------------------------------------------------------------- */
html[data-escala="125"] { font-size: 125%; --escala: 1.25; }
html[data-escala="150"] { font-size: 150%; --escala: 1.5; }

body {
  font-family: var(--font);
  font-size: 1rem;
  line-height: 1.45;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}
a { color: var(--primary); text-decoration: none; }
h1, h2, h3, h4 { margin: 0 0 .5rem; line-height: 1.25; }
h1 { font-size: 1.65rem; letter-spacing: -.02em; }
h2 { font-size: 1.25rem; }
h3 { font-size: 1.02rem; letter-spacing: -.01em; }
p { margin: 0 0 .75rem; }
.muted { color: var(--muted); }
.small { font-size: .85rem; }
.mono { font-variant-numeric: tabular-nums; }
.hidden, [hidden] { display: none !important; }
/* Esconde da vista sem esconder do teclado nem do leitor de tela. Existe para
   campo acionado por um <label> desenhado — o input de arquivo da ficha pública:
   com [hidden] ele sai da árvore e a seção inteira fica sem nada focável. */
.campo-oculto {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); border: 0; white-space: nowrap;
}
.text-right { text-align: right; }
.nowrap { white-space: nowrap; }

/* ---------- Botões ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  padding: .5rem .85rem; border-radius: var(--radius-sm); border: 1px solid transparent;
  font: inherit; font-size: .875rem; font-weight: 500; cursor: pointer; white-space: nowrap;
  transition: background .15s, border-color .15s, color .15s, transform .05s;
  background: var(--surface-2); color: var(--text); border-color: var(--border);
}
.btn:hover { background: var(--border); border-color: var(--border-strong); }
.btn .ico { color: var(--muted); }
.btn-primary .ico, .btn-danger .ico, .btn-success .ico, .btn-whatsapp .ico { color: currentColor; }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .6; cursor: not-allowed; }
.btn-primary { background: var(--primary); color: var(--primary-ink); border-color: var(--primary); font-weight: 600; }
.btn-primary:hover { border-color: var(--primary-hover); }
.btn-primary:hover { background: var(--primary-hover); }
.btn-danger { background: var(--danger); color: var(--bg); border-color: var(--danger); }
.btn-danger:hover { filter: brightness(.92); }
.btn-ghost { background: transparent; border-color: transparent; color: var(--muted); }
.btn-ghost:hover { background: var(--gray-soft); color: var(--text); }
.btn-success { background: var(--success); color: var(--bg); border-color: var(--success); }
.btn-whatsapp { background: #1f7a4d; color: #fff; border-color: #1f7a4d; }
.btn-whatsapp:hover { background: #24905c; border-color: #24905c; }
.btn-sm { padding: .34rem .62rem; font-size: .8rem; }
.btn-block { width: 100%; }
.btn-icon {
  display: inline-grid; place-items: center; background: transparent; border: none; cursor: pointer;
  line-height: 1; padding: .35rem; border-radius: var(--radius-sm); color: var(--muted);
}
.btn-icon:hover { background: var(--gray-soft); color: var(--text); }

.spinner {
  width: 0.875rem; height: 0.875rem; border-radius: 50%; display: inline-block;
  border: 2px solid var(--spinner-track); border-top-color: currentColor;
  animation: spin .7s linear infinite; vertical-align: -2px;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- Formulários ---------- */
.field { display: flex; flex-direction: column; gap: .3rem; margin-bottom: .9rem; }
.field label { font-size: .85rem; font-weight: 600; color: var(--muted); }
.field .hint { font-size: .8rem; color: var(--muted); }
input[type="text"], input[type="email"], input[type="password"], input[type="tel"], input[type="number"],
input[type="date"], input[type="month"], input[type="search"], select, textarea {
  width: 100%; padding: .62rem .8rem; border: 1px solid var(--border); border-radius: var(--radius-sm);
  font: inherit; color: var(--text); background: var(--surface-2);
  transition: border-color .15s, box-shadow .15s;
}
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--border-strong); box-shadow: 0 0 0 3px var(--ring);
}
textarea { resize: vertical; min-height: 5rem; }
.form-row { display: grid; grid-template-columns: 1fr; gap: 0 .9rem; }
@media (min-width: 640px) { .form-row { grid-template-columns: 1fr 1fr; } }
.form-error { color: var(--danger); font-size: .9rem; margin: .5rem 0; min-height: 1.2em; }
.switch { display: inline-flex; align-items: center; gap: .5rem; cursor: pointer; }
.switch input { width: auto; }
/* Rádio e caixa de seleção nativos têm 13px fixos e não sabem de font-size:
   com Tamanho 150% a bolinha do plano ficava minúscula ao lado de um texto de
   24px. --escala multiplica o tamanho nativo — só em 125% e 150%, para o 100%
   continuar exatamente com o tamanho que cada navegador desenha.
   O rádio invisível dos cartões de plano do formulário público fica de fora: ele
   já mede 1.125rem, do tamanho da bolinha desenhada por cima dele. */
html:is([data-escala="125"], [data-escala="150"]) :is(input[type="radio"], input[type="checkbox"]):not(.plano-op input) {
  width: calc(13px * var(--escala)); height: calc(13px * var(--escala));
  /* dentro de um .switch (flex) o input encolheria de volta a 13px de largura
     ao lado de um rótulo longo, e a caixa sairia achatada */
  flex: none;
}

/* iOS Safari dá zoom automático em campos com fonte < 16px. max(): nunca abaixo
   de 16px, mas crescendo com a escala da interface (20px em 125%, 24px em 150%)
   — em 16px fixos o campo ficava pequeno ao lado de um rótulo 50% maior. */
@media (max-width: 899px) {
  input[type="text"], input[type="email"], input[type="password"], input[type="tel"], input[type="number"],
  input[type="date"], input[type="month"], input[type="search"], select, textarea { font-size: max(16px, 1rem); }
}

/* ---------- Cards / painéis ---------- */
.card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 1.15rem 1.25rem;
}
.card + .card { margin-top: 1rem; }
/* no celular o respiro interno é o mesmo dos cartões de lista (1rem dos lados):
   com 1.25rem, os botões lado a lado dentro do cartão (o link de Cadastros)
   ficavam sem folga nenhuma em 360px */
@media (max-width: 639px) { .card { padding: 1rem; } }
.card-header { display: flex; align-items: center; justify-content: space-between; gap: .75rem; margin-bottom: .75rem; flex-wrap: wrap; }
.card-header h2, .card-header h3 { margin: 0; }

/* ---------- Badges ---------- */
.badge {
  display: inline-flex; align-items: center; gap: .3rem; padding: .2rem .55rem; border-radius: 999px;
  font-size: .74rem; font-weight: 600; letter-spacing: .01em; white-space: nowrap;
  background: var(--gray-soft); color: var(--muted);
}
.badge-novo         { background: var(--info-soft);    color: var(--info); }
/* "Em contato" não é mais status de lead (fundido em Negociando); a classe fica
   porque Cadastros pinta "Em análise" com ela (ENROLLMENT_STATUS em js/ui.js). */
.badge-em-contato   { background: var(--warning-soft); color: var(--warning); }
.badge-sem-resposta { background: var(--gray-soft);    color: var(--muted); }
.badge-negociando   { background: var(--purple-soft);  color: var(--purple); }
.badge-ganho        { background: var(--success-soft); color: var(--success); }
.badge-perdido      { background: var(--danger-soft);  color: var(--danger); }
.badge-inadimplente { background: var(--warning-soft); color: var(--warning); }
.role-gestor       { background: var(--purple-soft);  color: var(--purple); }
.role-operador        { background: var(--info-soft);    color: var(--info); }
.role-representante { background: var(--success-soft); color: var(--success); }
.badge-inactive     { background: var(--danger-soft);  color: var(--danger); }
.rep-interno        { background: var(--info-soft);    color: var(--info); }
.rep-externo        { background: var(--warning-soft); color: var(--warning); }

/* quadradinho de ícone do card, na cor do status */
.tile-novo         { background: var(--info-soft);    color: var(--info); }
.tile-sem-resposta { background: var(--gray-soft);    color: var(--muted); }
.tile-negociando   { background: var(--purple-soft);  color: var(--purple); }
.tile-ganho        { background: var(--success-soft); color: var(--success); }
.tile-perdido      { background: var(--danger-soft);  color: var(--danger); }
.tile-inadimplente { background: var(--warning-soft); color: var(--warning); }
.bot-pendente       { background: var(--gray-soft);    color: var(--muted); }
.bot-enviado        { background: var(--success-soft); color: var(--success); }
.bot-erro           { background: var(--danger-soft);  color: var(--danger); }
.bot-ignorado       { background: var(--gray-soft);    color: var(--muted); }

/* ---------- Layout do app ---------- */
.layout { display: grid; grid-template-columns: 1fr; min-height: 100vh; }
.sidebar {
  background: var(--surface); border-bottom: 1px solid var(--border);
  display: flex; flex-direction: column; padding: .55rem .8rem;
  position: sticky; top: 0; z-index: 30;
}
.sidebar-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; min-height: 2.125rem; }
.brand { display: inline-flex; align-items: center; }

/* Wordmark. É background e não <img> de propósito: a marca tem duas versões
   (branca e escura) e assim o navegador baixa só a do tema em vigor — são
   136 KB cada. Como background, a troca também acontece na pintura, sem passar
   por JS, então não pisca ao carregar nem ao trocar de tema.
   Quem dá a altura é quem usa; a largura sai do aspect-ratio do arquivo. */
.logo-useclube {
  display: block; aspect-ratio: 1066 / 264;
  background: var(--logo-useclube) left center / contain no-repeat;
}
.brand-logo { height: 1.375rem; }
/* navegação agrupada — só no desktop; no celular quem manda é a .tabbar */
.nav { display: none; flex-direction: column; gap: 1.35rem; padding: .7rem 0 .3rem; }
.nav-group { display: flex; flex-direction: column; gap: .1rem; }
.nav-label { padding: 0 .7rem .45rem; }
.nav a {
  display: flex; align-items: center; gap: .6rem; padding: .5rem .6rem; border-radius: var(--radius-sm);
  color: var(--muted); font-weight: 500; font-size: .93rem; white-space: nowrap;
}
.nav a .ico { color: var(--faint); transition: color .15s; }
.nav a:hover { background: var(--gray-soft); color: var(--text); }
.nav a:hover .ico { color: var(--muted); }
.nav a.active { background: var(--primary-soft); color: var(--text); font-weight: 600; }
.nav a.active .ico { color: var(--primary); }

/* usuário */
.user-box { display: flex; align-items: center; padding-top: .6rem; border-top: 1px solid var(--border); }
.user-trigger {
  display: none; align-items: center; gap: .55rem; width: 100%; padding: .45rem .5rem;
  background: none; border: 1px solid transparent; border-radius: var(--radius-sm);
  font: inherit; color: inherit; cursor: pointer; text-align: left;
}
.user-trigger:hover { background: var(--gray-soft); }
.avatar {
  width: 2.125rem; height: 2.125rem; border-radius: 50%; background: var(--primary); color: var(--primary-ink);
  display: grid; place-items: center; font-weight: 700; font-size: .78rem; flex-shrink: 0;
}
.user-meta { display: grid; line-height: 1.2; min-width: 0; flex: 1; }
.user-meta .name { font-weight: 600; font-size: .87rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-caret { color: var(--faint); display: inline-grid; }
.user-menu { position: relative; width: 100%; }
.user-menu .menu {
  position: absolute; left: 0; right: 0; top: calc(100% + 0.375rem); background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow-lg);
  min-width: 11.875rem; padding: .3rem; z-index: 40; display: none;
}
.user-menu.open .menu { display: block; }
.user-menu .menu button {
  width: 100%; display: flex; align-items: center; gap: .55rem; text-align: left; background: none;
  border: none; padding: .5rem .6rem; border-radius: 6px; font: inherit; font-size: .88rem;
  cursor: pointer; color: var(--text);
}
.user-menu .menu button .ico { color: var(--faint); }
.user-menu .menu button:hover { background: var(--gray-soft); }

/* ---------- Seletor de tema ----------
   Três opções lado a lado em vez de um botão que alterna. Alternar esconderia
   "seguir o sistema", que é o padrão, e um botão que cicla três estados não diz
   em qual deles está. Aqui a opção em vigor fica marcada. */
.tema-linha {
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  padding: .45rem .6rem; margin-top: .15rem; border-top: 1px solid var(--border);
}
.tema-rotulo {
  display: inline-flex; align-items: center; gap: .55rem;
  font-size: .88rem; color: var(--text);
}
.tema-rotulo .ico { color: var(--faint); }
.tema-seg {
  display: inline-flex; gap: 2px; padding: 2px; flex: none;
  background: var(--surface-2); border-radius: 8px;
}
.tema-seg button {
  width: 1.875rem; height: 1.625rem; padding: 0; display: grid; place-items: center;
  background: none; border: 0; border-radius: 6px; cursor: pointer;
  color: var(--muted); transition: background .12s, color .12s;
}
.tema-seg button:hover { color: var(--text); }
/* A opção escolhida em azul cheio, e não só com o texto azul sobre um fundo um
   tom mais claro: a diferença era só de matiz (luminâncias quase iguais), e
   quem enxerga pouco — justamente quem vem aqui mexer no Tamanho — não via
   qual estava marcada. */
.tema-seg button[aria-checked="true"] {
  background: var(--primary); color: var(--primary-ink); box-shadow: var(--shadow);
}
/* anel opaco: com o foco andando pelas setas, é ele que mostra onde o teclado
   está, e o --ring translúcido dava 1.6:1 contra o trilho */
.tema-seg button:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
/* o seletor do menu lateral herda a largura do botão de item; aqui não */
.user-menu .menu .tema-seg button { width: 1.875rem; }

/* Tamanho: mesmo controle do tema, com texto ("125%") no lugar do ícone. A
   linha de cima já tem o fio separador; esta divide o mesmo bloco. */
.escala-linha { border-top: 0; margin-top: 0; }
/* Com Tamanho 150% no celular, rótulo e botões lado a lado passavam da largura
   da folha. A linha quebra: o rótulo fica, os botões descem e encostam à
   direita, que é onde estavam. Na folha, em 100%, cabe numa linha só. */
.tema-linha { flex-wrap: wrap; row-gap: .45rem; }
.tema-linha .tema-seg { margin-left: auto; }
.escala-seg button,
.user-menu .menu .escala-seg button {
  width: auto; min-width: 2.6rem; padding: 0 .45rem;
  font: inherit; font-size: .75rem; font-weight: 650; font-variant-numeric: tabular-nums;
}
/* No menu da barra lateral a linha tem ~205px, e o rótulo com os três tamanhos
   não cabem juntos (pediam 226px). Em vez de espremer os botões — o contrário do
   que precisa quem veio aqui aumentar a letra —, eles vão para a linha de baixo
   dividindo a largura toda. */
.user-menu .menu .escala-linha .escala-seg { flex: 1 1 100%; margin-left: 0; }
.user-menu .menu .escala-seg button { flex: 1 1 0; height: 1.875rem; justify-content: center; }

.main { padding: 1rem; width: 100%; min-width: 0; }
.page-header {
  display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-4);
  margin-bottom: var(--sp-6); flex-wrap: wrap;
}
.page-header h1 { margin: .35rem 0 0; font-size: 1.65rem; letter-spacing: -.025em; }
.page-actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; }

@media (min-width: 900px) {
  .layout { grid-template-columns: var(--sidebar-w) 1fr; }
  .sidebar {
    border-bottom: none; border-right: 1px solid var(--border); position: sticky; top: 0; height: 100vh;
    padding: 1.15rem .75rem 1rem;
  }
  .brand { padding: 0 .35rem; }
  .brand-logo { height: 1.4375rem; }
  /* A navegação ocupa o meio e ROLA sozinha; o bloco do usuário fica preso
     embaixo. Antes a lateral tinha 100vh sem rolagem e a lista do gestor (13
     rotas) passava da janela — em 150% o conteúdo chegava a 1149px numa tela de
     650px, e o menu do usuário, onde mora o Tamanho, saía da tela: quem
     aumentou não conseguia voltar. min-height:0 é o que deixa um item flex
     encolher abaixo do próprio conteúdo e rolar. */
  .nav { display: flex; padding-top: 1.6rem; flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
  /* Uma área que rola corta o que desenha fora dela, e o anel de foco dos links
     fica por fora da borda: 3px de folga de cada lado, devolvidos pela margem
     negativa, para o anel aparecer inteiro sem mudar a posição dos links. */
  .nav { padding-inline: 3px; margin-inline: -3px; }
  .nav a > span:not(.badge-num) { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  .user-trigger { display: flex; }
  .user-menu .menu { top: auto; bottom: calc(100% + 0.375rem); }
  .main { padding: 1.75rem 2rem; }
  .sidebar-spacer { display: none; }
}
/* Em 150% a lateral de 16.5rem viraria 396px, quase um terço de um notebook de
   1280px. 14rem (336px) ainda cabe "Coleta de dados" com ícone e respiro, e
   devolve 60px ao conteúdo, que é onde a letra maior mais precisa de espaço. */
html[data-escala="150"] { --sidebar-w: 14rem; }

/* ---------- Convite para instalar o app (js/pwa.js) ----------
   Aparece só para quem ainda não instalou, com dois botões. No desktop fica
   num canto; no celular, logo acima da barra de abas — nunca por cima dela,
   senão tampa a navegação justamente enquanto pede atenção. */
.install-card {
  position: fixed; z-index: 45; right: 1.25rem; bottom: 1.25rem;
  width: min(23.125rem, calc(100vw - 2.5rem));
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .1rem .8rem;
  padding: 1rem 1.05rem; background: var(--surface);
  border: 1px solid var(--border-strong); border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}
.install-icone { width: 2.75rem; height: 2.75rem; border-radius: 10px; align-self: center; }
.install-txt { display: grid; gap: .2rem; align-content: center; min-width: 0; }
.install-txt strong { font-size: .95rem; letter-spacing: -.01em; }
.install-txt small { color: var(--muted); font-size: .82rem; line-height: 1.4; }
.install-txt small b { color: var(--text); font-weight: 600; }
.install-acoes {
  grid-column: 1 / -1; display: flex; gap: .5rem; justify-content: flex-end; margin-top: .8rem;
}

/* ---------- Empresas visitadas (js/pages/empresas.js) ----------
   Mesma grade de cards dos leads; o que muda é o conteúdo: contato, CNPJ e a
   última visita, que é o dado que o gestor procura. */
.emp-list { display: grid; gap: var(--gap-lista); grid-template-columns: repeat(auto-fill, minmax(min(18.125rem, 100%), 1fr)); }
.emp-card {
  display: grid; gap: .5rem; padding: .85rem 1rem; text-align: left; cursor: pointer;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  color: inherit; font: inherit; transition: border-color .15s, box-shadow .15s, transform .15s;
}
.emp-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); transform: translateY(-1px); }
.emp-card:focus-visible { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring); }
.emp-card .emp-top { display: flex; align-items: center; gap: .6rem; }
.emp-card .emp-nome { font-weight: 650; font-size: .98rem; line-height: 1.3; letter-spacing: -.01em; }
.emp-card .emp-sub { color: var(--muted); font-size: .85rem; }
.emp-card .emp-meta { display: flex; flex-wrap: wrap; gap: .25rem .8rem; font-size: .76rem; color: var(--faint); }
.emp-card .emp-meta span { display: inline-flex; align-items: center; gap: .3rem; }
.emp-card.sem-visita .emp-meta .visita { color: var(--warning); }

/* aviso de "já tem alguém em contato", embaixo do campo de nome */
.emp-aviso { display: flex; align-items: flex-start; gap: .5rem; margin-top: .4rem; padding: .55rem .7rem;
  border-radius: var(--radius-sm); background: var(--warning-soft); color: var(--text); font-size: .85rem; }
.emp-aviso.ok { background: var(--success-soft); }

/* visitas no detalhe: linha com a data e a miniatura da foto */
.visita-list { display: grid; gap: .5rem; margin: 0; padding: 0; list-style: none; }
.visita-item { display: grid; grid-template-columns: 4rem minmax(0, 1fr) auto; align-items: center; gap: .7rem;
  padding: .5rem .6rem; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-2); }
.visita-foto { width: 4rem; height: 4rem; border-radius: 8px; object-fit: cover; background: var(--gray-soft);
  display: grid; place-items: center; color: var(--muted); cursor: zoom-in; border: 0; padding: 0; }
.visita-foto img { width: 100%; height: 100%; object-fit: cover; border-radius: 8px; }
.visita-data { font-weight: 600; }
.visita-sub { color: var(--muted); font-size: .8rem; }

/* ---------- Plano vendido (fechamento do contrato, js/pages/leads.js) ----------
   Uma linha por plano com o preço à direita: a pessoa vê o valor antes de marcar,
   e o valor é o que vai para as Métricas. 44px porque no celular é um toque que
   decide dinheiro. */
.plan-list { display: grid; gap: .4rem; }
.plan-opt {
  display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: .6rem;
  min-height: 2.75rem; padding: .5rem .75rem; cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-2);
}
.plan-opt:has(input:checked) { border-color: var(--primary); background: var(--primary-soft); }
.plan-opt input { margin: 0; accent-color: var(--primary); }
.plan-nome { font-weight: 600; }
.plan-preco { color: var(--muted); font-variant-numeric: tabular-nums; }
.field > .label { display: block; font-weight: 600; margin-bottom: .35rem; }

/* ---------- Aviso de versão nova (js/pwa.js) ----------
   Mesmo canto e mesma geometria do convite de instalar — os dois nunca aparecem
   juntos, e o pwa.js garante isso. A borda em --primary é o que separa os dois à
   primeira vista: um é oferta, o outro é pendência.

   Sem botão de dispensar de propósito: fica até a pessoa atualizar. Mas também
   sem backdrop e sem travar a tela, porque quem está no meio de um cadastro
   precisa terminar antes de recarregar. */
.update-card {
  position: fixed; z-index: 46; right: 1.25rem; bottom: 1.25rem;
  width: min(23.125rem, calc(100vw - 2.5rem));
  display: grid; gap: .85rem;
  padding: 1rem 1.05rem; background: var(--surface);
  border: 1px solid var(--primary); border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}
.update-txt { display: grid; gap: .2rem; min-width: 0; }
.update-txt strong { font-size: .95rem; letter-spacing: -.01em; }
.update-txt small { color: var(--muted); font-size: .82rem; line-height: 1.4; }
.update-card .btn { justify-content: center; }

@media (max-width: 899px) {
  .install-card, .update-card {
    left: .6rem; right: .6rem; width: auto;
    /* acima da barra de abas, contando a faixa de gesto do iPhone */
    bottom: calc(4.9rem + env(safe-area-inset-bottom, 0px));
  }
  .install-acoes { justify-content: stretch; }
  /* 44px, e não os 40px do mínimo geral: nos dois cartões o botão é a ação que
     o app está PEDINDO para a pessoa fazer, e no de atualizar ele é o único
     alvo do cartão. Ver o bloco "Alvos de toque no celular" mais abaixo. */
  .install-acoes .btn { flex: 1; justify-content: center; min-height: 2.75rem; }
  .update-card .btn { min-height: 2.75rem; }
}

/* ---------- Celular: barra de abas embaixo + folha de menu ----------
   Abaixo de 900px a barra lateral some e a navegação vira uma tab bar fixa,
   alcançável com o polegar. Como o gestor tem 7 rotas e barra de abas com 7
   itens não se usa, cada papel expõe até 3 abas e a última ("Menu") abre uma
   folha com o resto das rotas e as ações de conta. Ver js/app.js. */
.tabbar, .sheet, .sheet-backdrop { display: none; }

@media (max-width: 899px) {
  /* No celular a lateral vira uma linha do grid, e sem linhas declaradas as
     duas eram automáticas: com `min-height: 100vh`, a sobra de altura era
     repartida entre elas e a faixa da marca esticava para ~237px com 34px de
     conteúdo — aquele vão branco embaixo da logo. `auto 1fr` dá à faixa só o
     que ela ocupa e entrega o resto ao conteúdo. */
  .layout { grid-template-rows: auto 1fr; }

  /* a lateral fica só como faixa da marca; navegação e usuário saem dela */
  .user-box, .sidebar-spacer { display: none; }
  /* instalado como PWA o app ocupa a tela toda (viewport-fit=cover), então a
     faixa da marca precisa descer o tanto do entalhe/status bar */
  .sidebar { padding-top: calc(.55rem + env(safe-area-inset-top, 0px)); }

  .tabbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
    display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
    background: var(--surface); border-top: 1px solid var(--border);
    /* env(): respeita a faixa do gesto no iPhone, senão a barra fica sob ela */
    padding: .35rem .35rem calc(.35rem + env(safe-area-inset-bottom, 0px));
  }
  .tabbar a, .tabbar button {
    display: grid; justify-items: center; align-content: center; gap: .25rem;
    min-width: 0; min-height: 3.375rem; padding: .25rem .15rem;
    background: none; border: 0; font: inherit; font-size: .7rem; font-weight: 600;
    color: var(--muted); cursor: pointer; -webkit-tap-highlight-color: transparent;
  }
  /* rótulo curto que só vale com escala (abaNaEscala em js/app.js): "Enviar
     lead" em 150% não cabe na aba; em 100% continua o rótulo inteiro */
  .tabbar .aba-curta { display: none; }
  html:is([data-escala="125"], [data-escala="150"]) .tabbar .aba-longa { display: none; }
  html:is([data-escala="125"], [data-escala="150"]) .tabbar .aba-curta { display: block; }
  /* rótulo numa linha só: duas linhas numa aba sobem o ícone dela acima dos
     vizinhos e a fileira perde o alinhamento (era o "Minhas empresas") */
  .tabbar a > span:not(.badge-num), .tabbar button > span:not(.badge-num) {
    max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  /* A aba ativa é marcada por uma pílula atrás do ícone, não por um retângulo
     cheio: o retângulo da largura da aba era o maior bloco de cor da tela e
     competia com o conteúdo. A pílula é o próprio SVG com padding — sem
     marcação a mais. O padding lateral para de crescer em 18px: com Tamanho
     150% a pílula chegava a 83px numa aba de ~90px e virava o retângulo cheio
     de antes. */
  .tabbar .ico {
    color: currentColor; box-sizing: content-box; padding: .25rem min(1.1rem, 18px);
    border-radius: 999px; transition: background .15s, color .15s;
  }
  .tabbar a:active .ico, .tabbar button:active .ico { background: var(--gray-soft); }
  .tabbar a.active, .tabbar button.active { color: var(--text); }
  .tabbar a.active .ico, .tabbar button.active .ico { background: var(--primary-soft); color: var(--primary); }
  .tabbar a:focus-visible, .tabbar button:focus-visible { outline: none; }
  .tabbar a:focus-visible .ico, .tabbar button:focus-visible .ico { box-shadow: 0 0 0 2px var(--ring); }

  /* sem isto o fim da página fica escondido atrás da barra */
  .main { padding-bottom: calc(4.6rem + env(safe-area-inset-bottom, 0px)); }

  /* Cabeçalho de página no celular. Já foram quatro andares antes do primeiro
     lead: a sobrelinha "USECLUBE · OPERAÇÃO", o título, a contagem e um botão
     "Atualizar" da largura da tela — o controle menos importante da página era
     o maior dela, e em toda tela. Agora:
       · a sobrelinha some (a marca está na faixa logo acima, e o nome da
         seção repetia o título);
       · o Atualizar vira um ícone de 40px no canto do título — ele continua
         lá para quem desconfia da lista, mas não disputa com o conteúdo;
       · as outras ações (Nova empresa, Ativar notificações) seguem numa
         fileira embaixo, da largura da tela, porque essas são o que a página
         está pedindo. */
  .page-header {
    position: relative; flex-direction: column; align-items: stretch;
    gap: var(--sp-3); margin-bottom: var(--sp-4);
  }
  .page-header .eyebrow { display: none; }
  .page-header h1 { margin-top: 0; font-size: 1.4rem; }
  .page-header:has(.btn-atualizar) .page-title { padding-right: 3rem; }
  /* `.page-actions .btn` (mais abaixo) estica os botões; este sai do fluxo */
  .page-actions .btn.btn-atualizar {
    position: absolute; top: -.2rem; right: 0;
    width: 2.5rem; height: 2.5rem; min-height: 2.5rem; padding: 0; flex: none;
  }
  /* botões que no celular viram só o ícone: o rótulo sai da vista mas continua
     sendo o nome do botão para o leitor de tela */
  .btn-atualizar .btn-rotulo, .btn-icone-celular .btn-rotulo {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  .btn.btn-icone-celular { flex: none; width: 2.75rem; min-height: 2.75rem; padding: 0; }
  /* sozinho, o ícone não pode deixar para trás uma fileira vazia ocupando o gap */
  .page-actions:has(> .btn-atualizar:only-child) { display: contents; }

  /* Estado por classe, não por [hidden]: com display:none a transição não roda,
     e keyframes sem `to` deixa a folha presa em translateY(100%) — fora da tela —
     quando a animação não re-dispara na segunda abertura. */
  .sheet-backdrop {
    display: block; position: fixed; inset: 0; z-index: 55; background: rgba(0, 0, 0, .55);
    opacity: 0; visibility: hidden; transition: opacity .2s ease-out, visibility .2s;
  }
  .sheet-backdrop.open { opacity: 1; visibility: visible; }

  .sheet {
    display: block; position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
    background: var(--surface); border-top: 1px solid var(--border);
    border-radius: 18px 18px 0 0; box-shadow: var(--shadow-lg);
    padding: .5rem 1rem calc(1rem + env(safe-area-inset-bottom, 0px));
    max-height: 80vh; overflow-y: auto;
    /* ao escolher um Tamanho, o seletor é trazido à vista (scrollIntoView): sem
       isto ele parava colado na borda de baixo, sobre a faixa de gesto */
    scroll-padding-bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
    transform: translateY(100%); visibility: hidden;
    transition: transform .2s ease-out, visibility .2s;
  }
  .sheet.open { transform: none; visibility: visible; }

  .sheet-grab { width: 2.375rem; height: 4px; border-radius: 999px; background: var(--border-strong); margin: .35rem auto .9rem; }
  .sheet-user { display: flex; align-items: center; gap: .7rem; padding: 0 .2rem .9rem; border-bottom: 1px solid var(--border); }
  .sheet-links { display: grid; gap: .1rem; padding: .6rem 0; border-bottom: 1px solid var(--border); }
  /* `> button` e não `button`: o seletor de tema é injetado dentro de
     .sheet-actions e herdava este estilo de item de menu, ficando deformado.
     Ele vive dentro de um .tema-linha, então o filho direto não o alcança. */
  .sheet-links a, .sheet-actions > button {
    display: flex; align-items: center; gap: .7rem; width: 100%; padding: .7rem .5rem;
    background: none; border: 0; border-radius: var(--radius-sm);
    font: inherit; font-size: .95rem; font-weight: 500; color: var(--text);
    text-align: left; cursor: pointer;
  }
  .sheet-links a .ico, .sheet-actions > button .ico { color: var(--faint); }
  .sheet-links a:active, .sheet-actions > button:active { background: var(--gray-soft); }
  .sheet-links a.active { background: var(--primary-soft); font-weight: 600; }
  .sheet-links a.active .ico { color: var(--primary); }
  .sheet-actions { display: grid; gap: .1rem; padding-top: .6rem; }
}

/* ---------- Filtros ---------- */
.filters { display: grid; grid-template-columns: 1fr 1fr; gap: .5rem; margin-bottom: 1.15rem; }
.filters input, .filters select { padding: .5rem .65rem; }
.filters .grow { grid-column: 1 / -1; }
@media (min-width: 720px) {
  .filters { display: flex; flex-wrap: wrap; align-items: center; }
  .filters > * { flex: 0 1 11.875rem; }
  .filters .grow { flex: 1 1 16.25rem; max-width: 28.75rem; margin-right: auto; }
}

/* ---------- Barra de filtros
   No celular os filtros de Leads ocupavam quatro linhas antes do primeiro card:
   oito chips de status, busca e período. Aqui eles viram um botão só, que abre
   o painel e mostra no rótulo o filtro em vigor — a informação continua à vista
   sem custar a tela inteira. No desktop o botão some e o painel fica aberto,
   que é onde sobra espaço horizontal.
   ---------------------------------------------------------------------------- */
.filterbar { display: flex; gap: .5rem; align-items: stretch; margin-bottom: .7rem; }
/* Meio a meio. Já foi 45/55 a favor do botão, quando a busca dizia "Buscar por
   nome ou telefone…" e cortava de qualquer jeito. O botão ("Abertos · 30 dias")
   precisa de toda a metade dele; a busca, com a lupa, diz só "Buscar" — mesmo
   "Nome ou telefone" passava 3px da metade num aparelho de 375px. */
.filterbar > input[type="search"] { flex: 1 1 50%; min-width: 0; padding: .5rem .65rem; }

.filterbar-toggle {
  display: inline-flex; align-items: center; gap: .4rem; flex: 1 1 50%; min-width: 0;
  /* mesmo fundo dos campos: divide a linha com a busca, e no tema claro um
     branco ao lado de um cinza parecia dois componentes de telas diferentes */
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: .45rem .65rem; font: inherit; font-size: .82rem; font-weight: 600;
  cursor: pointer; transition: border-color .15s, color .15s;
}
.filterbar-toggle .resumo { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1 1 auto; text-align: left; }
.filterbar-toggle .ico { flex: none; color: var(--faint); }
.filterbar-toggle .caret { transition: transform .18s; }
.filterbar-toggle[aria-expanded="true"] { border-color: var(--primary); color: var(--primary); }
.filterbar-toggle[aria-expanded="true"] .ico { color: var(--primary); }
.filterbar-toggle[aria-expanded="true"] .caret { transform: rotate(180deg); }
.filterbar-toggle.grow { flex: 1 1 auto; justify-content: space-between; }

/* Campo de busca com a lupa desenhada dentro. Com ela o campo se explica
   sozinho, e o texto de exemplo pôde encolher: "Buscar por nome ou telefone…"
   cortava ao meio no celular, hoje é "Nome ou telefone" (ou só "Buscar", onde
   a busca divide a linha). O nome completo, para o leitor de tela, está no
   aria-label de cada campo.
   É a única cor literal fora das exceções do topo do arquivo: data URI não lê
   custom property. O cinza médio é decorativo e aparece nos dois temas.
   A regra repete os seletores de .filterbar e .filters de propósito — eles
   definem `padding` inteiro e, com a mesma especificidade, vinham depois. */
input[type="search"],
.filterbar > input[type="search"],
.filters input[type="search"] {
  padding-left: 2rem; padding-right: .5rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238c8c8c' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.8-3.8'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: .65rem center; background-size: 1rem 1rem;
}

.filterbar-panel {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); padding: .75rem .8rem .1rem; margin-bottom: 1rem;
}
.filterbar-panel .filters { margin-bottom: .65rem; }
.filterbar-panel .status-chips { margin-bottom: .65rem; }

/* Estado por classe, e não pelo atributo `hidden`: a regra global
   `[hidden] { display: none !important }` venceria a media query abaixo, e o
   painel — que nasce recolhido — sumiria no desktop, onde não há botão para
   trazê-lo de volta. O botão continua anunciando o estado por aria-expanded. */
.filterbar-panel.collapsed { display: none; }

@media (min-width: 900px) {
  /* tela larga: nada a esconder — o painel volta a ser a fileira de filtros */
  .filterbar-toggle { display: none; }
  /* Uma FILEIRA, não uma pilha. Com `display: block` o seletor de representante
     caía numa linha só para ele, embaixo dos botões de período, desperdiçando a
     largura que existe de sobra no desktop. Em linha, os dois filtros do mesmo
     assunto ficam juntos e o conteúdo sobe. O `wrap` é a saída de emergência:
     se os chips crescerem (a lista de status é longa), o seletor desce sozinho
     em vez de espremer. */
  /* margin-bottom: a fileira de filtros encostava no primeiro cartão (0px de
     distância), e o filtro parecia fazer parte da lista */
  .filterbar-panel,
  .filterbar-panel.collapsed {
    display: flex; flex-wrap: wrap; align-items: center; gap: .55rem .7rem;
    border: none; background: none; padding: 0; margin-bottom: var(--gap-bloco);
  }
  /* as margens de baixo eram o espaçamento da pilha; na fileira quem separa é o gap */
  .filterbar-panel .filters,
  .filterbar-panel .status-chips { margin-bottom: 0; }
  .filterbar-panel .segmented { flex: none; }
  /* Largura do próprio seletor, não "o que sobrar": com base de 240px e
     crescimento livre, o período de Leads nunca cabia ao lado dos oito status e
     descia sozinho para uma terceira linha de filtros. */
  .filterbar-panel .filters { flex: 0 1 auto; }
  .filterbar-panel .filters .grow { flex: 0 0 auto; width: auto; max-width: 100%; margin-right: 0; }
  /* na fileira dos status, o seletor tem a altura e o formato deles — com os
     40px de um campo de formulário ele sobrava ao lado de botões de 26px */
  .filterbar-panel .filters select {
    padding: .3rem 1.9rem .3rem .8rem; border-radius: 999px;
    font-size: .8rem; font-weight: 500; color: var(--muted); background-color: var(--surface);
  }
  /* em Métricas o vizinho é o controle de período, mais alto que os status */
  .filterbar-panel:has(.segmented) .filters select { padding-block: .5rem; }
  /* Oito status + o período numa fileira só a partir de 1280px. Com mouse o
     alvo menor não custa nada; no celular esta regra nem existe. */
  .filterbar-panel .status-chips { gap: .3rem; }
  .filterbar-panel .status-chips button { padding: .28rem .58rem; font-size: .76rem; }
  .filterbar { margin-bottom: var(--sp-3); }
}

/* ---------- Tabela larga vira lista de cards no celular
   Dez colunas num aparelho de 375px viravam uma faixa de rolagem lateral onde
   o nome do representante saía da tela junto com o resto. Aqui cada linha vira
   um cartão e cada célula ganha o próprio rótulo, então nada depende mais de
   lembrar qual coluna era qual.
   ---------------------------------------------------------------------------- */
@media (max-width: 899px) {
  .table-cards, .table-cards tbody, .table-cards tr, .table-cards td { display: block; width: 100%; }
  .table-cards thead { display: none; }
  .table-cards tr {
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
    padding: .35rem .85rem .6rem; margin-bottom: .6rem;
  }
  .table-cards td {
    border: none; padding: .3rem 0;
    display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
    font-variant-numeric: tabular-nums;
    /* E-mail é um token sem espaços que o navegador não quebra sozinho; sem isto
       ele estoura o cartão no celular. Vale para qualquer valor longo — resolve
       de uma vez em Usuários e em Contatos. */
    min-width: 0; overflow-wrap: anywhere;
  }
  /* Com escala, o valor que não cabe ao lado do rótulo desce para a linha de
     baixo: "Telefone +55 (47) 99911-0006" em 150% pedia 310px num cartão de
     219px, e o valor em nowrap estourava o cartão. */
  html:is([data-escala="125"], [data-escala="150"]) .table-cards td { flex-wrap: wrap; gap: .15rem 1rem; }
  /* mesmo rótulo de campo do resto do app (ver "Rótulos em caixa alta"), só
     que em --muted: aqui ele divide a linha com o valor e precisa ser lido */
  .table-cards td::before {
    content: attr(data-label); flex: none;
    color: var(--muted); font-size: .6875rem; font-weight: 650;
    text-transform: uppercase; letter-spacing: .06em;
  }
  /* primeira célula é o título do cartão: sem rótulo, com fio embaixo */
  .table-cards td:first-child {
    display: block; font-size: 1rem; padding: .5rem 0 .55rem;
    border-bottom: 1px solid var(--border); margin-bottom: .3rem;
  }
  .table-cards td:first-child::before { content: none; }
  /* a barra de meta precisa da linha inteira, não da metade que sobra */
  .table-cards td.stacked { display: block; padding-top: .5rem; }
  .table-cards td.stacked::before { display: block; margin-bottom: .35rem; }
  /* valor com segunda linha (plano + preço, data + autor): um item só ao lado do
     rótulo — sem o invólucro, cada pedaço virava um item do flex e o cartão
     espalhava as partes pela largura */
  .table-cards td .cell-val { text-align: right; }
  .table-cards td.empty-row { display: block; text-align: left; }
  .table-cards td.empty-row::before { content: none; }
  /* fileira de botões: ocupa a largura do cartão, sem rótulo à esquerda */
  .table-cards td.cell-actions { display: block; padding-top: .6rem; }
  .table-cards td.cell-actions::before { content: none; }
  .table-cards td.cell-actions .table-actions { justify-content: flex-start; flex-wrap: wrap; }
}


/* ---------- Cartão de lead ----------
   Uma linha: [nome / telefone · há quanto tempo] ........ [etiqueta].
   Já foram três definições deste cartão empilhadas no arquivo (a original, um
   "um degrau maior" e um "enxuto"), cada uma desfazendo parte da anterior, e
   um quadradinho de ícone repetindo a cor da etiqueta. Agora é esta, só. */
/* min(…, 100%) em todas as grades de cartões: com Tamanho 150% o mínimo em rem
   passa da largura de um celular, e a coluna única estourava a tela para a
   direita. Assim o mínimo nunca passa da largura disponível.
   Com escala, o mínimo sobe para 19rem: é a largura em que nome, telefone
   inteiro e etiqueta cabem lado a lado — abaixo dela o cartão passa para duas
   linhas (ver a consulta de contêiner logo abaixo), e no desktop isso não deve
   acontecer. Em 100% fica o 16.875rem (270px) de sempre. */
.lead-list { display: grid; gap: var(--gap-lista); grid-template-columns: repeat(auto-fill, minmax(min(16.875rem, 100%), 1fr)); }
html:is([data-escala="125"], [data-escala="150"]) .lead-list { grid-template-columns: repeat(auto-fill, minmax(min(19rem, 100%), 1fr)); }
.lead-card {
  display: flex; flex-wrap: wrap; align-items: center; gap: .35rem var(--sp-3);
  min-width: 0; min-height: 4.125rem; padding: .8rem 1rem;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); cursor: pointer;
  transition: border-color .15s, box-shadow .15s, transform .1s;
}
.lead-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); transform: translateY(-1px); }
.lead-card:focus-visible { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring); }

/* base 0 + min-width 0: o bloco do nome ocupa o que sobra ao lado da etiqueta
   e corta com reticências, em vez de empurrar a etiqueta para a linha de baixo */
.lead-card .lead-id { flex: 1 1 0; min-width: 0; }
.lead-card .lead-name {
  font-size: .95rem; font-weight: 600; line-height: 1.3; letter-spacing: -.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lead-card .lead-phone {
  margin-top: .15rem; font-size: .82rem; color: var(--muted);
  font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Coluna da direita: etiqueta em cima, "há 2 h" embaixo. O tempo já dividiu a
   linha do telefone e cortava ("há 3 di…") sempre que a etiqueta era larga;
   aqui ele tem a largura da etiqueta, e numa lista os tempos ficam alinhados
   uns sob os outros — dá para varrer a coluna e achar quem está esperando. */
.lead-card .lead-chips {
  flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: .3rem;
}
.lead-card .lead-quando {
  font-size: .75rem; color: var(--faint); white-space: nowrap; font-variant-numeric: tabular-nums;
}
/* Cartão estreito — o que acontece no celular com Tamanho 125% ou 150% —: a
   etiqueta e o "há 2 h" descem para uma linha própria, um em cada ponta, e o
   nome e o telefone ganham a largura toda. Lado a lado, o nome virava "Ana
   Paula Rib…" e o telefone perdia os últimos dígitos, justo para quem pediu
   letra maior. Consulta de contêiner, e não media query: quem decide é a
   largura do CARTÃO (que muda com a grade e com a escala), não a da tela. O
   limite em rem acompanha a escala (16.5rem são 330px em 125%, 396px em 150%),
   e é a mesma conta dos dois lados: nome, telefone e etiqueta crescem juntos.
   Só com escala: em 100% o cartão é exatamente o de antes. */
.lead-card { container-type: inline-size; }
@container (max-width: 16.5rem) {
  html:is([data-escala="125"], [data-escala="150"]) .lead-card .lead-chips {
    flex: 1 0 100%; flex-direction: row; align-items: center; justify-content: space-between;
  }
}
/* linha extra que ocupa o cartão inteiro (em "Enviados hoje": para quem foi) */
.lead-card .lead-meta {
  flex: 1 0 100%; min-width: 0; display: flex; flex-wrap: wrap; gap: .25rem .8rem;
  padding-top: .5rem; border-top: 1px solid var(--border);
  font-size: .78rem; color: var(--muted);
}
.lead-card .lead-meta span { display: inline-flex; align-items: center; gap: .3rem; min-width: 0; }
.lead-card .lead-meta .ico { color: var(--faint); }
.empty { text-align: center; color: var(--muted); padding: 2.5rem 1rem; grid-column: 1 / -1; }
.empty .big { display: inline-grid; place-items: center; width: 2.75rem; height: 2.75rem; border-radius: 12px;
  background: var(--gray-soft); color: var(--faint); margin-bottom: .7rem; }

/* status chips (contadores) */
.status-chips { display: flex; gap: .4rem; flex-wrap: wrap; margin-bottom: var(--gap-bloco); }
.status-chips button {
  display: inline-flex; align-items: center; gap: .35rem;
  border: 1px solid var(--border); background: var(--surface); border-radius: 999px; padding: .32rem .75rem;
  font: inherit; font-size: .8rem; font-weight: 500; cursor: pointer; color: var(--muted);
  transition: border-color .15s, background .15s, color .15s;
}
.status-chips button:hover { border-color: var(--border-strong); color: var(--text); }
.status-chips button.active { border-color: var(--primary); color: var(--primary-ink); background: var(--primary); }
.status-chips .count { font-weight: 700; font-variant-numeric: tabular-nums; }
.status-chips button .count { color: var(--faint); }
.status-chips button.active .count { color: color-mix(in srgb, var(--primary-ink) 70%, transparent); }

/* ---------- Detalhe do lead (modal) ---------- */
.lead-detail .top { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; flex-wrap: wrap; }
.lead-detail .phone-actions { display: flex; gap: .4rem; flex-wrap: wrap; margin: .5rem 0 1rem; }
.status-picker { display: flex; flex-wrap: wrap; gap: .4rem; }
.status-picker button {
  display: inline-flex; align-items: center; gap: .35rem;
  border: 1px solid var(--border); background: var(--surface); border-radius: 999px; padding: .4rem .8rem;
  font: inherit; font-size: .85rem; font-weight: 500; cursor: pointer; color: var(--muted);
}
.status-picker button:hover { border-color: var(--border-strong); color: var(--text); }
.status-picker button.active { border-width: 2px; }
.status-picker button.s-novo.active         { border-color: var(--info);    color: var(--info);    background: var(--info-soft); }
.status-picker button.s-sem-resposta.active { border-color: var(--muted);        color: var(--muted);        background: var(--gray-soft); }
.status-picker button.s-negociando.active   { border-color: var(--purple);  color: var(--purple);  background: var(--purple-soft); }
.status-picker button.s-ganho.active        { border-color: var(--success); color: var(--success); background: var(--success-soft); }
.status-picker button.s-perdido.active      { border-color: var(--danger);  color: var(--danger);  background: var(--danger-soft); }
.status-picker button.s-inadimplente.active { border-color: var(--warning); color: var(--warning); background: var(--warning-soft); }
.section-title { margin: var(--sp-6) 0 var(--sp-3); }
.timeline { list-style: none; margin: 0; padding: 0; display: grid; gap: .45rem; }
.timeline li { display: flex; gap: .6rem; font-size: .85rem; align-items: baseline; }
.timeline .when { color: var(--muted); white-space: nowrap; min-width: 6.5625rem; font-variant-numeric: tabular-nums; }
.note-list { display: grid; gap: .5rem; }
.note { background: var(--gray-soft); border-radius: var(--radius-sm); padding: .55rem .7rem; font-size: .9rem; }
.note .who { font-size: .75rem; color: var(--muted); margin-top: .2rem; }
.note-form { display: flex; gap: .5rem; margin-top: .5rem; }
.note-form textarea { min-height: 2.75rem; }
.kv { display: grid; grid-template-columns: max-content 1fr; gap: .25rem .75rem; font-size: .9rem; }
.kv dt { color: var(--muted); }
.kv dd {
  margin: 0;
  /* sem isto, uma palavra sem espaço (link colado numa observação) estica a
     coluna e o modal ganha rolagem lateral: a trilha 1fr tem min-width auto */
  min-width: 0; overflow-wrap: anywhere;
}

/* ---------- Comprovante do contrato ---------- */
.proof-list { list-style: none; margin: .5rem 0 0; padding: 0; display: grid; gap: .4rem; }
.proof-item {
  display: flex; align-items: center; gap: .6rem;
  background: var(--gray-soft); border-radius: var(--radius-sm); padding: .45rem .55rem;
}
.proof-meta { display: grid; gap: .1rem; min-width: 0; flex: 1; }
.proof-name {
  background: none; border: 0; padding: 0; text-align: left; cursor: pointer;
  color: var(--primary); font: inherit; font-size: .88rem; font-weight: 600;
  overflow-wrap: anywhere;
}
.proof-name:hover { color: var(--primary-hover); text-decoration: underline; }
.proof-empty { display: flex; align-items: center; gap: .4rem; }

/* ---------- Território do representante ---------- */
.terr-add { display: grid; grid-template-columns: 1fr; gap: .4rem; }
@media (min-width: 640px) { .terr-add { grid-template-columns: 1fr 1fr auto; align-items: start; } }

.terr-chips { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .5rem; }
.terr-chip {
  display: inline-flex; align-items: center; gap: .3rem;
  background: var(--primary-soft); color: var(--text);
  border: 1px solid var(--border); border-radius: 999px;
  padding: .2rem .35rem .2rem .55rem; font-size: .8rem;
}
/* cidade inteira é uma promessa maior que um bairro: cor diferente para não passar batido */
.terr-chip.is-city { background: var(--purple-soft); border-color: var(--purple); }
.terr-chip button {
  display: grid; place-items: center; width: 1.375rem; height: 1.375rem; flex: none;
  background: none; border: 0; border-radius: 50%; padding: 0; cursor: pointer; color: var(--muted);
}
.terr-chip button:hover { background: var(--danger-soft); color: var(--danger); }

.terr-sug {
  display: flex; flex-wrap: wrap; align-items: center; gap: .3rem;
  margin-top: .4rem; font-size: .82rem; line-height: 1.4;
}
.terr-sug.muted { color: var(--muted); }
.terr-opts { display: flex; flex-wrap: wrap; gap: .3rem; }
/* escolher representante aqui é um toque de verdade no celular: mesma altura do .btn-sm */
.terr-opts button {
  background: var(--surface-2); color: var(--text); border: 1px solid var(--border);
  border-radius: 999px; padding: .3rem .7rem; font-size: .78rem; cursor: pointer;
  min-height: 1.6875rem;
}
.terr-opts button:hover { border-color: var(--primary); color: var(--primary); }

/* ---------- Tabelas ---------- */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table { width: 100%; border-collapse: collapse; font-size: .9rem; }
th, td { padding: .6rem .6rem; border-bottom: 1px solid var(--border); text-align: left; vertical-align: middle; }
th { white-space: nowrap; }
tbody tr:hover { background: var(--surface-2); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
.table-actions { display: flex; gap: .3rem; justify-content: flex-end; }

/* ---------- KPIs / métricas ---------- */
.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(11.5625rem, 100%), 1fr)); gap: .7rem; margin-bottom: 1.15rem; }
.kpi {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: .85rem .95rem; box-shadow: var(--shadow); min-width: 0;
}
.kpi .label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.kpi .value { font-size: 1.6rem; font-weight: 700; letter-spacing: -.02em; margin-top: .3rem; line-height: 1.1; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.kpi .sub { font-size: .78rem; color: var(--muted); margin-top: .2rem; }

/* legenda ao lado do gráfico de rosca */
.chart-legend { display: grid; gap: .1rem; margin-top: .6rem; }
.chart-legend .row {
  display: grid; grid-template-columns: 0.625rem 1fr auto auto; align-items: center; gap: .55rem;
  padding: .3rem .1rem; font-size: .84rem; border-top: 1px solid var(--border);
}
.chart-legend .row:first-child { border-top: none; }
.chart-legend .dot { width: 0.625rem; height: 0.625rem; border-radius: 3px; }
.chart-legend .n { font-weight: 700; font-variant-numeric: tabular-nums; }
.chart-legend .p { color: var(--faint); font-variant-numeric: tabular-nums; min-width: 2.625rem; text-align: right; }
.charts { display: grid; grid-template-columns: 1fr; gap: 1rem; margin-bottom: 1.15rem; }
@media (min-width: 1080px) { .charts { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); } }
.chart-box { position: relative; height: 18.75rem; min-width: 0; }
.chart-box.short { height: 15rem; }
.chart-box.tall { height: 22.5rem; }
.progress { height: 0.5rem; background: var(--gray-soft); border-radius: 999px; overflow: hidden; min-width: 5rem; }
.progress > span { display: block; height: 100%; background: var(--primary); border-radius: 999px; }
.progress.done > span { background: var(--success); }
.segmented { display: inline-flex; border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; background: var(--surface); }
.segmented button { border: none; background: transparent; padding: .45rem .8rem; font: inherit; font-weight: 600; cursor: pointer; color: var(--muted); }
.segmented button.active { background: var(--primary-soft); color: var(--primary); }
.legend { display: flex; flex-wrap: wrap; gap: .3rem .9rem; font-size: .8rem; color: var(--muted); }
.legend > span { display: inline-flex; align-items: center; gap: .25rem; }
.legend i { display: inline-block; width: 0.625rem; height: 0.625rem; border-radius: 2px; margin-right: .3rem; vertical-align: -1px; }

/* ---------- Toast ---------- */
.toast-root {
  /* Parte da altura da faixa da marca, não do topo da tela: com `top: 1rem` o
     aviso nascia POR CIMA da logo (a faixa tem ~53px e z-index 30; o toast, 100).
     E somava o inset do entalhe como todo o resto do app já fazia — .sidebar,
     .tabbar, .main, .sheet e .install-card somam; só este ficara de fora, então
     no iPhone o aviso nascia debaixo da barra de status. */
  position: fixed;
  top: calc(3.6rem + env(safe-area-inset-top, 0px));
  right: calc(1rem + env(safe-area-inset-right, 0px));
  left: auto; bottom: auto; transform: none;
  display: grid; gap: .45rem; justify-items: end; z-index: 100; width: min(92vw, 20.625rem);
  pointer-events: none;
}
@media (min-width: 900px) {
  /* no desktop a marca fica na lateral, não no topo — o aviso pode subir */
  .toast-root { top: calc(1rem + env(safe-area-inset-top, 0px)); }
}
.toast {
  display: flex; align-items: flex-start; gap: .5rem; width: fit-content; max-width: 100%;
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--border-strong); border-left: 3px solid var(--muted);
  padding: .55rem .8rem; border-radius: var(--radius-sm); box-shadow: var(--shadow-lg);
  font-size: .84rem; line-height: 1.4;
  opacity: 0; transform: translateX(10px); transition: opacity .18s, transform .18s;
}
.toast.show { opacity: 1; transform: none; }
/* o tipo aparece como fio colorido e ícone, não como fundo chapado */
.toast .ico { color: var(--muted); margin-top: .08rem; }
.toast-success { border-left-color: var(--success); }
.toast-success .ico { color: var(--success); }
.toast-error { border-left-color: var(--danger); }
.toast-error .ico { color: var(--danger); }
.toast-warning { border-left-color: var(--warning); }
.toast-warning .ico { color: var(--warning); }
.toast-info { border-left-color: var(--info); }
.toast-info .ico { color: var(--info); }

/* ---------- Modal ---------- */
.modal-overlay {
  position: fixed; inset: 0; background: rgba(8, 8, 8, .32); backdrop-filter: blur(7px); -webkit-backdrop-filter: blur(7px); display: flex; align-items: flex-end; justify-content: center;
  z-index: 90; opacity: 0; transition: opacity .2s; padding: 0;
}
.modal-overlay.show { opacity: 1; }
.modal {
  background: var(--surface); width: 100%; max-height: 92vh; overflow: auto; border-radius: var(--radius) var(--radius) 0 0;
  box-shadow: var(--shadow-lg); transform: translateY(20px); transition: transform .2s;
}
.modal-overlay.show .modal { transform: none; }
.modal-header { display: flex; align-items: center; justify-content: space-between; padding: .9rem 1rem .5rem; position: sticky; top: 0; background: var(--surface); z-index: 1; }
.modal-title { margin: 0; }
.modal-body { padding: .5rem 1rem 1rem; }
.modal-footer { display: flex; justify-content: flex-end; gap: .5rem; padding: .75rem 1rem 1rem; border-top: 1px solid var(--border); position: sticky; bottom: 0; background: var(--surface); }

/* No celular o modal vira folha colada no rodapé, e ali embaixo, no iPhone, mora
   a faixa do gesto de voltar à tela inicial — os botões Salvar/Cancelar caíam
   debaixo dela. Todo o resto do app já somava este inset; o modal não.
   `:last-child` mira só o modal SEM rodapé: onde há rodapé, quem precisa do
   respiro é ele, e somar nos dois deixaria um vão morto no meio. */
.modal-footer { padding-bottom: calc(1rem + env(safe-area-inset-bottom, 0px)); }
.modal-body:last-child { padding-bottom: calc(1rem + env(safe-area-inset-bottom, 0px)); }

@media (min-width: 640px) {
  .modal-overlay { align-items: center; padding: 1rem; }
  .modal { border-radius: var(--radius); max-height: 90vh; }
  /* centralizado, o modal não encosta mais na borda: o inset viraria vão à toa */
  .modal-footer, .modal-body:last-child { padding-bottom: 1rem; }
  .modal-sm { max-width: 26.25rem; }
  .modal-md { max-width: 38.75rem; }
  .modal-lg { max-width: 53.75rem; }
}

/* ---------- Login ---------- */
.auth-page { min-height: 100vh; display: grid; grid-template-columns: minmax(0, 1fr); place-items: center; padding: 1rem; background: var(--bg); }
.auth-card {
  width: 100%; max-width: 25rem; background: var(--surface); border: 1px solid var(--border);
  border-radius: 16px; box-shadow: var(--shadow-md); padding: 2rem 1.6rem;
}
.auth-brand { display: flex; justify-content: center; margin-bottom: 1.6rem; }
.auth-brand .logo-useclube { height: 1.625rem; }
.auth-foot { text-align: center; font-size: .82rem; color: var(--muted); margin-top: 1rem; }
/* link de texto que na verdade é <button> (não navega, só troca o painel) */
.link-btn {
  background: none; border: 0; padding: 0; font: inherit; color: var(--primary);
  cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
}
.link-btn:hover { color: var(--primary-hover); }
.link-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 4px; }
.auth-lead { text-align: center; font-size: .9rem; color: var(--muted); margin-bottom: 1rem; }
.auth-back { margin: -.4rem 0 .6rem -.4rem; }
.auth-role-line { display: flex; align-items: center; justify-content: center; gap: .45rem; font-size: .9rem; color: var(--muted); margin-bottom: 1.1rem; }

/* escolha do papel na tela inicial */
.role-picker { display: grid; gap: .6rem; }
.role-option {
  display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: .8rem;
  padding: .75rem .85rem; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); color: var(--text);
  transition: border-color .15s, box-shadow .15s, transform .05s;
}
.role-option:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); }
.role-option:active { transform: translateY(1px); }
.role-option:focus-visible { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring); }
.role-option .role-ico { width: 2.375rem; height: 2.375rem; border-radius: 10px; display: grid; place-items: center; background: var(--gray-soft); color: var(--muted); }
.role-option[data-role="gestor"]       .role-ico { background: var(--purple-soft);  color: var(--purple); }
.role-option[data-role="operador"]        .role-ico { background: var(--info-soft);    color: var(--info); }
.role-option[data-role="representante"] .role-ico { background: var(--success-soft); color: var(--success); }
.role-option .role-go { display: inline-grid; }
.role-option strong { display: block; font-weight: 700; }
.role-option small { color: var(--muted); font-size: .82rem; }
.role-option .role-go { color: var(--muted); font-weight: 700; }

/* ---------- Diversos ---------- */
.inline-list { display: flex; gap: .4rem; flex-wrap: wrap; align-items: center; }
/* campo num flex nasce com min-width:auto (a largura do texto de exemplo) e não
   encolhe: com letra maior, o telefone de teste da Configuração estourava o cartão */
.inline-list > input { min-width: 0; }
.alert {
  display: flex; align-items: flex-start; gap: .55rem;
  padding: .7rem .9rem; border-radius: var(--radius-sm); font-size: .9rem; margin-bottom: 1rem;
}
.alert .ico { margin-top: .1rem; }
.alert-warning { background: var(--warning-soft); color: var(--warning); }
.alert-info { background: var(--info-soft); color: var(--info); }
.alert-danger { background: var(--danger-soft); color: var(--danger); }
.skeleton { background: linear-gradient(90deg, var(--surface) 25%, var(--surface-2) 37%, var(--surface) 63%); background-size: 400% 100%; animation: shimmer 1.2s infinite; border-radius: var(--radius-sm); height: 4rem; }
@keyframes shimmer { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }
.pulse { animation: pulse 1.2s ease-in-out 3; }
@keyframes pulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(37, 99, 235, .0); } 50% { box-shadow: 0 0 0 6px rgba(37, 99, 235, .25); } }

/* =============================================================================
   Ajustes do layout minimalista (referência: painel escuro)
   ============================================================================= */

/* faixa de KPIs: um bloco só, células separadas por fio de 1px */
.kpis {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(11.875rem, 100%), 1fr));
  gap: 1px; background: var(--border);
  border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden;
  margin-bottom: 1.5rem;
}
.kpi {
  background: var(--surface); border: none; border-radius: 0; box-shadow: none;
  padding: 1.1rem 1.25rem;
}
.kpi .value { font-size: 1.9rem; margin-top: .45rem; }
.kpi .sub { margin-top: .35rem; }
.kpi .delta { font-weight: 600; }
.kpi .delta.up { color: var(--success); }
.kpi .delta.down { color: var(--danger); }



/* cabeçalho de página com sobrelinha */
.page-title { min-width: 0; }
.page-title .muted { margin-top: .3rem; }

/* controles segmentados no estilo pílula */
.segmented { border-radius: 999px; padding: 3px; background: var(--surface-2); border-color: var(--border); }
.segmented button { border-radius: 999px; padding: .4rem .85rem; font-size: .85rem; }
.segmented button.active { background: var(--primary); color: var(--primary-ink); }

.icon-tile { width: 2.125rem; height: 2.125rem; }

/* tabelas mais arejadas */
th, td { padding: .7rem .65rem; }

/* a barra lateral no escuro encosta no fundo, sem parecer um cartão */
.sidebar { background: var(--sidebar-bg); }
@media (min-width: 900px) { .sidebar { padding: 1.25rem .85rem 1.1rem; } }


/* O Chart.js nem sempre reduz o canvas quando o container encolhe (ele só
   cresce de volta no próximo resize). Sem isto, o gráfico vaza para fora do
   card e cria scroll horizontal na página. */
.chart-box { overflow: hidden; }
.chart-box > canvas { max-width: 100%; }

/* ---------- Leads agrupados por representante ---------- */
.rep-groups { display: grid; gap: 1.6rem; }
.rep-group { display: grid; gap: .85rem; }
.rep-group-head {
  display: flex; align-items: center; justify-content: space-between; gap: .4rem 1rem; flex-wrap: wrap;
  padding-bottom: .7rem; border-bottom: 1px solid var(--border);
}
.rep-name { display: flex; align-items: center; gap: .7rem; color: var(--text); min-width: 0; }
.rep-name:hover strong { color: var(--primary); }
.rep-name .avatar { width: 2.25rem; height: 2.25rem; font-size: .8rem; }
.rep-name-txt { display: grid; min-width: 0; line-height: 1.25; }
.rep-name-txt strong { font-size: 1rem; letter-spacing: -.01em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rep-name-txt small { color: var(--faint); font-size: .78rem; }
.rep-group-more { display: inline-block; font-size: .84rem; color: var(--primary); }

/* Painel da equipe: substitui a antiga caixa "nenhum lead" por representante —
   com 9 pessoas aquilo virava uma parede de vazio. Aqui a equipe inteira cabe
   em poucas linhas e quem não tem lead só fica esmaecido. */
.section-label { margin: 0 0 var(--sp-3); }
.rep-board { display: grid; gap: .55rem; grid-template-columns: repeat(auto-fill, minmax(min(12.5rem, 100%), 1fr)); }
.rep-tile {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center;
  gap: .5rem .65rem; padding: .65rem .8rem; color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface);
  transition: border-color .15s, background .15s;
}
.rep-tile:hover { border-color: var(--border-strong); background: var(--surface-2); }
.rep-tile:focus-visible { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring); }
.rep-tile .avatar { width: 1.875rem; height: 1.875rem; font-size: .72rem; }
.rep-tile-txt { display: grid; min-width: 0; line-height: 1.25; }
.rep-tile-txt strong {
  font-size: .9rem; font-weight: 600; letter-spacing: -.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rep-tile-txt small { color: var(--faint); font-size: .74rem; }
.rep-tile-count { font-size: 1.2rem; font-weight: 700; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.rep-tile.is-quiet { opacity: .62; }   /* recuado, mas o nome ainda tem de ser legível */
.rep-tile.is-quiet .rep-tile-count { color: var(--faint); font-weight: 600; }

/* distribuição do funil: uma barra de 4px vale mais que seis números */
.rep-bar {
  grid-column: 1 / -1; display: flex; height: 4px; gap: 1px;
  border-radius: 999px; overflow: hidden; background: var(--surface-2);
}
.bar-novo         { background: var(--info); }
.bar-sem-resposta { background: var(--faint); }
.bar-negociando   { background: var(--purple); }
.bar-ganho        { background: var(--success); }
.bar-perdido      { background: var(--danger); }
.bar-inadimplente { background: var(--warning); }

/* quem ficou sem lead no recorte: uma linha, não uma caixa por pessoa */
.rep-rest {
  display: flex; align-items: center; flex-wrap: wrap; gap: .3rem .45rem;
  margin: 0; font-size: .82rem; color: var(--faint);
}
.rep-rest a { color: var(--muted); }
.rep-rest a:hover { color: var(--primary); }
.rep-rest a:not(:last-child)::after { content: ','; color: var(--faint); }

/* ---------- Metas: meta em % e linha clicável ---------- */
.rep-link { color: var(--text); }
.rep-link:hover strong { color: var(--primary); }
tr[data-id] { cursor: pointer; }
tr[data-id]:hover { background: var(--surface-2); }
tr[data-id] input { cursor: auto; }

/* campo de porcentagem: o "%" mora colado no input, sem virar coluna extra */
.pct-field { display: inline-flex; align-items: center; gap: .3rem; }
.pct-field input { width: 4.25rem; text-align: right; }
.pct-field span { color: var(--faint); font-size: .85rem; }
.back-link {
  display: inline-flex; align-items: center; gap: .25rem; margin-top: .35rem;
  font-size: .82rem; color: var(--muted);
}
.back-link:hover { color: var(--primary); }

/* ---------- Detalhe do lead: ação em cima, gestão isolada no fim ---------- */
.lead-phone-big { font-size: 1.3rem; font-weight: 700; letter-spacing: -.01em; }

@media (max-width: 639px) {
  /* Falar com o cliente é o que se faz ao abrir o lead: WhatsApp e Ligar
     dividem a largura em alvos de 44px, e Copiar vira ícone no fim da fileira.
     Antes eram três botões pequenos soltos, do tamanho do texto de cada um. */
  .lead-detail .phone-actions { flex-wrap: nowrap; gap: var(--sp-2); }
  .lead-detail .phone-actions .btn { min-height: 2.75rem; }
  .lead-detail .phone-actions .btn:not(.btn-icone-celular) { flex: 1 1 0; }
  .lead-detail .phone-actions .btn-icone-celular { border: 1px solid var(--border); }

  /* Status em grade de duas colunas, todas as opções do mesmo tamanho. Como
     pílulas soltas elas quebravam em três fileiras tortas (duas, duas e duas
     de larguras diferentes), e a escolha mais importante da tela parecia uma
     nuvem de etiquetas. */
  .status-picker { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); }
  .status-picker button {
    min-height: 2.75rem; padding: .5rem .75rem; justify-content: flex-start;
    border-radius: var(--radius-sm); font-size: .88rem;
  }

  /* A etiqueta do status ao lado do telefone não cabia nessa largura, caía numa
     linha só dela — e repetia o status que a grade logo abaixo já mostra
     marcado. No celular ela sai; no desktop fica, no canto, onde não custa. */
  .lead-detail .top > div:last-child:has(> .badge) { display: none; }

  /* Histórico: data numa linha, o que mudou na de baixo. Lado a lado, a coluna
     de 105px da data espremia a transição e "por Carla Mendes" quebrava torto. */
  .timeline li { flex-wrap: wrap; row-gap: .15rem; }
  .timeline .when { flex-basis: 100%; min-width: 0; font-size: .78rem; }
}

/* Detalhe estreito — o celular com Tamanho 125% ou 150%. Os limites saem de
   medidas em rem, que valem para qualquer escala: os dois status mais longos
   ("Contrato fechado" tem 9.8rem) lado a lado já passam do espaço abaixo de
   18rem, e WhatsApp + Ligar + copiar pedem 14.5rem, com folga até 15rem.
   Abaixo disso o texto estourava o botão e o copiar saía pela direita do
   modal. Em 125% num celular de 375px o detalhe tem ~17rem; em 150%, ~13.5rem.
   Só com escala: em 100% o detalhe é exatamente o de antes. */
.lead-detail { container: detalhe / inline-size; }
@container detalhe (max-width: 18rem) {
  html:is([data-escala="125"], [data-escala="150"]) .status-picker { grid-template-columns: minmax(0, 1fr); }
}
@container detalhe (max-width: 15rem) {
  html:is([data-escala="125"], [data-escala="150"]) .lead-detail .phone-actions { flex-wrap: wrap; }
  html:is([data-escala="125"], [data-escala="150"]) .lead-detail .phone-actions > .btn-whatsapp { flex: 1 0 100%; }
}
.lead-detail .kv { gap: .55rem 1rem; }
/* Rótulo em caixa normal, não em caixa alta: aqui são sete ou oito pares
   empilhados, e sete linhas gritando "ENVIADO POR", "ORIGEM", "LOCAL" pesavam
   mais que os próprios dados. Quem abre o bloco é o título da seção. */
.lead-detail .kv dt { font-size: .85rem; color: var(--muted); }
.kv-bot { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }

.admin-box {
  margin-top: 1.4rem; padding: .2rem 1rem 1rem; border: 1px solid var(--border);
  border-radius: var(--radius); background: var(--bg);
}
.admin-row { display: flex; align-items: center; gap: .55rem; flex-wrap: wrap; }
/* ellipsis não funciona em item de flex sem min-width: 0 — o nome do fluxo
   crescia e a página inteira ganhava rolagem lateral (375px medindo 486px) */
.rep-flow-name { min-width: 0; flex: 1 1 0; }
.admin-row select { width: auto; flex: 1 1 11.875rem; }
.admin-actions { display: flex; gap: .4rem; flex-wrap: wrap; margin-top: .7rem; }
.btn-ghost.danger { color: var(--danger); }
.btn-ghost.danger:hover { background: var(--danger-soft); color: var(--danger); }

/* o modal segue o tema, sem a tela ficar mais clara por trás */
.modal { border: 1px solid var(--border-strong); }


.toggle-row { align-items: flex-start; gap: .7rem; }
.toggle-row input { margin-top: .2rem; }
.toggle-row small { display: block; margin-top: .25rem; font-size: .82rem; line-height: 1.45; }

.field-label { font-size: .85rem; font-weight: 600; color: var(--muted); margin-bottom: .3rem; }

.rep-flow-list { display: grid; }
.rep-flow-row {
  display: flex; align-items: center; justify-content: space-between; gap: .75rem; flex-wrap: wrap;
  padding: .55rem 0; border-top: 1px solid var(--border);
}
.rep-flow-row:first-child { border-top: none; }
.rep-flow-name { font-size: .9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------- Configuração: composição da mensagem + celular ---------- */
.compose-card .card-header { align-items: flex-start; }
.compose-grid { display: grid; gap: 1.5rem; min-width: 0; }
/* o celular só fica ao lado quando sobra largura de verdade: com a barra lateral
   de 264px, abaixo de 1200px o editor ficaria com ~220px e viraria um filete */
@media (min-width: 1200px) {
  .compose-grid { grid-template-columns: minmax(0, 1fr) auto; align-items: start; }
}
/* empilhado, o celular fica centralizado em vez de colado à esquerda */
@media (max-width: 1199px) {
  .compose-preview .phone { margin-inline: auto; }
}
.compose-editor { min-width: 0; display: flex; flex-direction: column; }
.compose-editor textarea { font-family: var(--mono); font-size: .84rem; line-height: 1.6; resize: vertical; }
.compose-preview { min-width: 0; }

.chip-row { display: flex; flex-wrap: wrap; gap: .35rem; }
.chip {
  border: 1px solid var(--border); background: var(--surface-2); color: var(--muted);
  border-radius: 999px; padding: .3rem .65rem; font: inherit; font-size: .78rem; cursor: pointer;
  transition: border-color .15s, color .15s;
}
.chip:hover { border-color: var(--primary); color: var(--text); }

.check-list { display: grid; gap: .4rem; }
.check-list .switch { font-size: .88rem; }

/* `stretch`, não `start`: com `start` cada cartão ficava com a altura do próprio
   texto e a fileira terminava em degraus. Lado a lado, três caixas de alturas
   diferentes leem como desalinho, não como hierarquia — o conteúdo continua
   alinhado ao topo, mas a moldura fecha na mesma linha. */
/* minmax(0, 1fr) e não o `1fr` implícito: a trilha automática era dimensionada
   pelo min-content dos cartões, e um nome de fluxo longo empurrava a página
   inteira para fora da tela no celular. */
.settings-row { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1rem; align-items: stretch; margin-top: 1rem; }
/* `.card + .card { margin-top: 1rem }` existe para cartões EMPILHADOS. Dentro de
   uma grade quem separa é o `gap`, e aquela margem sobrando empurrava o 2º e o
   3º cartão 16px para baixo: eles esticavam até a mesma base, mas começavam
   mais embaixo e ficavam 16px mais baixos que o primeiro — a fileira terminava
   em degraus. */
.settings-row > .card + .card { margin-top: 0; }
@media (min-width: 1000px) { .settings-row { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* ---------- Celular fake com a conversa do WhatsApp ---------- */
.phone {
  /* largura definida + teto percentual, e não width: min(…, 100%): dentro da
     trilha `auto` do .compose-grid uma porcentagem na largura vira `auto` na
     conta da coluna, e o celular encolheria para o tamanho do conteúdo */
  width: 18.125rem; max-width: 100%; flex: none; padding: 0.6875rem; border-radius: 42px;
  background: linear-gradient(165deg, #4a4a4a 0%, #232323 45%, #121212 100%);
  box-shadow: 0 26px 60px rgba(0, 0, 0, .55), inset 0 0 0 1px rgba(255, 255, 255, .07);
}
.phone-screen {
  position: relative; height: 33.75rem; border-radius: 32px; overflow: hidden;
  background: #0b141a; display: grid; grid-template-rows: auto auto 1fr auto;
  color: #e9edef; font-size: .8rem;
}
.phone-island {
  position: absolute; top: 0.5rem; left: 50%; transform: translateX(-50%);
  width: 5.125rem; height: 1.375rem; border-radius: 999px; background: #000; z-index: 3;
}
.phone-status {
  display: flex; align-items: center; justify-content: space-between;
  padding: .55rem .95rem .3rem; font-size: .7rem; font-weight: 600; color: #e9edef;
}
.phone-status-icons { display: inline-flex; align-items: center; gap: .2rem; opacity: .85; }

.wa-header {
  display: flex; align-items: center; gap: .5rem; padding: .45rem .6rem;
  background: #1f2c34; border-bottom: 1px solid rgba(255, 255, 255, .06);
}
.wa-avatar {
  width: 1.75rem; height: 1.75rem; border-radius: 50%; display: grid; place-items: center;
  background: #4493f8; color: #0b141a; font-weight: 800; font-size: .72rem; flex: none;
}
.wa-who { display: grid; line-height: 1.15; flex: 1; min-width: 0; }
.wa-who strong { font-size: .82rem; font-weight: 600; }
.wa-who small { font-size: .66rem; color: #8696a0; }
.wa-header-icons { display: inline-flex; gap: .55rem; color: #8696a0; }

.wa-body {
  padding: .7rem .6rem; overflow: auto; background-color: #0b141a;
  background-image:
    radial-gradient(circle at 15% 20%, rgba(255,255,255,.022) 0 2px, transparent 2px),
    radial-gradient(circle at 65% 55%, rgba(255,255,255,.02) 0 2px, transparent 2px),
    radial-gradient(circle at 35% 85%, rgba(255,255,255,.018) 0 2px, transparent 2px);
  background-size: 7.5rem 7.5rem;
}
.wa-day {
  width: fit-content; margin: 0 auto .7rem; padding: .18rem .55rem; border-radius: 6px;
  background: #182229; color: #8696a0; font-size: .62rem; font-weight: 600; letter-spacing: .05em;
}
.wa-bubble {
  max-width: 88%; background: #202c33; color: #e9edef;
  padding: .45rem .6rem .35rem; border-radius: 0 8px 8px 8px;
  font-size: .78rem; line-height: 1.45; white-space: pre-wrap; overflow-wrap: anywhere;
  box-shadow: 0 1px 1px rgba(0, 0, 0, .35);
}
.wa-bubble strong { font-weight: 700; }
.wa-bubble code { background: rgba(255,255,255,.08); border-radius: 3px; padding: 0 .2rem; font-size: .95em; }
.wa-bubble .muted { color: #8696a0; }
.wa-time { display: block; text-align: right; margin-top: .15rem; font-size: .62rem; color: #8696a0; }

.wa-input {
  display: flex; align-items: center; gap: .4rem; padding: .5rem .6rem .8rem; background: #0b141a;
}
.wa-input-box {
  flex: 1; background: #1f2c34; color: #8696a0; border-radius: 999px;
  padding: .4rem .7rem; font-size: .74rem;
}
.wa-send {
  width: 1.875rem; height: 1.875rem; border-radius: 50%; background: #00a884; color: #0b141a;
  display: grid; place-items: center; flex: none;
}

/* =============================================================================
   Métricas no celular
   Fica no fim do arquivo de propósito: os "Ajustes do layout minimalista" acima
   redefinem .kpis e .segmented com a mesma especificidade, então uma media query
   colocada antes deles perderia por ordem de cascata.
   ============================================================================= */
@media (max-width: 639px) {
  /* dois por linha: cinco KPIs empilhados enchiam a tela antes do primeiro gráfico */
  .kpis { grid-template-columns: 1fr 1fr; }
  /* com escala, um por linha: "R$ 319,70" em letra maior não cabe em meia tela
     e invadia o KPI vizinho */
  html:is([data-escala="125"], [data-escala="150"]) .kpis { grid-template-columns: minmax(0, 1fr); }
  .kpi { padding: .75rem .8rem; }
  .kpi .label { white-space: normal; }
  .kpi .value { font-size: 1.4rem; margin-top: .35rem; }
  .kpi .sub { font-size: .72rem; margin-top: .2rem; }

  .chart-box { height: 14.375rem; }
  .chart-box.short { height: 12.8125rem; }
  .chart-box.tall { height: 18.125rem; }

  /* período: cinco opções não cabem lado a lado em 375px */
  .segmented { display: grid; grid-template-columns: repeat(3, 1fr); width: 100%; }
  .segmented button { padding: .5rem .4rem; font-size: .82rem; }
}
/* =============================================================================
   Cadastro público — a ficha que o cliente preenche pelo link (cadastro.html)
   e a tela de Cadastros dentro do app.

   A página pública usa a mesma folha do app de propósito: é a mesma marca, e
   manter dois arquivos de tema seria garantir que um dos dois envelhece.
   ============================================================================= */

/* ---------- Casca da página pública ---------- */
.cadastro-page {
  min-height: 100vh; display: flex; flex-direction: column;
  /* Uma medida só para o topo e para o miolo: é ela que faz a borda do banner
     cair no mesmo pixel da borda dos cartões, dos dois lados. Medida, não cor. */
  --cad-w: 48.75rem;
}
/* Quem pinta este topo é o js/cadastro.js, depois de saber se o link é de um
   representante (wordmark USECLUBE) ou de um convênio (o banner da parceria).
   Os 72px reservados aqui são a altura da wordmark. O banner é mais alto e não
   dá para reservá-lo — só a resposta do servidor diz qual dos dois é. */
.cadastro-topo {
  display: flex; align-items: center; justify-content: center;
  min-height: 4.5rem; padding: 1.25rem 1rem .75rem;
}
.cadastro-topo .logo-useclube { height: 1.875rem; }

/* O banner da parceria, no lugar dos dois selos. A arte tem degradê próprio e é
   opaca: não se adapta ao tema, e quem a separa do fundo da página é a borda —
   mesmo argumento que valia para os selos.

   Duas artes, mesma composição em recortes diferentes. A larga (1920x300) é uma
   tarja e só serve de 640px para cima. A alta (1280x640) é a do celular e tem
   céu e chão sobrando: o aspect-ratio de 1280/500 apara esse vazio e devolve
   ~50px da primeira tela. O desenho (logos, aperto de mãos, selo verde) vive
   entre 30% e 70% da altura, então o corte nunca o encosta — quem reexportar a
   arte com o desenho mais perto da borda quebra isso. */
.cadastro-topo.tem-banner {
  display: block; width: 100%; max-width: var(--cad-w);
  margin-inline: auto; padding: 1.25rem 1rem .75rem;
}
.cadastro-banner { display: block; width: 100%; }
/* As duas proporções vêm do canal, por custom property no <picture> (ver MARCAS
   em js/canais.js): cada parceria manda a arte que tem, e a tarja da Bruscon
   (6.4:1) não cabe no mesmo número da fileira de quatro marcas das malhas (3:1).
   Os valores no var() são só a rede para um canal sem desenho. */
.cadastro-banner img {
  display: block; width: 100%; height: auto;
  aspect-ratio: var(--ar-alto, 1280 / 500); object-fit: cover; object-position: center;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-2);
}
/* Esta condição tem de ser IDÊNTICA à do <source> em js/cadastro.js: é ela que
   diz qual arte o navegador baixou. Discordando, ele reserva a proporção errada
   e o topo salta quando a imagem chega. */
@media (min-width: 640px), (max-height: 480px) {
  .cadastro-banner img { aspect-ratio: var(--ar-largo, 1920 / 300); border-radius: var(--radius); }
}

.cadastro-main { flex: 1; width: 100%; max-width: var(--cad-w); margin: 0 auto; padding: 1rem 1rem 2.5rem; }
.cadastro-rodape { text-align: center; padding: 0 1rem 2rem; }
.cadastro-carregando { text-align: center; padding: 3.5rem 1rem; }

/* Desktop: a página passa de 780px para 1040px e a largura ganha vai TODA para
   dentro dos cartões, redistribuindo os campos numa grade de 12 colunas. Nenhum
   input passa de 465px — campo esticado é justamente o que faz um formulário
   parecer quebrado, e 1040px é o teto em que isso ainda é verdade.

   1000px não é número novo: é o mesmo ponto de quebra de .settings-row e
   .br-colunas. Abaixo dele esta folha fica igual à de antes desta mudança. */
@media (min-width: 1000px) {
  .cadastro-page { --cad-w: 65rem; }
  .cadastro-topo.tem-banner { padding: 1.5rem 1.25rem .75rem; }
  .cadastro-main { padding: 1.5rem 1.25rem 3rem; }
  .form-secao { padding: 1.6rem 1.75rem; }

  /* texto corrido não passa de 62ch: sem teto, o parágrafo de boas-vindas e o
     subtítulo do Titular viram linhas de 944px com ~115 caracteres */
  .form-secao > p, .secao-sub { max-width: 62ch; }
  /* a faixa do desconto vira pílula, em vez de barra com 400px de verde vazio */
  .form-secao > p.vantagem { width: fit-content; max-width: 100%; }

  /* escopado: .anexo-lista também é usada no modal da ficha do app
     (js/pages/cadastros.js) e lá duas colunas truncariam o nome do arquivo */
  .cadastro-page .anexo-lista { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* inline-flex não centraliza com margin auto; flex (nível de bloco) sim */
  .cadastro-page .btn-enviar { display: flex; max-width: 24rem; margin-inline: auto; }

  /* A grade das seções. row-gap é ZERO de propósito: o ritmo vertical desta
     folha vem do .field { margin-bottom }, e um row-gap aqui dobraria. */
  .secao-grade { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 0 .9rem; }
  /* os .form-row se dissolvem e os campos deles sobem para a grade, sem o JS
     precisar reagrupar nada — a ordem do DOM já é a ordem visual desejada.
     ARMADILHA: com display:contents, qualquer fundo, borda ou padding que um dia
     seja posto em .form-row some aqui, sem erro e sem aviso. */
  .secao-grade > .form-row { display: contents; }
  /* rede de segurança: :where() tem especificidade ZERO, então qualquer .grade-N
     ganha dela — e um campo que esqueceram de marcar vira linha inteira em vez
     de uma tira de 65px */
  :where(.secao-grade > *, .secao-grade > .form-row > *) { grid-column: span 12; }
  .secao-grade .grade-2 { grid-column: span 2; }
  .secao-grade .grade-3 { grid-column: span 3; }
  .secao-grade .grade-4 { grid-column: span 4; }
  .secao-grade .grade-5 { grid-column: span 5; }
  .secao-grade .grade-6 { grid-column: span 6; }
}

/* ---------- Seção numerada ---------- */
.form-secao {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 1.35rem; margin-bottom: 1rem;
}
.secao-head { display: flex; align-items: flex-start; gap: .7rem; margin-bottom: 1.1rem; }
.secao-num {
  flex: none; width: 1.625rem; height: 1.625rem; border-radius: 8px; display: grid; place-items: center;
  background: var(--primary); color: var(--primary-ink); font-weight: 700; font-size: .85rem;
}
.secao-head h2 { margin: 0; font-size: 1.05rem; letter-spacing: -.01em; }
.secao-sub { margin: .3rem 0 0; }
.boasvindas { margin-bottom: .5rem; }
/* A vantagem do convênio dita em uma linha, ainda na primeira seção: é o motivo
   de a pessoa ter clicado no link que o condomínio mandou, e ela precisa
   reencontrá-lo antes de decidir gastar cinco minutos preenchendo ficha. */
.vantagem {
  display: flex; align-items: center; gap: .5rem; margin: 0 0 .6rem;
  padding: .55rem .7rem; border-radius: var(--radius-sm);
  background: var(--success-soft); color: var(--success); font-size: .9rem;
}
.vantagem .ico { flex: none; }

/* asterisco de obrigatório: some para leitor de tela (aria-required já diz) */
.req { margin-left: .15rem; color: var(--danger); font-weight: 700; }

.erro-campo { font-size: .8rem; color: var(--danger); }
.erro-campo:empty { display: none; }
.field.invalido input, .field.invalido select { border-color: var(--danger); }
.field.invalido label { color: var(--danger); }

/* ---------- Dependentes ---------- */
.dep-card {
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 1rem; margin-bottom: .75rem;
}
.dep-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: .85rem; }
.link-btn.danger { color: var(--danger); }
.link-btn.danger:hover { filter: brightness(1.15); }

/* ---------- Anexos ---------- */
.dropzone {
  position: relative;
  display: flex; align-items: center; gap: .85rem; padding: 1.15rem; cursor: pointer;
  background: var(--surface-2); border: 1.5px dashed var(--border-strong); border-radius: var(--radius-sm);
  transition: border-color .15s, background .15s;
}
.dropzone:hover, .dropzone.over { border-color: var(--primary); background: var(--primary-soft); }
/* o input de arquivo é visualmente oculto (.campo-oculto): sem isto, quem navega
   por teclado chega nele e não tem como saber onde está */
.dropzone:focus-within { border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring); }
.dz-ico {
  flex: none; width: 2.5rem; height: 2.5rem; border-radius: 10px; display: grid; place-items: center;
  background: var(--gray-soft); color: var(--muted);
}
.dz-txt { display: flex; flex-direction: column; gap: .1rem; }

/* minmax(0, 1fr) e não `auto`: sem o mínimo zero a trilha era dimensionada pelo
   nome do arquivo (que é longo e sem espaços) e o modal ganhava rolagem lateral */
.anexo-lista { display: grid; grid-template-columns: minmax(0, 1fr); gap: .5rem; margin-top: .8rem; }
.anexo-item {
  display: flex; align-items: flex-start; gap: .6rem; padding: .65rem .7rem;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.anexo-ico {
  flex: none; width: 1.875rem; height: 1.875rem; border-radius: 8px; display: grid; place-items: center;
  background: var(--gray-soft); color: var(--muted);
}
.anexo-meta { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: .15rem; }
.anexo-nome { font-weight: 600; font-size: .9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.anexo-item .anexo-desc { margin-top: .35rem; padding: .38rem .55rem; }

.btn-enviar { margin-top: .5rem; padding: .85rem; font-size: 1rem; }

/* ---------- Fim de linha: link inválido ou cadastro enviado ---------- */
/* telaErro() e telaPronto() substituem o #root inteiro, e #root É a
   .cadastro-main — sem teto próprio, "Cadastro enviado" viraria um cartão de
   1040px com três linhas de texto perdidas no meio. */
.cadastro-aviso {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 2.25rem 1.5rem; text-align: center;
  max-width: 34rem; margin-inline: auto;
}
.cadastro-aviso h1 { margin-bottom: .5rem; font-size: 1.3rem; }
.cadastro-aviso .alert { margin-top: 1rem; }
.aviso-icone {
  display: inline-grid; place-items: center; width: 3.25rem; height: 3.25rem;
  border-radius: 14px; margin-bottom: 1rem;
}
.aviso-icone.ok { background: var(--success-soft); color: var(--success); }
.aviso-icone.erro { background: var(--danger-soft); color: var(--danger); }

/* ---------- Tela de Cadastros no app ---------- */
.filterbar > select { flex: 1 1 40%; min-width: 0; }

/* a busca logo abaixo encostava no cartão (0px), e parecia parte dele */
.link-card { margin-bottom: var(--gap-bloco); }
.link-card .link-url { display: flex; gap: .5rem; margin: .85rem 0 .65rem; }
.link-card .link-url input { font-family: var(--mono); font-size: .85rem; }
.link-acoes { display: flex; gap: .5rem; flex-wrap: wrap; }
.link-card.is-off { opacity: .75; }
.link-card.is-off .link-url input { color: var(--muted); text-decoration: line-through; }

@media (max-width: 639px) {
  /* Quatro botões soltos quebravam em fileiras de tamanhos diferentes. Em
     grade: o WhatsApp — que é o que se faz com o link — na largura toda, e os
     três de manutenção embaixo, do mesmo tamanho. */
  .link-acoes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-2); }
  .link-acoes .btn { min-height: 2.625rem; justify-content: center; padding-inline: .4rem; gap: .3rem; }
  .link-acoes .btn-whatsapp { grid-column: 1 / -1; min-height: 2.75rem; }
  .link-card > p { margin-bottom: 0; }
}

/* Cartão do link estreito (celular com Tamanho 125% ou 150%): os três botões de
   manutenção pedem ~15.7rem lado a lado ("Gerar outro" sozinho tem 4.9rem) e
   estouravam; viram dois por linha, com o último na largura toda. O endereço,
   que ficava com 6 letras visíveis ao lado do Copiar, ganha a linha inteira.
   Só com escala: em 100% o cartão é exatamente o de antes. */
.link-card { container: link / inline-size; }
@container link (max-width: 16rem) {
  html:is([data-escala="125"], [data-escala="150"]) .link-acoes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  html:is([data-escala="125"], [data-escala="150"]) .link-acoes .btn:last-child { grid-column: 1 / -1; }
  html:is([data-escala="125"], [data-escala="150"]) .link-card .link-url { flex-wrap: wrap; }
  html:is([data-escala="125"], [data-escala="150"]) .link-card .link-url input { flex: 1 0 100%; }
  html:is([data-escala="125"], [data-escala="150"]) .link-card .link-url .btn { flex: 1 1 auto; justify-content: center; }
}

/* Lista de fichas: uma por LINHA INTEIRA, não em grade de colunas.
   A ficha tem sete informações de relance; numa coluna de 250px elas viram sete
   linhas empilhadas e o nome trunca no meio. Também não herda `.lead-card` —
   aquela é uma grade de duas colunas feita para [ícone] [nome], e outros filhos
   caem nas células erradas. */
.cad-lista { display: flex; flex-direction: column; gap: var(--gap-lista); }
.cad-card {
  display: flex; align-items: center; gap: .85rem;
  padding: .75rem 1rem; cursor: pointer;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  transition: border-color .15s, box-shadow .15s, transform .1s;
}
.cad-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); transform: translateY(-1px); }
.cad-card:focus-visible { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring); }

.cad-ico {
  flex: none; width: 2.125rem; height: 2.125rem; border-radius: 10px; display: grid; place-items: center;
  background: var(--gray-soft); color: var(--faint);
}
.cad-card.is-new .cad-ico { background: var(--info-soft); color: var(--info); }

/* base 0, não auto: com `auto` o item pede a largura do próprio texto e, quando
   o cartão quebra linha no celular, ele não caberia ao lado do ícone e desceria
   sozinho. Com base 0 ele nunca exige espaço — só cresce para ocupar o que sobra.
   min-width:0 é o que deixa o ellipsis funcionar dentro de um item flex. */
.cad-id { flex: 1 1 0; min-width: 0; }
.cad-nome {
  font-size: .95rem; font-weight: 600; line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cad-sub {
  margin-top: .1rem; font-size: .82rem; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cad-sub .sep { margin: 0 .35rem; color: var(--faint); }

/* `0 1 auto` e não `none`: com shrink 0 o badge do nome do representante nunca
   encolhia e empurrava o cartão para fora da tela */
.cad-tags { flex: 0 1 auto; min-width: 0; display: flex; gap: .35rem; align-items: center; }
.cad-fim { flex: none; display: flex; gap: .6rem; align-items: center; }
.cad-quando { font-size: .76rem; color: var(--faint); white-space: nowrap; text-align: right; min-width: 4.5rem; }

/* Quebra de linha explícita para o celular. Só existe porque calcular a base do
   .cad-id para "encher a primeira linha" depende do gap e da largura do ícone —
   erra por um pixel e o ícone fica sozinho numa linha. Um item de 100% e altura
   zero empurra o que vem depois para a linha seguinte, e ponto. */
.cad-quebra { display: none; }

@media (max-width: 760px) {
  /* linha 1 = ícone + identificação · linha 2 = etiquetas à esquerda,
     situação e hora à direita */
  .cad-card { flex-wrap: wrap; row-gap: .6rem; padding: .8rem .85rem; }
  .cad-quebra { display: block; flex: 1 0 100%; height: 0; margin: 0; }
  .cad-fim { margin-left: auto; }
  .cad-tags { flex-wrap: wrap; }
  .cad-quando { min-width: 0; }
  /* Documento e telefone numa linha (sem quebrar: ela herda o nowrap e corta
     com reticências), cidade na de baixo. Quebrando livre, a cidade caía na
     segunda linha começando pelo "·" — um ponto solto no começo da linha, que
     parecia erro. */
  .cad-sub .sep-cidade { display: none; }
  .cad-sub .cad-cidade { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

.cad-detalhe .top { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.cad-detalhe .phone-actions { display: flex; gap: .4rem; flex-wrap: wrap; margin: .8rem 0 .25rem; }
.cad-detalhe .endereco { line-height: 1.65; }

.dados { display: grid; grid-template-columns: 1fr; }
.dado {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding: .45rem 0; border-bottom: 1px solid var(--border);
}
.dado-rot { flex: none; font-size: .85rem; color: var(--muted); }
.dado-val { font-size: .9rem; text-align: right; overflow-wrap: anywhere; }

@media (min-width: 600px) {
  .dados { grid-template-columns: 1fr 1fr; column-gap: 1.75rem; }
}

@media (max-width: 640px) {
  .cadastro-main { padding: .75rem .75rem 2.5rem; }
  .cadastro-topo { min-height: 3.75rem; padding: 1rem .75rem .5rem; }
  /* .cadastro-topo.tem-banner é (0,2,0) e vence a regra de cima (0,1,0) mesmo
     estando fora desta media query — media query não soma especificidade. Por
     isso o padding de celular precisa ser redeclarado aqui, com a classe. */
  .cadastro-topo.tem-banner { padding: 1rem .75rem .5rem; }
  .form-secao { padding: 1rem; border-radius: var(--radius-sm); }
  /* o ícone ao lado do texto espreme as duas linhas em 375px */
  .dropzone { flex-direction: column; text-align: center; }
  .dz-txt { align-items: center; }
}

/* ---------------------------------------------------------------------------
   Ficha de adesão: copiar e imprimir (#/cadastros)

   A ficha existe para adiantar a digitação do representante, e o último passo
   dela é sair da tela — para o sistema da operadora, por cópia, ou para o papel
   que acompanha o contrato.
--------------------------------------------------------------------------- */

/* Valor clicável. O alvo é o próprio texto, então o realce precisa transbordar
   um pouco a caixa; a margem negativa devolve o espaço para não mexer no layout. */
[data-copiar] {
  cursor: pointer;
  border-radius: 5px;
  padding: .1rem .25rem;
  margin: -.1rem -.25rem;
  transition: background-color .12s ease;
}
[data-copiar]:hover,
[data-copiar]:focus-visible { background-color: rgba(127, 127, 127, .16); }
[data-copiar]:active { background-color: rgba(127, 127, 127, .28); }

/* ---------------------------------------------------------------------------
   Impressão

   Em vez de gerar PDF por biblioteca — que traria CDN e build para um projeto
   que não tem nenhum dos dois —, o botão chama window.print() e é esta folha
   que decide o que vai para o papel.

   `imprimindo-ficha` no body some com a aplicação inteira e o modal deixa de
   ser sobreposição para virar documento. As regras só existem dentro deste
   @media, então esquecer a classe ligada não estraga nada na tela.
--------------------------------------------------------------------------- */
@media print {
  @page { margin: 1.5cm; }

  /* O papel sai sempre no tamanho normal: a escala é conforto de tela, e a
     ficha em 150% transbordaria a folha A4. */
  html[data-escala] { font-size: 100%; --escala: 1; }

  body.imprimindo-ficha > *:not(.modal-overlay) { display: none !important; }

  body.imprimindo-ficha .modal-overlay {
    position: static; display: block; opacity: 1;
    padding: 0; background: none; overflow: visible;
  }
  body.imprimindo-ficha .modal {
    position: static; width: auto; max-width: none; max-height: none;
    border: 0; border-radius: 0; box-shadow: none;
  }
  body.imprimindo-ficha .modal-body { max-height: none; overflow: visible; padding: 0; }
  body.imprimindo-ficha .modal-header { padding: 0 0 .6rem; border-bottom: 1px solid #000; }

  /* Nada de interativo no papel. A anotação interna e a situação ficam de fora
     de propósito: a folha acompanha o contrato, e nota da equipe não é do cliente. */
  body.imprimindo-ficha .modal-close,
  body.imprimindo-ficha .modal-footer,
  body.imprimindo-ficha .phone-actions,
  body.imprimindo-ficha .nao-imprime,
  body.imprimindo-ficha .anexo-item .btn { display: none !important; }

  /* Tinta é cara e fundo colorido não imprime bem: tudo vira preto no branco. */
  body.imprimindo-ficha .modal,
  body.imprimindo-ficha .modal * { color: #000 !important; background: none !important; }
  body.imprimindo-ficha [data-copiar] { padding: 0; margin: 0; }
  body.imprimindo-ficha .section-title { border-bottom: 1px solid #bbb; padding-bottom: .15rem; }

  body.imprimindo-ficha .dado,
  body.imprimindo-ficha .anexo-item,
  body.imprimindo-ficha tr { break-inside: avoid; }
}

/* ---------- Materiais: pastas e arquivos ---------- */
/* Mesma linguagem do cartão de cadastro: linha inteira, varrível de cima a
   baixo. Pasta é alvo grande de toque porque no celular ela é o passo 1. */
.pasta-grid { display: grid; gap: var(--gap-lista); grid-template-columns: repeat(auto-fill, minmax(min(16.25rem, 100%), 1fr)); }
.pasta-card {
  display: flex; align-items: center; gap: .8rem; text-decoration: none; color: inherit;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: .9rem 1rem; transition: border-color .15s, box-shadow .15s, transform .1s;
}
.pasta-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); transform: translateY(-1px); }
.pasta-card:focus-visible { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring); }
.pasta-ico {
  flex: none; width: 2.375rem; height: 2.375rem; border-radius: 10px; display: grid; place-items: center;
  background: var(--info-soft); color: var(--info);
}
.pasta-id { flex: 1 1 0; min-width: 0; }
.pasta-nome { font-weight: 600; font-size: .96rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pasta-desc {
  margin-top: .1rem; font-size: .8rem; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pasta-qtd { flex: none; font-size: .76rem; color: var(--faint); white-space: nowrap; }

.mat-lista { display: flex; flex-direction: column; gap: var(--gap-lista); }
.mat-card {
  display: flex; align-items: center; gap: .8rem;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: .7rem .95rem;
}
.mat-ico {
  flex: none; width: 2rem; height: 2rem; border-radius: 9px; display: grid; place-items: center;
  background: var(--gray-soft); color: var(--faint);
}
.mat-id { flex: 1 1 0; min-width: 0; }
.mat-nome { font-weight: 600; font-size: .92rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mat-sub {
  margin-top: .1rem; font-size: .79rem; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mat-sub .sep { margin: 0 .35rem; color: var(--faint); }
.mat-acoes { flex: none; display: flex; gap: .35rem; }

@media (max-width: 620px) {
  /* no celular o nome fica em cima e as ações embaixo, sem espremer o botão */
  .mat-card { flex-wrap: wrap; row-gap: .55rem; }
  .mat-id { flex: 1 1 calc(100% - 2.8rem); }
  .mat-acoes { margin-left: auto; }
  .mat-sub { white-space: normal; }
}

/* ---------- Meu desempenho ---------- */
.secao-mat { margin: var(--sp-6) 0 var(--sp-3); }
.secao-mat:first-child { margin-top: 0; }

/* Barras dos últimos meses. SVG seria exagero: são 6 colunas e nenhuma escala
   que precise de eixo — altura relativa ao maior mês já conta a história. */
.mes-grafico {
  display: flex; align-items: flex-end; gap: .5rem; height: 8.25rem;
  padding: .9rem 1rem; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius);
}
/* O rótulo sai do fluxo e a barra ganha a pista inteira. Antes os dois dividiam
   a altura da coluna, então o `height: N%` inline da barra resolvia contra um
   espaço menor que o previsto e a barra mais alta aparecia comprimida — o
   gráfico mentia na proporção entre os meses. */
.mes-col {
  flex: 1 1 0; display: flex; flex-direction: column; justify-content: flex-end;
  height: 100%; position: relative; padding-bottom: 1.35rem;
}
/* Duas barras por mês, lado a lado, na mesma escala. Já foi uma barra só com os
   fechados pintados por dentro — mas desde que o contrato conta no mês em que
   FECHOU, os fechados de um mês podem passar dos recebidos, e a barra inteira
   verde parecia "converteu tudo". */
.mes-par { display: flex; align-items: flex-end; gap: 3px; height: 100%; }
.mes-barra {
  flex: 1 1 0; background: var(--info-soft); border-radius: 5px 5px 2px 2px;
}
.mes-barra.ganho { background: var(--success, var(--primary)); }
.mes-rotulo { position: absolute; left: 0; right: 0; bottom: 0; text-align: center; font-size: .7rem; color: var(--faint); text-transform: capitalize; }
.legenda-mes { display: flex; align-items: center; gap: .4rem; margin-top: .5rem; }
.legenda-mes .amostra { width: 0.625rem; height: 0.625rem; border-radius: 3px; display: inline-block; }
.legenda-mes .amostra-recebido { background: var(--info-soft); }
.legenda-mes .amostra-ganho { background: var(--success, var(--primary)); margin-left: .6rem; }

/* ---------- Avisos ---------- */
/* O número de não lidos. Sempre ancorado ao item de navegação, então o item
   precisa ser posicionado — na barra lateral ele já é flex; a âncora vem daqui. */
#nav a, .sheet-links a, .tabbar a, .tabbar button { position: relative; }
.badge-num {
  min-width: 1.125rem; height: 1.125rem; padding: 0 0.3125rem; border-radius: 999px;
  background: var(--danger); color: #fff;
  font-size: .68rem; font-weight: 700; line-height: 1.125rem; text-align: center;
  font-variant-numeric: tabular-nums;
}
/* Na lateral e na folha o número fecha a linha, à direita do rótulo. */
#nav a .badge-num, .sheet-links a .badge-num { margin-left: auto; }
/* Na barra de abas ele vira bolinha sobre o ícone — não há linha para ocupar. */
.tabbar a .badge-num, .tabbar button .badge-num {
  position: absolute; top: .18rem; left: 50%; margin-left: .25rem;
  box-shadow: 0 0 0 2px var(--surface);
}

.aviso-form { display: grid; gap: .7rem; margin-bottom: 1.15rem; }
.aviso-form-fim { display: flex; align-items: center; justify-content: space-between; gap: .7rem; flex-wrap: wrap; }

.aviso-lista { display: flex; flex-direction: column; gap: var(--gap-lista); }
.aviso {
  display: flex; gap: .85rem; align-items: flex-start;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: .9rem 1rem;
}
/* Aviso desligado continua visível para o gestor (é ele quem pode religar),
   mas recuado: não compete com o que a equipe está vendo. */
.aviso.inativo { opacity: .6; }
.aviso-avatar {
  flex: none; width: 2.125rem; height: 2.125rem; border-radius: 50%; display: grid; place-items: center;
  background: var(--primary-soft); color: var(--primary);
  font-size: .76rem; font-weight: 700; letter-spacing: .02em;
}
.aviso-corpo { flex: 1 1 0; min-width: 0; }
.aviso-topo { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.aviso-titulo { font-size: .96rem; font-weight: 650; line-height: 1.3; }
.aviso-msg {
  margin: .3rem 0 .45rem; font-size: .88rem; line-height: 1.5; color: var(--text);
  white-space: pre-wrap;            /* o gestor escreve em linhas; respeita */
  overflow-wrap: anywhere;          /* palavra gigante não estoura o cartão */
}
.aviso-pe { display: flex; align-items: center; gap: .3rem; font-size: .76rem; color: var(--faint); flex-wrap: wrap; }
.aviso-autor { display: inline-flex; align-items: center; gap: .25rem; font-weight: 600; }
.aviso-pe .sep { color: var(--border-strong); }
.aviso-acoes { flex: none; display: flex; gap: .35rem; }

@media (max-width: 620px) {
  /* no celular as ações descem para baixo do texto, em vez de espremer a coluna */
  .aviso { flex-wrap: wrap; }
  .aviso-acoes { margin-left: auto; }
}

/* ---------- Campo de arquivo ----------
   O input[type=file] nativo tem ~21px de altura e nunca foi estilizado. Isso
   pesava mais no fechamento de contrato: lá o `change` do campo É o gesto que
   registra a venda (não há botão intermediário), então o alvo mais crítico do
   app era o menor. Vale para todos os campos de arquivo, inclusive os do
   formulário público que o cliente preenche no celular. */
input[type="file"] {
  width: 100%; min-height: 2.875rem; padding: .45rem .55rem;
  border: 1px dashed var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface-2); color: var(--muted);
  font: inherit; font-size: .86rem; cursor: pointer;
}
input[type="file"]:hover { border-color: var(--primary); }
input[type="file"]:focus-visible { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring); }
/* o botão interno também precisa ser tocável, não só a caixa em volta */
input[type="file"]::file-selector-button {
  min-height: 2.25rem; padding: .45rem .85rem; margin: 0 .7rem 0 0;
  border: 0; border-radius: var(--radius-sm);
  background: var(--primary); color: #fff;
  font: inherit; font-size: .84rem; font-weight: 600; cursor: pointer;
}
input[type="file"]::file-selector-button:hover { filter: brightness(1.08); }

/* ---------- Alvos de toque no celular ----------
   Auditoria mediu vários controles entre 20px e 35px de altura. No mouse isso
   passa; no polegar, não. O mínimo confortável é 40px, e 44px onde o erro custa
   caro (refazer uma escolha, apagar texto digitado).

   Tudo aqui vive na media query do celular de propósito: no desktop os mesmos
   controles em 31px estão bons, e engordá-los lá só desperdiçaria espaço. */
@media (max-width: 899px) {
  /* fileira de ações do cabeçalho, presente em quase toda tela */
  .page-actions .btn { min-height: 2.5rem; }
  /* três botões no cabeçalho só existem em Materiais: divididos, cabem sem
     empurrar a ação principal para uma segunda linha sozinha */
  .page-actions .btn { flex: 1 1 auto; justify-content: center; }

  /* chips de status: são o filtro principal de Leads e Cadastros, e ficavam
     colados um no outro, o que faz errar o vizinho */
  .status-chips { gap: .5rem; }
  .status-chips button { flex: none; min-height: 2.75rem; padding: .4rem .9rem; }
  /* Fora do painel de filtros (Cadastros), cinco etiquetas de 44px quebravam em
     duas fileiras e empurravam a primeira ficha para o fim da tela. Aqui elas
     ficam numa fileira só que rola de lado, encostando nas bordas da tela — a
     etiqueta cortada na borda é o que avisa que há mais. Dentro do painel de
     Leads continuam quebrando: ali a pessoa abriu o painel justamente para ver
     todas. */
  .status-chips:not(.filterbar-panel .status-chips) {
    flex-wrap: nowrap; overflow-x: auto; overscroll-behavior-x: contain;
    margin-inline: -1rem; padding: 0 1rem; scrollbar-width: none;
  }
  .status-chips:not(.filterbar-panel .status-chips)::-webkit-scrollbar { display: none; }

  /* o seletor de tema dentro da folha, que deixou de herdar o estilo de menu.
     A largura importa tanto quanto a altura: são três botões colados, e um alvo
     estreito faz acertar o vizinho. */
  .sheet-actions .tema-seg button { min-height: 2.75rem; min-width: 2.75rem; padding: .5rem .9rem; }

  /* chips de "Inserir campo" em Configuração: cada clique insere texto na
     posição do cursor, então errar o chip custa apagar e repetir */
  .chip { padding: .55rem .8rem; min-height: 2.5rem; }
  .chip-row { gap: .5rem; }

  /* caixas de seleção do modal "Gerar mensagem": a label já envolve o input,
     então aumentar a área da label resolve sem tocar no JS */
  .check-list { gap: .15rem; }
  .check-list .switch {
    min-height: 2.75rem; padding: .35rem .25rem; border-radius: var(--radius-sm);
    display: flex; align-items: center;
  }

  /* ações na linha do arquivo, em Materiais */
  .mat-acoes { gap: .5rem; }
  .mat-acoes .btn { min-height: 2.5rem; min-width: 2.5rem; justify-content: center; }
}

@media (max-width: 639px) {
  /* barra de período das Métricas e o botão que ABRE os filtros: no celular
     este botão é o único caminho para o painel, e tinha 34px */
  .segmented button { padding: .62rem .4rem; min-height: 2.75rem; }
  .filterbar-toggle { min-height: 2.75rem; }
}

/* ---------- Foto de perfil ----------
   A bolinha de perfil (.avatar na barra lateral e na folha do celular,
   .aviso-avatar no card do aviso) mostra a foto quando existe e as iniciais
   quando não. `tem-foto` tira o fundo colorido: a foto passa a ser o fundo. */
.avatar.tem-foto, .aviso-avatar.tem-foto { background: var(--surface-2); overflow: hidden; }
.avatar img, .aviso-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 50%; }
/* o modal: a prévia grande e centrada do que vai subir */
.foto-perfil { display: flex; justify-content: center; margin: .2rem 0 .8rem; }
.foto-perfil .avatar { width: 7.5rem; height: 7.5rem; font-size: 2rem; }
/* ---------- Canal parceiro: planos no formulário público ---------- */
/* Cartões de rádio em vez de um <select>: são duas opções com preço, e preço
   escondido atrás de um menu é preço que ninguém compara. O rádio nativo
   continua lá (foco, teclado, leitor de tela); só a bolinha é redesenhada. */
.plano-opcoes { display: grid; gap: .6rem; }
@media (min-width: 560px) { .plano-opcoes { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.plano-op { position: relative; display: block; min-width: 0; cursor: pointer; }
.plano-op input {
  position: absolute; top: .95rem; left: .9rem; width: 1.125rem; height: 1.125rem;
  margin: 0; opacity: 0;
}
.plano-corpo {
  display: flex; flex-direction: column; gap: .2rem; min-width: 0;
  padding: .85rem .9rem .85rem 2.6rem;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); transition: border-color .15s, background .15s;
}
/* a bolinha desenhada, no lugar exato do rádio escondido */
.plano-corpo::before {
  content: ''; position: absolute; top: .95rem; left: .9rem;
  width: 1.125rem; height: 1.125rem; border-radius: 50%;
  border: 2px solid var(--border-strong); background: var(--surface);
  transition: border-color .15s, box-shadow .15s;
}
.plano-op:hover .plano-corpo { border-color: var(--border-strong); }
.plano-op input:checked + .plano-corpo {
  border-color: var(--primary); background: var(--primary-soft);
}
.plano-op input:checked + .plano-corpo::before {
  border-color: var(--primary); box-shadow: inset 0 0 0 4px var(--primary);
}
.plano-op input:focus-visible + .plano-corpo {
  outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring);
}
.plano-nome { font-weight: 650; font-size: .95rem; overflow-wrap: anywhere; }
.plano-valores { display: flex; align-items: baseline; gap: .45rem; flex-wrap: wrap; min-width: 0; }
.plano-preco { font-size: 1.15rem; font-weight: 700; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.plano-preco small { font-size: .74rem; font-weight: 500; color: var(--muted); margin-left: .15rem; }
/* o preço sem o convênio. Fica ANTES do real e menor: ele é a referência, e
   referência que compete em tamanho com o número que vale é o que faz a pessoa
   ler o valor errado. */
.plano-de {
  font-size: .9rem; font-weight: 500; color: var(--faint);
  text-decoration-thickness: 1.5px; font-variant-numeric: tabular-nums;
}
/* o "de" e o "por". Minúsculos de propósito: são ligação entre os dois números,
   não informação — quem lê rápido pula direto do riscado para o que vale. */
.plano-rot { font-size: .78rem; font-weight: 500; color: var(--muted); }

/* Plano único: não é escolha, é informação — então não tem rádio, nem borda de
   opção selecionável. O código vai num input oculto e o que se vê é o preço. */
.plano-unico {
  display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; min-width: 0;
  padding: .85rem 1rem;
  background: var(--primary-soft); border: 1px solid var(--primary);
  border-radius: var(--radius-sm);
}
.plano-unico .plano-preco { font-size: 1.45rem; }
.plano-selo {
  display: inline-flex; align-items: center; gap: .3rem; min-width: 0;
  color: var(--success); font-size: .82rem; font-weight: 600;
}
.plano-selo .ico { flex: none; }

/* ---------- Aba Bruscon ---------- */
.cond-lista, .br-fichas { display: flex; flex-direction: column; gap: .5rem; }

.cond-item {
  display: flex; align-items: center; gap: .6rem; min-width: 0;
  padding: .6rem .7rem;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius);
}
/* Condomínio fora do formulário continua visível — é o gestor quem religa —,
   mas recuado, para não competir com o que está no ar. */
.cond-item.is-off { opacity: .62; }
.cond-id { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: .1rem; }
.cond-nome { font-weight: 600; font-size: .92rem; overflow-wrap: anywhere; }
/* mesmo respiro do ponto separador dos outros cartões (.cad-sub, .mat-sub) */
.cond-id .sep, .br-ficha-id .sep { margin: 0 .35rem; color: var(--faint); }
.cond-acoes { flex: none; display: flex; align-items: center; gap: .15rem; }
.cond-acoes .badge { margin-right: .25rem; }

.br-ficha {
  display: flex; align-items: center; gap: .6rem; min-width: 0;
  padding: .6rem .7rem; color: inherit; text-decoration: none;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius);
  transition: border-color .15s, transform .15s;
}
.br-ficha:hover { border-color: var(--border-strong); transform: translateY(-1px); }
.br-ficha:focus-visible { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring); }
.br-ficha-id { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: .1rem; }
.br-ficha-nome { font-weight: 600; font-size: .92rem; overflow-wrap: anywhere; }
.br-ficha-fim { flex: none; display: flex; align-items: center; gap: .5rem; }

/* No celular a linha quebra em duas: nome e condomínio em cima, situação e
   quando embaixo — é a mesma solução dos cartões de cadastro. */
@media (max-width: 599px) {
  .cond-item, .br-ficha { flex-wrap: wrap; row-gap: .45rem; }
  .cond-id, .br-ficha-id { flex: 1 0 100%; }
  .cond-acoes, .br-ficha-fim { margin-left: auto; }
  .cond-acoes .btn-icon { width: 2.5rem; height: 2.5rem; }
}
/* Duas colunas, e não as três de .settings-row: são dois cartões, e o da
   direita carrega linha com nome, condomínio, plano e valor — num terço da
   tela isso quebra letra a letra. O da esquerda é lista curta e cabe estreito. */
.br-colunas { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1rem; align-items: start; }
.br-colunas > .card { margin-top: 0; min-width: 0; }
@media (min-width: 1000px) { .br-colunas { grid-template-columns: minmax(0, 22rem) minmax(0, 1fr); } }
/* ---------- Subabas (Coleta de dados) ---------- */
/* Uma tira de botoes, e nao itens na barra lateral: os canais sao irmaos de uma
   mesma tela e dividem o mesmo cabecalho, o mesmo botao de Atualizar e o mesmo
   desenho. Item separado na lateral daria a entender que sao telas diferentes. */
.subabas {
  display: flex; gap: .3rem; flex-wrap: wrap; min-width: 0;
  margin: 0 0 1rem; padding: .3rem;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius);
}
.subabas button {
  flex: 0 1 auto; min-width: 0; padding: .5rem .9rem;
  background: transparent; border: 1px solid transparent; border-radius: var(--radius-sm);
  color: var(--muted); font-size: .9rem; font-weight: 600; cursor: pointer;
  transition: background .15s, color .15s, border-color .15s;
}
.subabas button:hover { color: var(--text); background: var(--gray-soft); }
.subabas button:focus-visible { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--ring); }
.subabas button.ativa {
  background: var(--surface); border-color: var(--border);
  color: var(--text); box-shadow: var(--shadow);
}
/* no celular o alvo de toque manda, e duas ou tres abas cabem lado a lado */
@media (max-width: 640px) {
  .subabas button { flex: 1 1 auto; padding: .6rem .7rem; min-height: 2.75rem; }
}

/* =============================================================================
   Escala da interface: o que se reorganiza em 125% e 150%

   A escala em si é uma linha (a fonte da raiz, no começo da folha). O que mora
   aqui é o que precisa MUDAR DE LUGAR quando tudo cresce. Media query não
   enxerga a escala — o navegador mede breakpoints na fonte inicial, nunca na
   que o CSS definiu —, então num notebook de 1280px em 150% a página montava
   três colunas como se sobrassem 1280px de letra normal. As consultas de
   contêiner abaixo medem a área útil em rem, que cresce com a escala, e os
   limites dos contêineres `principal` e `cadlista` são os breakpoints de 100%
   convertidos (a tela de 1000px deixa 42rem de conteúdo ao lado da lateral; a
   de 760px, 45.5rem de lista); os de `pastas` e `papeis` saem de medidas.
   Tudo escopado a 125% e 150%: em 100% a página é exatamente a de antes.
   E tudo dentro de @media screen: na impressão a fonte volta a 100%, e estas
   regras (que empatam em especificidade com as da ficha impressa e vêm depois)
   mudariam o papel.
   ============================================================================= */
@media screen {
.main { container: principal / inline-size; }
.cad-lista { container: cadlista / inline-size; }
.pasta-grid { container: pastas / inline-size; }
.role-picker { container: papeis / inline-size; }

/* Configuração e Coleta de dados: três cartões, ou duas colunas, só com espaço */
@container principal (max-width: 41.99rem) {
  html:is([data-escala="125"], [data-escala="150"]) .settings-row,
  html:is([data-escala="125"], [data-escala="150"]) .br-colunas { grid-template-columns: minmax(0, 1fr); }
}
/* Métricas: a rosca ao lado do gráfico de linha pede ~47rem */
@container principal (max-width: 46.99rem) {
  html:is([data-escala="125"], [data-escala="150"]) .charts { grid-template-columns: minmax(0, 1fr); }
}
/* Configuração: o editor da mensagem e o celular de prévia lado a lado pedem ~54.5rem */
@container principal (max-width: 54.49rem) {
  html:is([data-escala="125"], [data-escala="150"]) .compose-grid { grid-template-columns: minmax(0, 1fr); }
  html:is([data-escala="125"], [data-escala="150"]) .compose-preview .phone { margin-inline: auto; }
}

/* Cadastros: a ficha numa linha só pede 45.5rem. Mais estreita, vira as duas
   linhas do celular — em 150% num notebook o nome da ficha ficava com 86px.
   Mesmas regras de @media (max-width: 760px), que em 100% continua valendo. */
@container cadlista (max-width: 45.5rem) {
  html:is([data-escala="125"], [data-escala="150"]) .cad-card { flex-wrap: wrap; row-gap: .6rem; }
  html:is([data-escala="125"], [data-escala="150"]) .cad-quebra { display: block; flex: 1 0 100%; height: 0; margin: 0; }
  html:is([data-escala="125"], [data-escala="150"]) .cad-fim { margin-left: auto; }
  html:is([data-escala="125"], [data-escala="150"]) .cad-tags { flex-wrap: wrap; }
  html:is([data-escala="125"], [data-escala="150"]) .cad-quando { min-width: 0; }
  html:is([data-escala="125"], [data-escala="150"]) .cad-sub .sep-cidade { display: none; }
  html:is([data-escala="125"], [data-escala="150"]) .cad-sub .cad-cidade {
    display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
}
/* Lista estreita de verdade (o celular): documento e telefone também não cabem
   juntos, e o telefone saía cortado nas reticências. Uma linha para cada. */
@container cadlista (max-width: 22rem) {
  html:is([data-escala="125"], [data-escala="150"]) .cad-sub .sep { display: none; }
  html:is([data-escala="125"], [data-escala="150"]) .cad-sub .mono {
    display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
}

/* Materiais: a contagem de arquivos desce para baixo do nome quando a pasta
   fica estreita — ao lado, ela deixava 84px para "Propostas". O recuo alinha
   a contagem com o nome (ícone de 2.375rem + gap de .8rem). */
@container pastas (max-width: 16rem) {
  html:is([data-escala="125"], [data-escala="150"]) .pasta-card { flex-wrap: wrap; row-gap: .25rem; }
  html:is([data-escala="125"], [data-escala="150"]) .pasta-qtd { flex-basis: 100%; padding-left: 3.175rem; }
}

/* Login: o nome do papel é uma palavra só ("Representante") e não quebra; em
   150% ele não cabia ao lado do ícone e da seta, e a tela de login ganhava
   rolagem lateral. O ícone sai; a cor do papel continua na etiqueta da tela
   seguinte. */
@container papeis (max-width: 14rem) {
  html:is([data-escala="125"], [data-escala="150"]) .role-option { grid-template-columns: minmax(0, 1fr) auto; }
  html:is([data-escala="125"], [data-escala="150"]) .role-option .role-ico { display: none; }
}

@media (max-width: 899px) {
  /* Respiro lateral fixo em 16px quando a letra cresce. Em rem, 150% num
     celular de 360px gastava 96px só com margens (24px da página + 24px do
     cartão, dos dois lados) e espremia o que estava no meio. A borda da tela
     não precisa crescer: quem precisa é o texto. */
  html:is([data-escala="125"], [data-escala="150"]) .main { padding-left: 16px; padding-right: 16px; }
  html:is([data-escala="125"], [data-escala="150"]) .status-chips:not(.filterbar-panel .status-chips) {
    margin-inline: -16px; padding-inline: 16px;
  }
  html:is([data-escala="125"], [data-escala="150"]) .auth-page { padding-left: 16px; padding-right: 16px; }
  html:is([data-escala="125"], [data-escala="150"]) .auth-card { padding-left: 16px; padding-right: 16px; }
  html:is([data-escala="125"], [data-escala="150"]) .sheet { padding-left: 16px; padding-right: 16px; }

  /* Busca e botão de filtros, cada um na sua linha: meio a meio, o resumo
     "Abertos · 30 dias" virava "Ab…" — e é o único lugar que diz qual filtro
     está valendo. */
  html:is([data-escala="125"], [data-escala="150"]) .filterbar { flex-wrap: wrap; }
  html:is([data-escala="125"], [data-escala="150"]) .filterbar > * { flex: 1 1 100%; }

  /* Tema e Tamanho na folha, em 150% num celular de 320px: os três botões do
     Tamanho (278px) mais o recuo da linha passavam da folha. Sem o recuo cabem. */
  html:is([data-escala="125"], [data-escala="150"]) .sheet-actions .tema-linha { padding-inline: 0; }
}

@media (max-width: 639px) {
  html:is([data-escala="125"], [data-escala="150"]) .card,
  html:is([data-escala="125"], [data-escala="150"]) .modal-header,
  html:is([data-escala="125"], [data-escala="150"]) .modal-body,
  html:is([data-escala="125"], [data-escala="150"]) .modal-footer { padding-left: 16px; padding-right: 16px; }
}

/* Prévia do WhatsApp em Configuração: com a letra maior, os 33.75rem de altura
   passavam da janela de um notebook. Com escala, no máximo 75% da altura. */
html:is([data-escala="125"], [data-escala="150"]) .phone-screen { height: min(33.75rem, 75vh); }
} /* fim do @media screen da escala */

/* iPhone: campo com fonte abaixo de 16px dá zoom sozinho ao ser tocado. Estes
   dois venciam a regra geral de 16px por especificidade, e o zoom acontecia já
   em 100% — é a única correção deste bloco que vale em 100%, de propósito. */
@media (max-width: 899px) {
  .link-card .link-url input { font-size: max(16px, .85rem); }
  .compose-editor textarea { font-size: max(16px, .84rem); }
}
