/* =====================================================================
   Agenda King — Design System
   Tema claro/escuro + cor primária injetada pelo tenant em runtime.
   ===================================================================== */

:root {
  /*
   * O calendário do campo de data NÃO é nosso.
   *
   * `<input type="date">` abre um painel desenhado pelo navegador, fora
   * do documento: CSS não alcança, seletor não pega, tema não segue. A
   * única coisa que o navegador escuta é esta propriedade — e sem ela o
   * padrão é `normal`, que significa claro.
   *
   * O efeito era um calendário branco saltando de uma tela escura, com
   * o dia selecionado em azul de sistema. E não só ele: a lista de um
   * `<select>` aberto, as setinhas do campo numérico, o relógio do campo
   * de hora e o amarelo do preenchimento automático são todos pintados
   * pelo navegador. São 105 campos assim no produto.
   *
   * Declarar aqui resolve os 105 de uma vez, e é a ÚNICA forma: não
   * existe truque de CSS para dentro do painel nativo. `filter: invert`
   * no ícone só mascararia o sintoma no botãozinho, deixando o
   * calendário branco do mesmo jeito.
   */
  color-scheme: light;

  /* ===================================================================
   * IDENTIDADE V81 — tokens canônicos (fonte única da paleta).
   * ---------------------------------------------------------------
   * Tudo abaixo destes 12 tokens é ALIAS. Os nomes legados (--bg,
   * --card, --text, --brand…) continuam existindo porque ~8.500 linhas
   * de CSS já os consomem — mas nenhum deles carrega mais um hex
   * próprio: todos apontam para cá. Trocar a identidade de novo é
   * mexer só neste bloco e no par escuro, nunca caçar cor espalhada.
   * =================================================================== */
  --background: #EDE2D7;
  --background-secondary: #F6EFE7;

  --surface: #FBF7F1;
  --surface-highlight: #E7DBCE;

  --text-primary: #17130F;
  --text-secondary: #685B49;
  --text-on-gold: #17130F;

  --brand-primary: #B58A48;
  --brand-light: #C9A874;
  --brand-dark: #8B6838;

  --border: #D4C7B6;
  --shadow: rgba(23, 19, 15, 0.14);

  /* Branco de apoio — só onde o papel é REALMENTE papel branco (fundo de
     campo, miolo de gráfico), nunca como superfície geral: o claro é
     bege quente, não interface branca genérica. */
  --paper: #FFFFFF;

  /* cores base — sobrescritas por tenant via --brand */
  --brand: var(--brand-primary);
  --brand-fg: var(--text-on-gold);

  /*
   * A marca tem DOIS papéis que puxam para lados opostos.
   *
   * Como TEXTO sobre superfície escura — aba ativa, item de menu, link —
   * ela precisa ser clara. É por isso que `readableBrand` põe piso 0.62
   * de luminosidade no tema escuro.
   *
   * Como FUNDO sob texto branco — botão principal, item ativo da
   * navegação da plataforma — ela precisa ser escura. Clara demais e o
   * branco por cima some.
   *
   * Um token não serve aos dois. Enquanto serviu, o fundo seguiu o papel
   * de texto e o branco por cima media 3,68:1, abaixo dos 4,5:1 que o
   * WCAG AA pede. --brand-action é o papel de FUNDO; --brand segue sendo
   * texto, ícone, borda e decoração, sem alteração.
   *
   * Aqui no claro os dois coincidem: #111827 sob branco dá 17,74:1, e
   * `var(--brand)` faz a cor do tenant continuar chegando sozinha.
   */
  --brand-action: var(--brand);
  /*
   * O dourado como TEXTO/ícone sobre superfície clara precisa ser o tom
   * mais FUNDO da família. --brand-primary (#B58A48) mede 2,94:1 sobre
   * --surface (#FBF7F1) e reprova o mínimo de 4,5:1; quem passa é
   * --brand-dark (#8B6838), 4,76:1. --brand-primary segue sendo o
   * PREENCHIMENTO da marca (--brand, com --brand-fg escuro em cima,
   * 5,89:1) — encher e escrever são papéis diferentes. Nunca o
   * --brand-light: dourado claro sobre bege claro some.
   * Segue --icon-accent para que os dois temas andem juntos: no escuro
   * a tinta volta a ser --brand-primary (#D4A260, 7,86:1 sobre o card).
   */
  --accent: var(--icon-accent);

  /* Superfícies — todas derivadas dos 4 tokens canônicos acima.
     --surface-2 é o fundo RECUADO (rodapé de card), perto do fundo
     geral; --surface-3 é hover/campo, o bege um passo mais fundo. */
  --bg: var(--background);
  --surface-2: var(--background-secondary);
  --surface-3: var(--surface-highlight);
  --card: var(--surface);
  --card-highlight: var(--surface-highlight);
  /* Listras diagonais dentro do card — quase imperceptíveis de
     propósito (nunca no fundo geral do dashboard). */
  --card-texture: rgba(181, 138, 72, .018);
  --border-subtle: #E0D5C6;
  --border-strong: #C0B09A;
  --icon-accent: var(--brand-dark);
  --icon-box: #F3E7D5;
  --icon-box-border: rgba(181, 138, 72, .20);

  --text: var(--text-primary);
  /*
   * #667085 era o valor sugerido pelo briefing para "texto desabilitado"
   * no tema escuro (ver nota em [data-theme='dark']) — lá ele reprovava
   * por medir só 3,54:1 contra os cards escuros. Aqui, no claro, é outro
   * cálculo: sobre --surface (#fff) e --surface-3 (#f3f4f6) ele mede
   * ~4,97:1 e ~4,93:1 — acima do mínimo de 4,5:1 para texto normal — e é
   * exatamente o cinza-azulado "premium" que o briefing pede para
   * --text-2. Usado aqui, no papel de texto de apoio de verdade.
   */
  --text-2: var(--text-secondary);
  /*
   * Fase 3.1: --text-3 (texto discreto/apoio secundário — .dim,
   * .kpi__hint, .empty__text, .section-title) media SÓ 2,54:1 no valor
   * antigo (#9ca3af) — abaixo do mínimo de 4,5:1 para texto normal, e
   * usado em texto de verdade (dica de KPI, texto de estado vazio), não
   * em nada realmente desabilitado. Corrigido para #6c7686: mede 4,59:1
   * sobre --surface (branco) e ainda mais sobre --surface-3.
   *
   * Não dá pra ir mais claro que isso e continuar passando: 4,5:1 sobre
   * fundo quase branco deixa pouquíssima margem entre "passa" e "escuro
   * como --text-2" — os dois ficam parecidos no claro por causa disso,
   * o oposto do que acontece no escuro (onde --text-3 tem folga real
   * para ser mais apagado que --text-2 e ainda passar). É limite do
   * próprio AA sobre fundo claro, não decisão de design.
   *
   * Texto que É pra ficar bem apagado (mesmo abaixo do mínimo, porque
   * é decoração ou está genuinamente desabilitado) usa --text-disabled,
   * não este token.
   */
  --text-3: #7A6B57;
  /* Elemento REALMENTE desabilitado (WCAG isenta esse caso do mínimo de
     contraste de texto normal) — nunca usar em texto de apoio comum,
     ver justificativa completa no bloco [data-theme='dark']. */
  --text-disabled: #A0917E;

  /* Semântica preservada (verde=sucesso, vermelho=erro, âmbar=alerta,
     azul=informação) — só reequilibrada para o bege quente. Nenhum
     destes vira dourado: estado não é identidade de marca. Todos
     medidos ≥4,5:1 sobre --surface. */
  --green: #2F7D4F;
  --green-bg: #DDEBDF;
  --red: #C0392B;
  --red-bg: #F6DED9;
  /* Fundo do botão destrutivo sólido (.btn--danger) — mesmo desenho de
     --brand/--brand-action: --red segue sendo texto/ícone/borda, e o
     botão de preenchimento sólido ganha o papel próprio. Aqui os dois
     coincidem porque --red já nasce escuro o bastante (4,83:1 com texto
     branco) pro claro; no escuro os papéis se separam de verdade — ver
     comentário no bloco [data-theme='dark']. */
  --red-action: var(--red);
  --amber: #8F5E10;
  --amber-bg: #F5E7CC;
  --blue: #2C6CB0;
  --blue-bg: #DCE7F3;
  --violet: #6D4AA8;
  --violet-bg: #E6DFF2;

  /* Texto para cima de um preenchimento SÓLIDO de --green/--red/--amber/
     --orange/--blue (mapa de ocupação, não badge — badge usa a versão
     -bg, clara, com o texto normal em cima). Aqui claro funciona porque,
     no claro, esses tokens são a versão escura/saturada da cor. */
  --on-solid: var(--paper);

  --r-sm: 8px;
  /* --r-md existia em duas regras (cadastro de cliente, serviços) sem nunca
     ter sido definido: `border-radius: var(--r-md)` é declaração inválida,
     e as duas caixas saíam com canto reto. */
  --r-md: 10px;
  --r: 12px;
  --r-lg: 16px;
  --r-xl: 22px;
  --r-full: 999px;

  /* Sombra discreta e quente — derivada de --shadow, nunca cinza-azulada
     (chumbo frio sobre bege denuncia paleta emprestada). */
  --sh-1: 0 1px 2px rgba(23, 19, 15, .06);
  --sh-2: 0 4px 12px rgba(23, 19, 15, .10);
  --sh-3: 0 12px 32px var(--shadow);

  /* Escala de espaçamento. Uma régua só para o sistema inteiro: telas que
     escolhem o próprio número são o que faz um painel parecer montado por
     três pessoas diferentes. */
  --sp-0: 4px;
  --sp-1: 8px;
  --sp-2: 12px;
  --sp-3: 16px;
  --sp-4: 20px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 40px;

  --sidebar-w: 252px;
  --topbar-h: 60px;
  --bottomnav-h: 64px;
  --sidebar-bg: var(--background-secondary);
  --topbar-bg: var(--surface);
  --topbar-hairline: 0 1px 0 0 rgba(23, 19, 15, .06);
  --account-bg: var(--surface-highlight);
  --account-border: transparent;
  --dash-kpi-body: var(--surface);
  --dash-kpi-label: var(--text-secondary);
  --dash-kpi-delta: #7A6B57;
  --brand-word: var(--brand-dark);
  --nav-parent-ink: #3A3128;
  --nav-sub-ink: #4A4034;
  /* Realce de navegação SEMPRE dourado (identidade fixa da V76), nunca a
     cor customizável do tenant (--brand é tema/ação, injetada por
     estabelecimento — nav ativo não deve mudar com ela). */
  --nav-active-ink: #6B4E22;
  --nav-active-bg: #EFE0C9;
  --nav-active-border: transparent;
  --nav-active-glow: transparent;

  --font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;

  /*
   * Tokens de movimento — o painel já tinha muita transição espalhada
   * (botão, input, modal, kpi clicável…) com duração escrita na mão em
   * cada regra (.12s aqui, .16s ali, .18s acolá). Isto não troca o que já
   * existe (risco desnecessário em dezenas de regras já testadas) — serve
   * de referência única para qualquer transição NOVA a partir de agora,
   * e é o valor usado nas animações novas desta rodada (entrada de
   * página, badges, etc.).
   */
  --motion-fast: 120ms;
  --motion-base: 180ms;
  --motion-slow: 260ms;
  --ease-standard: cubic-bezier(.2, .8, .2, 1);
}

[data-theme='dark'] {
  /* o par da declaração em :root — é isto que faz o calendário nativo,
     a lista do select e a barra de rolagem virarem escuros junto */
  color-scheme: dark;

  /*
   * Redesign Fase 4 (troca global de paleta — dark premium + azul +
   * verde WhatsApp, pedido explícito do dono): valores novos pra
   * --bg/--surface/--surface-2/--surface-3/--border, mapeados pela MESMA
   * escala de papéis de sempre, não por nome — --surface continua sendo
   * o que .card/.sidebar/.topbar/.modal usam, --surface-3 continua sendo
   * hover (.nav__item:hover/.btn:hover/.tenant-pill:hover) e agora
   * também dobra como fundo de input/select/dropdown (mesmo tom pedido
   * pro briefing pra "superfície secundária"). --border vira hex sólido
   * em vez de rgba branco translúcido — mesma função, valor exato pedido.
   */
  /* ===================================================================
   * IDENTIDADE V81 — tokens canônicos do tema ESCURO (o padrão).
   * Mesmo contrato do bloco claro: só estes 12 carregam hex; o resto
   * do arquivo é alias. Marrom-carvão quente, nunca preto chapado —
   * #080706 mantém a leitura de profundidade entre fundo e card.
   * =================================================================== */
  --background: #080706;
  --background-secondary: #11100E;

  --surface: #181611;
  --surface-highlight: #211B13;

  --text-primary: #F7F2EA;
  --text-secondary: #A09F9D;
  --text-on-gold: #110D08;

  --brand-primary: #D4A260;
  --brand-light: #EBD2A3;
  --brand-dark: #946630;

  --border: #30302D;
  --shadow: rgba(0, 0, 0, 0.45);

  /* No escuro não existe "papel branco": o papel de máximo contraste é
     o próprio texto claro. Evita #fff cravado saltando do carvão. */
  --paper: #F7F2EA;

  /*
   * --surface-2 é o fundo RECUADO (rodapé de card etc.) — papel de ficar
   * perto do fundo geral, não de --surface. --surface-3 é hover/campo,
   * um passo ACIMA do card (o "card destacado" da identidade).
   */
  --bg: var(--background);
  --surface-2: var(--background-secondary);
  --surface-3: var(--surface-highlight);
  --card: var(--surface);
  --card-highlight: rgba(235, 210, 163, .03);
  /* Listras diagonais só dentro de card/superfície de destaque, no
     limiar do perceptível — nunca no fundo geral do dashboard. */
  --card-texture: rgba(212, 162, 96, .022);
  --border-subtle: #24231F;
  /* Um passo mais claro que --border, pra divisor/foco que precisa se
     destacar mais — mesma família neutra quente. */
  --border-strong: #45443F;
  --icon-accent: var(--brand-primary);
  --icon-box: #2A2116;
  --icon-box-border: rgba(212, 162, 96, .24);

  --text: var(--text-primary);
  --text-2: var(--text-secondary);
  /*
   * --text-3 segue o valor do briefing (#7F8794). --text-disabled
   * continua em #667085 (não pedido no briefing, mantido do valor já
   * validado por QA — ainda funciona: a diferença entre os novos
   * --bg/--surface e os antigos é mínima, o contraste dele não muda de
   * forma perceptível).
   */
  --text-3: #85837F;
  --text-disabled: #5E5C58;

  /*
   * Migração visual v76 (identidade dourada, pedido explícito do dono):
   * o azul de marca (#609FF4) vira dourado (#F4BD50), mesma mecânica de
   * papéis já estabelecida para o azul. Dourado claro como TEXTO/ícone/
   * borda tem folga enorme sobre --surface (~10,3:1) mas, como FUNDO
   * sólido, texto branco mediria só ~1,7:1 — pior ainda que o azul.
   * --brand-fg continua o tom escuro do próprio sistema (#101112), que
   * sobre #F4BD50 mede ~12,2:1. --brand-action usa o MESMO dourado.
   *
   * --gold-2 é o tom mais claro (#FFD470) usado só em gradiente/hover de
   * destaque (botão primário, borda ativa da sidebar) — nunca como cor
   * de texto sozinha.
   *
   * Tenant com cor própria continua mandando onde existir esse fluxo
   * (público /b/<slug>, textoSobre() recalcula o par certo sozinho);
   * aqui é só o padrão do painel.
   */
  --brand: var(--brand-primary);
  --brand-fg: var(--text-on-gold);
  --brand-action: var(--brand-primary);
  --gold-2: var(--brand-light);

  /* Cor de estado no escuro: as claras precisam subir de luminosidade para
     manter contraste ≥ 4.5:1 sobre --surface, e o fundo desce.
     --green e --blue viram o par novo (verde WhatsApp/sucesso e azul de
     marca, pedidos no briefing como a mesma cor pra "sucesso" e
     "informação"); --red/--amber ficam vermelho/âmbar semânticos sem
     mudança (pedido explícito: não virar tudo azul); --violet/--orange
     (abaixo) ficam como estão — são categorias reais em uso (KPI de
     "confirmado"/"em atendimento", séries de gráfico, heatmap de
     horário de pico), não sobra de marca antiga. */
  --green: #7FD3A3;
  --red: #EF8A80;
  /*
   * --red-action (achado de auditoria, fechado agora): .btn--danger
   * usava var(--red) direto como fundo sólido com texto branco fixo —
   * no escuro, --red é a versão CLARA de estado (#f87171, pensada pra
   * ler como TEXTO sobre --surface), e branco em cima dela mede só
   * 2,77:1, abaixo do mínimo de 4,5:1. Mesmo problema que --brand tinha,
   * mesma solução: papel de FUNDO sólido separado do papel de texto.
   *
   * #dc2626 não é um valor novo — é o --red do tema CLARO, já usado
   * hardcoded em 2 lugares deste arquivo (o contador de badge vermelho,
   * comentário "vermelho fixo, não var(--red)") exatamente por já ser
   * escuro o bastante: 4,83:1 com branco. Reaproveitado aqui como
   * token em vez de mais um hex solto.
   */
  --red-action: #C0392B;
  --amber: #F0C063;
  --blue: #7EB6F5;
  --violet: #B79BF0;
  /* Fundos de badge em tom quente e fundo, na mesma família do carvão —
     o azul/verde/roxo frios de antes brigavam com o marrom da base. */
  --green-bg: #14281C;
  --red-bg: #33160F;
  --amber-bg: #2E2410;
  --blue-bg: #14243A;
  --violet-bg: #221B33;

  /* No escuro esses tokens viram a versão CLARA da cor (comentário acima),
     então o mesmo branco fica ilegível em cima — texto escuro é quem
     garante contraste aqui. Vale pro novo --green (#89D8A9) e pro novo
     --blue (#609FF4) do mesmo jeito que já valia pro amber/orange. */
  --on-solid: #17130F;

  --sh-1: 0 1px 2px rgba(0, 0, 0, .45);
  --sh-2: 0 4px 14px rgba(0, 0, 0, .5);
  --sh-3: 0 16px 40px rgba(0, 0, 0, .6);

  --sidebar-bg: linear-gradient(180deg, #0D0C0A, #0A0908 72%, #0D0C0A);
  --topbar-bg: rgba(17, 16, 14, .94);
  --topbar-hairline: 0 1px 0 0 rgba(247, 242, 234, .05);
  --account-bg: #15130F;
  --account-border: rgba(235, 210, 163, .12);
  --dash-kpi-body: linear-gradient(#1A1712, #15130F);
  --dash-kpi-label: #BDB9B2;
  --dash-kpi-delta: #94918C;
  --brand-word: var(--brand-light);
  --nav-parent-ink: #D8D3CB;
  --nav-sub-ink: #A8A49D;
  --nav-active-ink: var(--brand-light);
  --nav-active-bg: linear-gradient(110deg, rgba(212, 162, 96, .14), rgba(212, 162, 96, .05));
  --nav-active-border: rgba(212, 162, 96, .55);
  --nav-active-glow: rgba(212, 162, 96, .85);
}

* { box-sizing: border-box; }
*::before, *::after { box-sizing: border-box; }

/*
 * O navegador esconde [hidden] com display:none, mas qualquer regra nossa
 * de display vence essa, porque é mais específica. Era o que fazia o campo
 * do sinal continuar ocupando a coluna com "Pagar no local" selecionado:
 * o atributo estava lá, o display:flex da grade passava por cima.
 */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  /*
   * Antes só `body` tinha fundo — `html` ficava branco por padrão do
   * navegador. Não dava pra ver numa carga normal (body cobre a tela
   * inteira antes de qualquer coisa), mas aparecia no bounce/overscroll
   * elástico do iOS e em qualquer instante entre o parse do documento e
   * o primeiro paint do body. Mesma variável dos dois: nunca diverge.
   */
  background: var(--bg);
}

body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}

h1, h2, h3, h4 { margin: 0; font-weight: 650; letter-spacing: -.015em; }
/* Título de página (só usado via pageHeader() — ver ~60 views): 24px
   ficava abaixo da escala pedida (28-32px desktop). 28, não 32, porque
   o próprio briefing pede pra evitar título gigante. */
h1 { font-size: 28px; }
h2 { font-size: 19px; }
h3 { font-size: 16px; }
p { margin: 0; }
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }
img { max-width: 100%; display: block; }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 99px; border: 3px solid var(--bg); }

/* ---------------------------------------------------------------- LAYOUT */
.shell { display: flex; min-height: 100vh; min-height: 100dvh; }

.sidebar {
  width: var(--sidebar-w);
  flex: 0 0 var(--sidebar-w);
  background: var(--sidebar-bg);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  position: fixed;
  inset: 0 auto 0 0;
  z-index: 60;
  transition: transform .22s cubic-bezier(.4, 0, .2, 1);
}

/* Marca do PRODUTO (não do tenant) — wordmark fixo "Agenda King", igual
   em toda instalação; a identidade do TENANT (nome do negócio) mora no
   topbar/menu de perfil, não aqui (ver renderTenantIdentity/openProfileMenu
   em app.js). Fonte cursiva de pincel (Permanent Marker, ver <link> no
   index.html) — mesma escolha tipográfica da V76 para este elemento
   único; nenhum outro texto do painel usa esta fonte. */
.sidebar__brand {
  display: flex;
  align-items: center;
  padding: 14px 18px 12px;
  flex: 0 0 auto;
}
.sidebar__brand-word {
  font-family: 'Permanent Marker', 'Segoe Print', 'Arial Black', Impact, sans-serif;
  font-size: 21px; line-height: 1.15; color: var(--brand-word); letter-spacing: .015em;
}
.sidebar__brand-sub { font-size: 10.5px; color: var(--text-3); margin-top: 2px; }
/* Compat: telas antigas ainda podem referenciar estas classes por engano
   — mantidas sem efeito visual (o logo do tenant não mora mais aqui). */
.sidebar__logo, .sidebar__name, .sidebar__sub { display: none; }

.sidebar__nav { flex: 1 1 auto; overflow-y: auto; padding: 4px 12px 20px; }
/* ---- menu em árvore: pasta (grupo) e filhos (itens), no vocabulário
   visual da V76 (nav-group/nav-parent/nav-sub/nav-subitem) aplicado aos
   mesmos seletores/estrutura de sempre (.nav__pasta/.nav__cabeca/
   .nav__filhos/.nav__item) — trocar só a classe quebraria a lógica de
   colapso/gaveta mobile/acessibilidade já testada; o resultado visual é
   que muda. */
.nav__pasta { margin-bottom: 3px; }
.nav__cabeca {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 8px 13px; border: 1px solid transparent; border-radius: 9px;
  background: transparent; color: var(--nav-parent-ink);
  font: inherit; font-size: 14px; font-weight: 650;
  cursor: pointer; text-align: left; min-height: 36px;
  transition: background .12s, color .12s, border-color .12s;
}
.nav__cabeca:hover { background: rgba(212, 162, 96, .07); color: var(--nav-active-ink); }
.nav__cabeca > span:first-of-type { flex: 1 1 auto; min-width: 0; }
.nav__cabeca svg { width: 17px; height: 17px; flex: 0 0 17px; opacity: .85; color: currentColor; }
.nav__seta {
  display: flex; flex: 0 0 auto; opacity: .8; font-weight: 700;
  transition: transform .18s ease;
}
.nav__seta svg { width: 14px; height: 14px; }
.nav__pasta.is-aberta > .nav__cabeca {
  color: var(--nav-active-ink); font-weight: 700;
  background: var(--nav-active-bg);
  border-color: var(--nav-active-border);
  box-shadow: inset 0 -2px 0 0 var(--nav-active-glow);
}
.nav__pasta.is-aberta > .nav__cabeca .nav__seta { transform: rotate(90deg); }

/* a pasta que contém a página aberta fica marcada, mesmo recolhida */
.nav__pasta:has(.nav__item.is-active) > .nav__cabeca { color: var(--nav-active-ink); }

.nav__filhos {
  height: 0; overflow: hidden;
  transition: height .18s ease;
  margin: 4px 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 3px;
}
.nav__pasta.is-aberta > .nav__filhos { height: auto; }
.nav__filhos .nav__item { font-size: 13px; font-weight: 650; padding: 7px 10px 7px 13px; }
.nav__filhos .nav__cabeca { font-size: 13px; padding: 7px 10px; }

@media (prefers-reduced-motion: reduce) {
  .nav__filhos, .nav__seta { transition: none; }
}
.nav__item {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 10px 7px 13px; border-radius: 7px;
  color: var(--nav-sub-ink); background: rgba(212, 162, 96, .08);
  font-size: 13px; font-weight: 650;
  cursor: pointer; user-select: none; margin-bottom: 0;
  transition: background .12s, color .12s;
}
.nav__item:hover { background: rgba(212, 162, 96, .16); color: var(--nav-active-ink); }
/* O item ATIVO de verdade (fundo tênue + texto na marca + barra à
   esquerda) já foi refinado numa rodada anterior — ver bloco "SIDEBAR —
   refinamento" mais abaixo neste arquivo. Não duplicar a regra aqui. */
.nav__item.is-active svg { opacity: 1; }
.nav__item svg { width: 15px; height: 15px; flex: 0 0 15px; opacity: .85; color: currentColor; }
.nav__badge {
  margin-left: auto; color: var(--paper);
  /*
   * --red-action, não var(--red): no escuro --red é a versão CLARA do
   * estado — clara de propósito, para servir de TEXTO sobre superfície
   * escura (é o mesmo motivo do --brand-action, documentado lá em cima).
   * Como FUNDO sólido com texto claro em cima ela reprova o mínimo de
   * 4,5:1. --red-action é justamente o papel de fundo sólido: mesmo
   * vermelho escuro nos dois temas, então esta bolinha continua com a
   * mesma cor em claro e escuro, agora via token em vez de hex cravado.
   * Mesmo ajuste em .topbar__badge, que tem o mesmo formato.
   */
  background: var(--red-action);
  font-size: 10.5px; font-weight: 700; padding: 1px 6px; border-radius: var(--r-full);
}
.nav__lock { margin-left: auto; opacity: .45; width: 14px; height: 14px; }

.sidebar__context { display: none; }
.sidebar__footer { flex: 0 0 auto; border-top: 1px solid var(--border); padding: 10px; }
.drawer-profile {
  display: flex; align-items: center; gap: 9px; width: 100%; padding: 7px 4px;
  border: 0; background: transparent; color: var(--text); font: inherit; text-align: left; cursor: pointer;
}
.drawer-profile:hover { color: var(--brand-text, var(--brand)); }
.drawer-profile__copy { display: flex; flex: 1 1 auto; min-width: 0; flex-direction: column; gap: 1px; font-size: 13px; font-weight: 650; }
.drawer-profile__copy small { color: var(--text-3); font-size: 11px; font-weight: 500; }
.drawer-profile > svg { width: 15px; height: 15px; color: var(--text-3); }
.topbar__mobile-brand { display: none; }

.main { flex: 1 1 auto; min-width: 0; margin-left: var(--sidebar-w); display: flex; flex-direction: column; }

/*
 * Redesign Fase 3 — sidebar colapsável (~252px ↔ ~64px).
 *
 * A troca de largura é UMA declaração: redefinir --sidebar-w na raiz. Como
 * `.sidebar` e `.main` já leem `var(--sidebar-w)` (linhas acima), os dois
 * acompanham sozinhos — não existe risco de um lado atualizar e o outro
 * não. A classe fica no <html> (não num wrapper interno) pelo mesmo motivo
 * do tema: precisa existir ANTES do primeiro paint (ver script no <head>
 * de app/index.html), e só `document.documentElement` existe naquele
 * momento.
 */
/*
 * Achado de auditoria: este bloco inteiro não tinha guarda de largura —
 * o estado "recolhida" (coluna fixa de 64px, só ícone) só faz sentido no
 * desktop. Sem a guarda, colapsar a sidebar no desktop e depois abrir o
 * painel (ou redimensionar) abaixo de 900px herdava a gaveta mobile sem
 * legenda nenhuma e sem o botão de desfazer (que já some no mobile, ver
 * .btn.sidebar-toggle abaixo). A gaveta mobile já tem largura própria
 * fixa (min(300px,86vw)) desenhada com espaço de sobra pros rótulos, então
 * a guarda não tira nada do mobile — só impede o estado colapsado de
 * vazar pra lá.
 */
@media (min-width: 901px) {
  html.sb-collapsed { --sidebar-w: 64px; }

  html.sb-collapsed .sidebar__brand { padding: 14px 8px 12px; justify-content: center; }
  html.sb-collapsed .sidebar__brand-sub { display: none; }
  html.sb-collapsed .sidebar__brand-word { font-size: 15px; }
  html.sb-collapsed .sidebar__nav { padding: 4px 8px 20px; }
  html.sb-collapsed .nav__item,
  html.sb-collapsed .nav__cabeca { justify-content: center; padding: 9px; gap: 0; }
  html.sb-collapsed .nav__item span,
  html.sb-collapsed .nav__cabeca span:first-of-type,
  html.sb-collapsed .nav__seta,
  html.sb-collapsed .nav__badge,
  html.sb-collapsed .nav__lock { display: none; }
  /* Sem espaço pros filhos aparecerem — ver comportamento de clique em
     app.js: clicar num ícone de pasta recolhida expande a sidebar E abre a
     pasta no mesmo gesto, então o conteúdo nunca fica inacessível. */
  html.sb-collapsed .nav__filhos { display: none; }
  html.sb-collapsed .sidebar__footer .nav__item { justify-content: center; }
  html.sb-collapsed .sidebar__footer .nav__item span { display: none; }
  html.sb-collapsed .sidebar__footer #navTeste { padding: 9px; }
}

.topbar {
  height: var(--topbar-h);
  background: var(--topbar-bg);
  border-bottom: 1px solid var(--border);
  box-shadow: var(--topbar-hairline);
  display: flex; align-items: center; gap: 12px;
  padding: 0 24px;
  position: sticky; top: 0; z-index: 40;
}
.topbar__title { font-size: 18px; font-weight: 800; letter-spacing: -.005em; min-width: 0; color: var(--text); }
.topbar__spacer { flex: 1 1 auto; }
/*
 * Fase 3.2, achado real: `.topbar__burger{display:none}` e
 * `.sidebar-toggle{display:none}` (dentro do media query mobile, mais
 * abaixo) têm a MESMA especificidade de `.btn{display:inline-flex}` —
 * e `.btn` vem depois no arquivo. Empate de especificidade é ordem no
 * arquivo que decide, então `.btn` sempre vencia e os dois botões
 * ficavam visíveis em TODA largura, nunca escondidos. `.btn.` na frente
 * dá a especificidade que faltava, nos dois lados (aqui e no media
 * query) — sem isso, corrigir só um lado inverteria o bug.
 */
.btn.topbar__burger { display: none; }
/* Espelho do burger: aparece só no desktop, onde a sidebar é uma coluna
   fixa (no mobile ela é gaveta — recolher não faz sentido, ver media
   query abaixo que esconde este botão junto com o resto do layout fixo). */
.btn.sidebar-toggle { display: inline-flex; }
.topbar__novo span { margin-left: 2px; }

/* Escolha de tema de 3 posições, dentro do menu de perfil — mesmo
   controle da V76 (.ak-theme-choice). */
.theme-choice { padding: 3px; display: flex; border: 1px solid var(--border-strong); border-radius: 999px; background: var(--surface-2); }
.theme-choice button {
  width: 33px; height: 31px; border: 0; border-radius: 999px; color: var(--text-3);
  background: transparent; cursor: pointer; display: grid; place-items: center;
}
.theme-choice button svg { width: 16px; height: 16px; }
.theme-choice button.is-active { color: var(--brand-fg); background: var(--icon-accent); }

/* Botões-ícone do topbar (link do site, sino, alternar sidebar) no
   vocabulário V76 (".icon-btn"): sem moldura/fundo, ícone sempre dourado
   — escopado a `.topbar` para não mudar nenhum outro `.btn--icon` do
   resto do painel (centenas de usos fora daqui). */
.topbar .btn--ghost.btn--icon,
.topbar .btn.sidebar-toggle {
  border-color: transparent; background: transparent; color: var(--icon-accent);
}
.topbar .btn--ghost.btn--icon:hover,
.topbar .btn.sidebar-toggle:hover { background: rgba(212, 162, 96, .1); border-color: transparent; }

.topbar__bell { position: relative; }
.topbar__badge {
  position: absolute; top: 3px; right: 3px; min-width: 15px; height: 15px;
  padding: 0 3px; border-radius: var(--r-full);
  /*
   * --red-action, não var(--red): no escuro --red é a versão CLARA do
   * estado, feita para servir como TEXTO sobre fundo escuro. Como FUNDO
   * sólido com texto claro em cima ela reprova o mínimo de 4,5:1.
   * --red-action é o papel de fundo sólido — mesmo vermelho escuro nos
   * dois temas — então esta bolinha continua igual em claro e escuro,
   * agora via token em vez de hex cravado.
   */
  background: var(--red-action); color: var(--paper);
  font-size: 9.5px; font-weight: 700; line-height: 15px; text-align: center;
  border: 2px solid var(--surface);
}

/* Identidade do tenant ativo, no topbar (desktop) — vocabulário visual
   V76 (".account"): pílula escura própria, não a superfície genérica do
   painel, com o mesmo contraste em qualquer tema. */
.tenant-pill {
  display: flex; align-items: center; gap: 8px; padding: 4px 10px 4px 4px;
  border-radius: var(--r-full); border: 1px solid var(--account-border); background: var(--account-bg);
  color: var(--text); cursor: pointer; max-width: 210px;
}
.tenant-pill:hover { border-color: var(--nav-active-glow); }
.tenant-pill svg { width: 15px; height: 15px; flex: 0 0 auto; opacity: .6; }
.tenant-pill__info { display: flex; flex-direction: column; min-width: 0; align-items: flex-start; line-height: 1.25; }
.tenant-pill__name { font-size: 13px; font-weight: 650; max-width: 140px; }
.tenant-pill__role { font-size: 11px; color: var(--text-3); }

/* Contexto ativo abaixo da topbar em telas estreitas. */
.mobile-shell-context, .mobile-context { display: none; }

/* Mesma identidade, cartão abaixo da topbar — só no mobile */
.tenant-card-mobile { display: none; }

/*
 * Fase 3.2 — TABLET (901-1280px).
 *
 * Entre o breakpoint mobile (900px, sidebar vira gaveta) e ~1280px
 * (--page--conteudo, já usado como "largura confortável" no resto do
 * painel) a topbar ficava em modo desktop completo — sidebar-toggle +
 * título + "+ Novo" com texto + link + sino + tema + pílula com nome e
 * cargo — sem nenhuma acomodação. Medido: em 1024px isso sozinho (mais
 * o bug de especificidade corrigido acima) já bastava para a barra
 * precisar de ~920px num espaço de 762px.
 *
 * Aqui só ENCOLHE o que sobra sem remover o que funciona: "+ Novo" e a
 * pílula do tenant perdem o texto, viram ícone/avatar com tooltip
 * (rótulo acessível continua no aria-label, aplicado em app.js).
 * Nada disso aparece abaixo de 900px porque os dois já são
 * display:none no mobile (ver bloco @media 900px mais abaixo) — a
 * pílula vira o cartão de linha inteira, "+ Novo" vira o FAB da
 * bottomnav.
 */
@media (max-width: 1280px) {
  .topbar { gap: 8px; }
  .topbar__novo span { display: none; }
  /* Achado de auditoria: só a largura era fixada em 38px aqui; a altura
     continuava herdando .btn--sm (32px), enquanto os botões-ícone vizinhos
     (#btnSite/#btnBell/#btnTheme/.sidebar-toggle, todos .btn--icon sem
     --sm) medem 38×38 — quebrava a fileira por 6px entre 901-1280px. */
  .topbar__novo { padding: 0; width: 38px; height: 38px; }
  .tenant-pill { max-width: none; padding: 5px 6px; gap: 0; }
  .tenant-pill__info { display: none; }
}

/*
 * Entrada de página: cada rota substitui o innerHTML do outlet inteiro,
 * então o `.page` novo é sempre um nó recém-criado — a animação CSS
 * dispara sozinha a cada troca de rota, sem precisar de nenhuma classe
 * ou lógica em app.js. Curta o bastante para nunca atrasar a leitura do
 * conteúdo (ele já está lá, só a opacidade/posição estão em transição).
 */
@keyframes pageEnter { from { opacity: 0; transform: translateY(4px); } }
.page { padding: 20px; flex: 1 1 auto; max-width: 1500px; width: 100%;
  animation: pageEnter var(--motion-base) var(--ease-standard); }
@media (prefers-reduced-motion: reduce) {
  .page { animation: none; }
}
.page--flush { padding: 0; max-width: none; }
/* Fase 3.1: 1500px serve a Agenda (grade, quer a largura toda) mas deixa
   card/KPI de tela administrativa esticado feio em monitor grande — a
   régua não precisa ser a mesma para as duas coisas. */
.page--conteudo { max-width: 1280px; }

/* --------------------------------------------------------------- MOBILE */
.backdrop {
  position: fixed; inset: 0; background: rgba(8, 7, 6, .5);
  z-index: 55; opacity: 0; pointer-events: none; transition: opacity .2s;
  backdrop-filter: blur(2px);
}
.backdrop.is-open { opacity: 1; pointer-events: auto; }

.bottomnav { display: none; }

@media (max-width: 900px) {
  body.drawer-open { overflow: hidden; }
  .backdrop { transition: none; }
  .sidebar { transform: translateX(-100%); box-shadow: var(--sh-3); transition: none; }
  .sidebar.is-open { transform: translateX(0); }
  .main { margin-left: 0; }
  .btn.topbar__burger { display: none; }
  .btn.sidebar-toggle { display: none; }
  .topbar { height: 56px; padding: 0 12px; gap: 8px; }
  .topbar__mobile-brand { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1 1 auto; }
  .topbar__mobile-logo {
    width: 30px; height: 30px; border-radius: 9px; flex: 0 0 30px;
    display: grid; place-items: center; background: linear-gradient(155deg, var(--gold-2), var(--brand)); color: var(--brand-fg);
  }
  .topbar__mobile-logo svg { width: 17px; height: 17px; stroke-width: 2.1; }
  .topbar__mobile-copy { min-width: 0; line-height: 1.15; }
  .topbar__mobile-name { font-size: 14px; font-weight: 750; letter-spacing: -.015em; white-space: nowrap; }
  .topbar__mobile-sub { font-size: 10.5px; color: var(--text-3); white-space: nowrap; }
  .topbar__title { display: none; }
  .topbar__spacer { display: none; }
  .sidebar__context {
    display: flex; flex-direction: column; gap: 8px; padding: 11px 12px;
    border-bottom: 1px solid var(--border); background: var(--surface);
  }
  .drawer-context__tenant { display: flex; align-items: center; gap: 9px; min-width: 0; }
  .drawer-context__copy { display: flex; flex: 1 1 auto; min-width: 0; flex-direction: column; gap: 1px; }
  .drawer-context__name { font-size: 13.5px; font-weight: 700; }
  .drawer-context__role { font-size: 11px; color: var(--text-3); }
  .drawer-context__field { display: grid; grid-template-columns: 60px minmax(0, 1fr); align-items: center; gap: 8px; color: var(--text-2); font-size: 11.5px; font-weight: 650; }
  .drawer-context__field .select { height: 34px; padding-top: 0; padding-bottom: 0; background-color: var(--surface-2); }
  .drawer-context__reset { align-self: flex-start; padding: 2px 0; border: 0; background: transparent; color: var(--text-3); font: inherit; font-size: 11.5px; cursor: pointer; }
  .drawer-context__reset:hover { color: var(--brand-text, var(--brand)); }
  .sidebar__nav { padding-top: 8px; }
  .sidebar__footer { padding-bottom: calc(10px + env(safe-area-inset-bottom)); }
  #topbarActions { margin-left: auto; min-width: 0; gap: 2px; }
  #topbarActions .btn--icon { width: 34px; height: 34px; }
  #topbarActions #btnSite { display: none; }
  /*
   * Achado real (iPhone físico, Mobile QA V18.3): esta margem inferior
   * nunca somava env(safe-area-inset-bottom), mas o .bottomnav logo
   * abaixo CRESCE exatamente por essa mesma variável em iPhone com
   * notch/home indicator (.bottomnav { height: calc(var(--bottomnav-h)
   * + env(safe-area-inset-bottom)) }). O FAB ainda soma mais 18px pra
   * cima disso (margin-top:-18px). Resultado: em Chromium sem notch
   * simulado a margem de 20px sobrava e nada vazava — em iPhone real,
   * o fim de qualquer página rolável (aqui, os botões do cartão de
   * pré-visualização no onboarding) ficava atrás do FAB/bottomnav,
   * sem como rolar mais pra revelar. Faltava o mesmo termo que o
   * próprio .bottomnav já usa.
   */
  .page { padding: 14px 14px calc(var(--bottomnav-h) + 20px + env(safe-area-inset-bottom)); }

  .tenant-pill { display: none; }
  a.topbar__novo { display: none; }

  .bottomnav {
    display: flex;
    position: fixed; inset: auto 0 0 0; z-index: 50;
    height: calc(var(--bottomnav-h) + env(safe-area-inset-bottom));
    padding-bottom: env(safe-area-inset-bottom);
    background: var(--topbar-bg);
    border-top: 1px solid var(--border);
  }
  .bottomnav__item {
    flex: 1 1 0; display: flex; flex-direction: column;
    align-items: center; justify-content: center; gap: 3px;
    border: 0; background: transparent; font: inherit;
    font-size: 10.5px; font-weight: 600; color: var(--text-3);
    cursor: pointer; padding-top: 6px;
  }
  .bottomnav__item svg { width: 21px; height: 21px; }
  .bottomnav__item.is-active,
  .bottomnav__item.is-open { color: var(--icon-accent); }
  .bottomnav__fab {
    flex: 0 0 auto;
    width: 52px;
    height: 46px;
    margin: -10px 6px 0;
    display: grid;
    place-items: center;
    border: 1px solid color-mix(in srgb, var(--brand-action) 78%, var(--surface));
    border-radius: var(--r-md);
    background: var(--brand-action);
    color: var(--brand-fg);
    box-shadow: 0 5px 14px color-mix(in srgb, var(--brand-action) 22%, transparent);
  }
  .bottomnav__fab svg { width: 22px; height: 22px; }
  h1 { font-size: 20px; }
}

/* ---------------------------------------------------------------- CARDS */
/*
 * Migração visual v76: a microtextura (antes só em .page--dashboard ou
 * via .card--textured explícito) passa a ser o padrão de QUALQUER .card
 * — mesmo tratamento que .kpi já recebia em todas as páginas (ver
 * .kpis > .kpi abaixo). A regra de sempre continua valendo: formulários,
 * tabelas, menus e modais comuns continuam lisos (usam --surface/--card
 * diretamente, nunca .card) para não competir com o conteúdo.
 */
.card {
  background:
    linear-gradient(135deg, var(--card-highlight), transparent 42%),
    repeating-linear-gradient(135deg, var(--card-texture) 0 1px, transparent 1px 12px),
    var(--card);
  /* v76: borda com leve tinta dourada (na referência era o dourado antigo
     a 42%), não cinza neutro — mesmo valor usado em .kpi abaixo. A tinta
     agora sai de --brand, então acompanha a paleta V81 nos dois temas. */
  border: 1px solid color-mix(in srgb, var(--brand) 20%, var(--border));
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
}
.card--textured,
.page--dashboard .card {
  background:
    linear-gradient(135deg, var(--card-highlight), transparent 42%),
    repeating-linear-gradient(135deg, var(--card-texture) 0 1px, transparent 1px 12px),
    var(--card);
}
.card__head {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 16px; border-bottom: 1px solid var(--border);
}
.card__title { font-size: 14.5px; font-weight: 650; }
.card__body { padding: 16px; }
.card__foot { padding: 12px 16px; border-top: 1px solid var(--border); background: var(--surface-2); border-radius: 0 0 var(--r-lg) var(--r-lg); }

.grid { display: grid; gap: 14px; }
.grid--kpi { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
/* 320px de mínimo era maior que o próprio menor celular suportado (320px
   de VIEWPORT, menos padding da página — nunca cabe). Todo outro
   .grid--N do arquivo usa 190-260px; alinhado aqui. */
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

/* Faixa de indicadores. Onze telas ja escreviam class="kpis" sem que a
   classe existisse no CSS: o resultado era numero solto empilhado no canto
   esquerdo, com a tela inteira vazia ao lado. A definicao aqui e a mesma
   grade e a mesma casca de cartao que o dashboard sempre usou. */
/* Quatro por linha no desktop, sempre. Com auto-fill a tela larga cabia
   sete cartões e deixava o oitavo sozinho embaixo — linha quebrada é a
   primeira coisa que denuncia tela pela metade. */
/*
 * Achado real (varredura de design, print do usuário): .kpis nunca teve
 * margin-bottom próprio — cada tela dependia de lembrar de embrulhar a
 * chamada de kpiGrid() numa div com mb-N, e a maioria não fazia isso. O
 * efeito era a linha de KPIs colada na próxima seção/card, parecendo um
 * bloco só. Nenhuma tela envolve kpiGrid() com margem própria hoje
 * (conferido), então a margem entra aqui sem risco de dobrar espaço.
 */
.kpis { display: grid; gap: 14px; grid-template-columns: repeat(4, minmax(0, 1fr)); margin-bottom: var(--sp-5); }
.kpis > .kpi, .grid--kpi > .kpi {
  background:
    linear-gradient(135deg, var(--card-highlight), transparent 42%),
    repeating-linear-gradient(135deg, var(--card-texture) 0 1px, transparent 1px 12px),
    var(--card);
  border: 1px solid color-mix(in srgb, var(--brand) 20%, var(--border)); border-radius: var(--r-lg); box-shadow: var(--sh-1);
  min-height: 96px;                 /* mesma altura entre telas */
}
.kpi { padding: 15px 16px; }
/* Números grandes não podem empurrar a coluna: o cartão corta, não estica.
   Achado de auditoria: .grid--kpi (14 usos hand-rolled fora de kpiGrid())
   usava os mesmos nomes de classe internos (.kpi__value etc) sem herdar
   essa proteção — estendida aqui pelos mesmos seletores.
   Achado (Mobile QA V18.1): essa proteção cortava o PRÓPRIO valor em
   reticências — "-R$ 999...." — escondendo o número real num painel
   financeiro, o pior lugar possível pra isso. .kpi__hint (texto de
   apoio) continua cortando: informação secundária, não crítica.
   .kpi__value quebra pra 2 linhas em vez de truncar: a coluna ainda
   não estica (grid track continua com minmax(0,1fr), fixado abaixo),
   só a linha fica mais alta — nunca esconde o valor.
   Achado (iPhone físico, Mobile QA V18.4): .kpi__label é display:flex
   (pra comportar um ícone opcional dentro do próprio rótulo — ver
   `.kpi__label svg` mais abaixo). text-overflow:ellipsis não renderiza
   o "…" dentro de um container flex na maioria dos motores — o
   overflow:hidden ainda corta o texto (então não vaza pra fora da
   caixa), mas sem o "…" o corte cai no meio de uma palavra ("receita
   d") bem em cima de onde o ícone.kpi__ico (position:absolute) fica —
   lido à primeira vista como o ícone "comendo" o texto. .kpi__label
   passa a quebrar linha, mesmo tratamento do valor.
   Achado (FECHAMENTO GLOBAL, sweep real 320px): nenhum caller hoje bota
   ícone dentro do texto do label (grep confirmado) — o display:flex
   ficou só como órfão, e é ele quem causa a quebra: um item flex sem
   min-width explícito não encolhe abaixo do min-content do seu próprio
   texto, então overflow-wrap:break-word acima nunca chegava a agir
   (palavra única como "Recorrentes" vazava do cartão em vez de quebrar
   — achado ao vivo em Retenção/Dashboard). display:block resolve sem
   precisar re-testar cada tela: nada muda pro caso sem ícone (100% dos
   casos reais), e o dia que alguém precisar de ícone dentro do label de
   novo, essa regra volta a ganhar sentido. */
.kpis .kpi__hint, .grid--kpi .kpi__hint {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kpis .kpi__value, .grid--kpi .kpi__value,
.kpis .kpi__label, .grid--kpi .kpi__label {
  overflow-wrap: break-word; white-space: normal;
}

@media (max-width: 1024px) { .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px) {
  .grid--2, .grid--3 { grid-template-columns: 1fr; }
  .kpis { grid-template-columns: 1fr; gap: 9px; }
  .kpis > .kpi, .grid--kpi > .kpi { padding: 12px 13px; min-height: 0; }
  .kpis .kpi__value, .grid--kpi .kpi__value { font-size: 21px; }
}
.kpi__label { font-size: 12.5px; color: var(--text-2); font-weight: 550; }
.kpi__value { font-size: 25px; font-weight: 700; letter-spacing: -.03em; margin-top: 6px; line-height: 1.1; }
.kpi__hint { font-size: 12.5px; color: var(--text-3); margin-top: 4px; }
.kpi__delta { font-size: 12px; font-weight: 650; display: inline-flex; align-items: center; gap: 3px; }
.kpi__delta.up { color: var(--green); }
.kpi__delta.down { color: var(--red); }

/* -------------------------------------------------------------- CONTROLS */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: 38px; padding: 0 15px;
  border-radius: var(--r-sm); border: 1px solid var(--border-strong);
  background: var(--surface); color: var(--text);
  font-size: 14px; font-weight: 600; cursor: pointer;
  transition: filter .12s, background .12s, opacity .12s, border-color .12s;
  white-space: nowrap;
}
.btn--icon { color: var(--icon-accent); }
.btn--icon.btn--primary, .btn--icon.btn--danger { color: inherit; }
.btn:hover { background: var(--surface-3); }
.btn:active { transform: translateY(.5px); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn svg { width: 16px; height: 16px; }

.btn--primary { background: var(--brand-action); color: var(--brand-fg); border-color: transparent; }
/*
 * Comentário original (pré-troca de paleta) media este hover contra
 * texto BRANCO em --brand-action — não se aplica mais: --brand-fg agora
 * é escuro (troca de paleta, ver comentário em [data-theme='dark']), e
 * clarear o fundo só AUMENTA o contraste com texto escuro. 1.06 segue
 * sendo só a diferença visível escolhida, sem limite de contraste
 * empurrando o valor (ao contrário do que era antes, e do que ainda é
 * o caso em .btn--danger, logo abaixo).
 *
 * O `background` se repete aqui porque `.btn:hover` tem duas classes de
 * especificidade e venceria `.btn--primary` sozinho, devolvendo o botão
 * ao cinza de superfície.
 */
.btn--primary:hover { background: var(--brand-action); filter: brightness(1.06); }
.btn--danger { background: var(--red-action); color: var(--paper); border-color: transparent; }
/*
 * Mesmo cuidado do hover de --brand-action (comentário acima): clarear
 * custa contraste, e o hover também precisa passar. 1.1 (valor antigo)
 * derrubava o par --red-action + --paper para abaixo do mínimo de 4,5:1
 * — reprova. 1.03 preserva a margem e ainda é uma mudança perceptível
 * num vermelho já saturado.
 */
.btn--danger:hover { filter: brightness(1.03); background: var(--red-action); }
.btn--ghost { background: transparent; border-color: transparent; }
.btn--ghost:hover { background: var(--surface-3); }
.btn--sm { height: 32px; padding: 0 11px; font-size: 13px; border-radius: var(--r-sm); }
/* Fase 3.3, achado real: dentro de um flex apertado (a topbar no
   celular), um botão-ícone sem flex-shrink:0 encolhe — o burger chegou a
   ~25px de largura em vez dos 38px daqui, um alvo de toque ruim demais
   pra ser o único jeito de abrir o menu. Texto pode truncar; ícone não
   tem "versão menor" que continue tocável, então nunca encolhe. */
.btn--icon { width: 38px; padding: 0; flex-shrink: 0; }
.btn--icon.btn--sm { width: 32px; }
.btn--block { width: 100%; }
.btn--lg { height: 46px; font-size: 15px; padding: 0 20px; }
/* Achado de auditoria: estado "selecionado" de um .btn usado como
   filtro/toggle usava .btn--primary condicionalmente em 2 telas — a mesma
   cor reservada pra "ação principal" também virava "selecionado", sem
   distinção visual entre os dois papéis. Classe neutra dedicada. */
.btn.is-active { background: var(--surface-3); border-color: var(--border-strong); }

.field { display: block; margin-bottom: 14px; }
.field__label { display: block; font-size: 12.5px; font-weight: 600; color: var(--text-2); margin-bottom: 5px; }
.field__hint { font-size: 12.5px; color: var(--text-3); margin-top: 4px; }
.field__error { font-size: 11.5px; color: var(--red); margin-top: 4px; }

.input, .select, .textarea {
  width: 100%; height: 40px; padding: 0 12px;
  background: var(--card); color: var(--text);
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  outline: none; transition: border-color .12s, box-shadow .12s;
}
.textarea { height: auto; min-height: 84px; padding: 10px 12px; resize: vertical; line-height: 1.5; }
.input:focus, .select:focus, .textarea:focus {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 18%, transparent);
}
.input::placeholder, .textarea::placeholder { color: var(--text-3); }
/* Achado de auditoria: não havia nenhuma regra de estado disabled/readonly
   para campo de texto — um <input disabled> (ex. data/hora de agendamento
   já criado) ficava visualmente idêntico a um campo editável. */
.input:disabled, .select:disabled, .textarea:disabled, .input[readonly] {
  background: var(--surface-3); color: var(--text-disabled); cursor: not-allowed;
}
.select { appearance: none; cursor: pointer; padding-right: 32px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2.5' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 10px center; background-size: 15px; }

/*
 * Fase 3.3, bug real confirmado por medição: `.input`/`.select`/
 * `.textarea` herdam o font-size do body (15px) — abaixo dos 16px que
 * o Safari/iOS exige para NÃO dar zoom automático ao focar um campo.
 * Só no mobile (onde o teclado do sistema realmente abre) e só nos
 * controles editáveis — rótulo, dica, card, corpo do texto continuam
 * no tamanho de sempre. `.input--sm`/`.select--sm` (de servicos.css,
 * 13px/32px) têm a correção correspondente lá, não aqui — são regras
 * sem media query, carregadas DEPOIS deste arquivo, e uma regra daqui
 * dentro de @media perderia para elas na mesma especificidade.
 */
@media (max-width: 900px) {
  .input, .select, .textarea { font-size: 16px; }
  /* Achado de auditoria (font-size scale cleanup): .hora__campo (input de
     horário do editor de jornada) e .rev__linkCampo .input (campo do link
     do site) têm font-size próprio declarado DEPOIS da regra acima, então
     ganhavam na mesma especificidade e escapavam do fix de zoom do
     Safari/iOS — mesmo motivo já documentado para .input--sm/.select--sm
     duas linhas acima, resolvido aqui do mesmo jeito. */
  .hora__campo, .rev__linkCampo .input { font-size: 16px; }
}

.row { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; }
.row > .field { flex: 1 1 190px; margin-bottom: 0; }
.stack { display: flex; flex-direction: column; gap: 12px; }
.inline { display: flex; align-items: center; gap: 8px; }
.inline--wrap { flex-wrap: wrap; }
.spacer { flex: 1 1 auto; }

.switch { display: inline-flex; align-items: center; gap: 9px; cursor: pointer; user-select: none; }
.switch input { position: absolute; opacity: 0; pointer-events: none; }
.switch__track {
  width: 40px; height: 23px; border-radius: 99px; background: var(--border-strong);
  position: relative; transition: background .16s; flex: 0 0 auto;
}
.switch__track::after {
  content: ''; position: absolute; top: 2.5px; left: 2.5px;
  width: 18px; height: 18px; border-radius: 50%; background: var(--paper);
  transition: transform .16s; box-shadow: var(--sh-1);
}
.switch input:checked + .switch__track { background: var(--green); }
.switch input:checked + .switch__track::after { transform: translateX(17px); }
.switch__label { font-size: 13.5px; font-weight: 500; }

.check { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: 14px; }
.check input { width: 17px; height: 17px; accent-color: var(--brand); cursor: pointer; }

.segmented {
  display: inline-flex; background: var(--surface-3); padding: 3px;
  border-radius: var(--r-sm); gap: 2px;
}
.segmented button {
  display: inline-flex; align-items: center; gap: 6px;
  border: 0; background: transparent; color: var(--text-2);
  padding: 6px 12px; border-radius: 6px; font-size: 13px; font-weight: 600; cursor: pointer;
  font-family: inherit;
}
.segmented button.is-active { background: var(--surface); color: var(--text); box-shadow: var(--sh-1); }
/*
 * icon() devolve <svg> sem width/height: quem dimensiona é o contexto.
 * Faltava esta linha, e o alternador Cards/Tabela virava um quadrado
 * disforme sem identificação em Profissionais, Clientes e Serviços.
 */
.segmented button svg { width: 16px; height: 16px; flex: 0 0 16px; }
/* No celular o rótulo sai e fica só o ícone, que aí já tem tooltip */
@media (max-width: 640px) { .segmented__txt { display: none; } }

/* ---------------------------------------------------------------- TABLE */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.table { width: 100%; border-collapse: collapse; font-size: 14px; }
.table th {
  text-align: left; font-size: 11.5px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-3);
  padding: 10px 14px; border-bottom: 1px solid var(--border); white-space: nowrap;
}
.table td { padding: 12px 14px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr.is-clickable { cursor: pointer; }
.table tbody tr.is-clickable:hover { background: var(--surface-2); }
/* Linha com checkbox de seleção em lote marcado — mesma técnica :has()
   já usada em outras partes do CSS do projeto. */
.table tbody tr:has(input[data-sel]:checked) { background: var(--surface-2); }
.table .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.table tfoot td { font-weight: 700; border-top: 2px solid var(--border-strong); border-bottom: 0; }

/*
 * Fase 2 do Relatório Gerencial — tabela analítica no mobile.
 *
 * .table-wrap com overflow-x:auto (acima) resolve o desktop e o tablet,
 * mas no celular uma tabela de 15 colunas rolando na horizontal é
 * inutilizável — a pessoa não compara linha com cabeçalho. Abaixo de
 * 900px (mesmo corte da sidebar virar gaveta) a tabela desaparece e um
 * cartão por linha assume, com só o essencial visível e o resto atrás de
 * "Ver detalhes" — mesmo padrão de resumo-e-detalhe do resto do painel.
 */
.tabela-resp__cards { display: none; }
@media (max-width: 900px) {
  .tabela-resp__tabela { display: none; }
  .tabela-resp__cards { display: flex; flex-direction: column; gap: 8px; }
}
.tr-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); padding: 12px 14px; }
.tr-card__linha1 { display: flex; align-items: baseline; gap: 8px; justify-content: space-between; }
.tr-card__titulo { font-weight: 650; font-size: 14px; }
.tr-card__destaque { font-weight: 700; font-variant-numeric: tabular-nums; }
.tr-card__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px 12px; margin-top: 8px; font-size: 12.5px; }
.tr-card__grid .dim { display: block; }
.tr-card__detalhes { margin-top: 8px; padding-top: 8px; border-top: 1px dashed var(--border); display: none; }
.tr-card.is-aberto .tr-card__detalhes { display: block; }
.tr-card__toggle { background: none; border: 0; color: var(--brand-text, var(--brand)); font-size: 12.5px; font-weight: 600; padding: 6px 0 0; cursor: pointer; }

.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: var(--r-full);
  font-size: 11.5px; font-weight: 650; white-space: nowrap;
  background: var(--surface-3); color: var(--text-2);
}
.badge--green { background: var(--green-bg); color: var(--green); }
.badge--red { background: var(--red-bg); color: var(--red); }
.badge--amber { background: var(--amber-bg); color: var(--amber); }
.badge--blue { background: var(--blue-bg); color: var(--blue); }
.badge--violet { background: var(--violet-bg); color: var(--violet); }

/* Selo de Clube dentro do cartão/chip da Agenda — discreto, não pode
   competir com a grade num agendamento de 20px de altura. */
.ag__badge-clube { padding: 1px 6px; font-size: 9.5px; vertical-align: middle; }

.avatar {
  width: 36px; height: 36px; border-radius: 50%; flex: 0 0 auto;
  background: var(--surface-3); color: var(--text-2);
  display: grid; place-items: center; font-size: 13px; font-weight: 700;
  overflow: hidden; text-transform: uppercase;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; }
.avatar--sm { width: 28px; height: 28px; font-size: 11px; }
.avatar--lg { width: 56px; height: 56px; font-size: 19px; }
.avatar--xl { width: 84px; height: 84px; font-size: 28px; }

.progress { height: 7px; border-radius: 99px; background: var(--surface-3); overflow: hidden; }
.progress__bar { height: 100%; border-radius: 99px; background: var(--brand); transition: width .4s; }
.progress__bar.is-good { background: var(--green); }
.progress__bar.is-warn { background: var(--amber); }
.progress__bar.is-bad { background: var(--red); }

/* --------------------------------------------------------------- STATES */
/* .empty/.empty__title/.empty__text/.empty svg: definição ativa mais
   abaixo, seção "STATES" perto de .empty__acoes — achado de auditoria,
   esta era uma versão antiga (padding 44px, ícone 42px) que a de baixo,
   igual em especificidade e mais recente no arquivo, sempre venceu.
   Morta de verdade: nenhum navegador nunca aplicou esta aqui. */

.skeleton {
  background: linear-gradient(90deg, var(--surface-3) 25%, var(--surface-2) 50%, var(--surface-3) 75%);
  background-size: 200% 100%; animation: sk 1.4s infinite; border-radius: 6px;
}
@keyframes sk { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }

.spinner {
  width: 17px; height: 17px; border-radius: 50%;
  border: 2.5px solid color-mix(in srgb, currentColor 25%, transparent);
  border-top-color: currentColor; animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* --------------------------------------------------------------- MODAL */
.modal-root {
  position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; height: 100dvh;
  z-index: 200; display: none;
}
.modal-root.is-open { display: block; }
.modal__overlay { position: absolute; inset: 0; background: rgba(8, 7, 6, .55); backdrop-filter: blur(3px); animation: fade .16s; }
.modal {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: min(560px, calc(100vw - max(28px, env(safe-area-inset-left) + env(safe-area-inset-right) + 28px)));
  max-height: calc(100vh - max(60px, env(safe-area-inset-top) + env(safe-area-inset-bottom) + 60px));
  /*
   * Auditoria WebKit (Mobile QA V18.2): 100vh no Safari iOS é calculado
   * contra o viewport de LAYOUT (assume a barra de endereço escondida),
   * não o visual — com a barra visível, o valor real disponível na tela
   * é menor que 100vh calcula. Um modal alto o bastante pra encostar no
   * teto de max-height ficava com o rodapé (botões) atrás da barra do
   * Safari, inacessível sem a barra recolher sozinha. dvh acompanha o
   * viewport visual de verdade; a linha de 100vh acima fica como
   * fallback pra navegador sem suporte a dvh (regra depois vence).
   */
  max-height: calc(100dvh - max(60px, env(safe-area-inset-top) + env(safe-area-inset-bottom) + 60px));
  background: var(--surface); border-radius: var(--r-xl); box-shadow: var(--sh-3);
  display: flex; flex-direction: column; overflow: hidden; animation: pop .18s cubic-bezier(.3, 1.3, .6, 1);
}
.modal--wide { width: min(880px, calc(100vw - max(28px, env(safe-area-inset-left) + env(safe-area-inset-right) + 28px))); }
.modal__head { display: flex; align-items: center; gap: 10px; padding: 16px 18px; border-bottom: 1px solid var(--border); }
.modal__title { font-size: 16.5px; font-weight: 650; }
.modal__body { padding: 18px; overflow-y: auto; flex: 1 1 auto; }
.modal__foot { padding: 13px 18px; border-top: 1px solid var(--border); display: flex; gap: 9px; justify-content: flex-end; background: var(--surface-2); }
@keyframes fade { from { opacity: 0; } }
@keyframes pop { from { opacity: 0; transform: translate(-50%, -46%) scale(.97); } }

@media (max-width: 640px) {
  .modal {
    left: 0; top: auto; bottom: 0; transform: none;
    width: 100vw; max-height: 92vh; max-height: 92dvh;
    border-radius: var(--r-xl) var(--r-xl) 0 0;
    animation: slideup .22s cubic-bezier(.4, 0, .2, 1);
  }
  .modal__foot { padding-bottom: calc(13px + env(safe-area-inset-bottom)); flex-wrap: wrap; }
  /* nota/resumo do rodapé ocupa a linha toda para não espremer os botões */
  .modal__foot > .small:first-child { flex: 1 1 100%; margin: 0 0 8px 0 !important; }
  .modal__foot .btn { flex: 1 1 auto; }
  /* Achado de auditoria: modal sem footer (menu "mais ações", bottom-sheet
     encostado em bottom:0) não tinha safe-area no fim do corpo — o último
     botão (geralmente destrutivo) ficava colado na barra de gestos do
     iPhone. */
  .modal__body { padding-bottom: calc(18px + env(safe-area-inset-bottom)); }
  @keyframes slideup { from { transform: translateY(100%); } }
}

/* --------------------------------------------------------------- TOASTS */
.toasts {
  position: fixed; z-index: 300; right: 16px;
  /* Auditoria WebKit (Mobile QA V18.2): bottom:16px fixo encosta bem
     perto (ou embaixo) da faixa do home indicator em iPhone com notch —
     env(safe-area-inset-bottom) é 0 em navegador sem notch, então isto
     não muda nada fora do iPhone. */
  bottom: calc(16px + env(safe-area-inset-bottom));
  display: flex; flex-direction: column-reverse; gap: 9px; pointer-events: none;
}
.toast {
  pointer-events: auto; min-width: 260px; max-width: 380px;
  background: var(--surface); border: 1px solid var(--border);
  border-left: 3px solid var(--text-3);
  border-radius: var(--r); box-shadow: var(--sh-3);
  padding: 12px 14px; display: flex; gap: 10px; align-items: flex-start;
  animation: toastin .22s cubic-bezier(.3, 1.2, .6, 1);
}
.toast--success { border-left-color: var(--green); }
.toast--error { border-left-color: var(--red); }
.toast--warn { border-left-color: var(--amber); }
.toast__title { font-size: 13.5px; font-weight: 650; }
.toast__text { font-size: 13px; color: var(--text-2); margin-top: 2px; }
@keyframes toastin { from { opacity: 0; transform: translateX(20px); } }
@media (max-width: 640px) {
  .toasts { right: 10px; left: 10px; bottom: calc(var(--bottomnav-h) + 10px + env(safe-area-inset-bottom)); }
  .toast { min-width: 0; max-width: none; }
}

/* --------------------------------------------------------------- UTILS */
.muted { color: var(--text-2); }
.dim { color: var(--text-3); }

/* ---------------------------------------------------- ARRASTAR/REORDENAR
 * Handle (☰) é o único ponto de arraste — o resto da linha continua
 * clicável, e a lista continua rolando com o dedo em qualquer outro
 * ponto. Mesmo princípio do drag da Agenda: pointer-events, sem lib.
 */
.reorder-handle {
  cursor: grab; color: var(--text-3); flex: 0 0 auto;
  padding: 6px; margin: -6px; touch-action: none; display: flex;
}
.reorder-handle svg { width: 16px; height: 16px; }
.reorder-handle:active { cursor: grabbing; }
.reorder-item { display: flex; align-items: center; gap: 10px; }
.reorder-item.reorder-dragging {
  box-shadow: var(--sh-2); border-radius: 8px; background: var(--surface);
  opacity: .95;
}
.reorder-placeholder {
  border: 2px dashed var(--border-strong); border-radius: 8px;
  background: var(--surface-2);
}
.reorder-setas { display: flex; flex-direction: column; gap: 0; flex: 0 0 auto; }
.reorder-setas button {
  border: none; background: none; padding: 2px 4px; cursor: pointer;
  color: var(--text-3); line-height: 1;
}
.reorder-setas svg { width: 14px; height: 14px; }
.reorder-setas button:hover { color: var(--text-1); }
.reorder-setas button:disabled { opacity: .3; cursor: default; }
@media (max-width: 640px) {
  .reorder-handle { padding: 10px; margin: -10px; }
  .reorder-setas { flex-direction: row; gap: 2px; }
  .reorder-setas button { min-width: 32px; min-height: 32px; padding: 8px; }
}
/* Segmentos e retenção no celular: cartão por cliente, não a tabela de
   7 colunas na horizontal. Mesmo padrão de .ags__lista-mobile. */
.rt__lista-mobile { display: none; }
.rt__cartao {
  display: block; padding: 12px 16px; border-top: 1px solid var(--border);
  color: inherit; cursor: pointer;
}
.rt__cartao:hover { background: var(--surface-2); }
@media (max-width: 720px) {
  .rt__tabela { display: none; }
  .rt__lista-mobile { display: block; }
}

/* Fase 3.1: 12px era a linha que mais aparecia nos prints como "fraco
   demais" — dica de apoio, texto de estado vazio, rótulo secundário.
   12.5px é pouco, mas some com o efeito "letra de rodapé de contrato". */
.tiny { font-size: 12.5px; }
.small { font-size: 13px; }
.b { font-weight: 650; }
/*
 * Achado real de QA (troca de paleta): icon() (ui/ui.js) devolve um
 * <svg viewBox="0 0 24 24"> sem width/height nenhum — mesma causa raiz
 * já documentada acima em .au-card__ico (este projeto nunca teve uma
 * regra global tipo `svg { width... }`; cada contexto tem a própria).
 * `.b` é só peso de fonte, texto puro em quase todo uso — nos dois
 * lugares onde um ícone entra direto dentro dela (Relatório gerencial
 * "Resumo do período", Cupons "Cupom válido"), o SVG não tinha NENHUMA
 * classe de tamanho por perto e esticava pra largura do container —
 * 460×460px numa tela estreita, 942×942px em desktop largo, sempre
 * exatamente a largura disponível do `.card__body` por perto. Escopado
 * em `.b svg`: não afeta as dezenas de outros `.b` que são só texto,
 * porque não têm `svg` filho.
 */
.b svg { width: 20px; height: 20px; max-width: 20px; max-height: 20px; flex-shrink: 0; vertical-align: -5px; }
.mono { font-variant-numeric: tabular-nums; }
.money-pos { color: var(--green); font-weight: 650; }
.money-neg { color: var(--red); font-weight: 650; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hide { display: none !important; }
.center { text-align: center; }
.mt-0 { margin-top: 0; } .mt-1 { margin-top: 8px; } .mt-2 { margin-top: 16px; } .mt-3 { margin-top: 24px; }
.mb-1 { margin-bottom: 8px; } .mb-2 { margin-bottom: 16px; }
/* ---------------------------------------------------------------------
   Barra superior e contexto ativo em telas estreitas
   --------------------------------------------------------------------- */
.topbar__desktop-context { display: flex; align-items: center; gap: 8px; min-width: 0; }
.topbar__unit-select, .topbar__tenant-select { width: auto; min-width: 150px; }

@media (max-width: 900px) {
  .topbar__desktop-context { display: none; }
}

@media (max-width: 720px) {
  .topbar > .inline { min-width: 0; flex: 0 0 auto; gap: 2px; }
  .topbar > .inline > * { flex: 0 0 auto; }
}

/* O router isola cada tela num container próprio: ele precisa ser
   transparente para o layout (a .page interna é que define o espaçamento). */
#outlet > .view { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; }

/* ------------------------------------------------- MODO CONTINGÊNCIA */
.contingencia {
  position: sticky; top: 0; z-index: 300;
  display: flex; align-items: center; gap: 10px;
  padding: 8px 14px;
  background: color-mix(in srgb, var(--amber) 16%, var(--surface));
  border-bottom: 1px solid color-mix(in srgb, var(--amber) 45%, transparent);
  color: var(--text); font-size: 13px; line-height: 1.35;
}
.contingencia--lenta { background: color-mix(in srgb, var(--amber) 9%, var(--surface)); }
.contingencia__bola { font-size: 15px; }
.contingencia__texto { display: flex; flex-direction: column; min-width: 0; }
.contingencia__texto b { font-weight: 650; }
.contingencia__texto span { color: var(--text-3); }
.contingencia button { margin-left: auto; flex: 0 0 auto; }

.contingencia__volta {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(22px + env(safe-area-inset-bottom)); z-index: 320;
  padding: 8px 14px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--border);
  box-shadow: var(--sh-2); font-size: 13px;
}

@media (max-width: 560px) {
  .contingencia { padding: 7px 10px; font-size: 12px; align-items: flex-start; }
  .contingencia button { margin-left: auto; }
}

/* ------------------------------------------------- SELETOR DE COR */
.cor__campo { display: flex; align-items: center; gap: 8px; }
.cor__amostra {
  width: 42px; height: 42px; flex: 0 0 42px;
  border-radius: 10px; border: 1px solid var(--border);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .12), var(--sh-1);
  cursor: pointer; padding: 0;
}
.cor__amostra:hover { transform: translateY(-1px); }
.cor__hex { flex: 1 1 110px; min-width: 90px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; text-transform: uppercase; }
.cor__nativo {
  position: absolute; width: 1px; height: 1px; opacity: 0;
  pointer-events: none; border: 0; padding: 0; margin: -1px; overflow: hidden;
}
.cor__aviso {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: 6px; font-size: 11.5px; line-height: 1.35; color: var(--text-2);
}
.cor__aviso::before {
  content: ''; width: 6px; height: 6px; flex: 0 0 6px;
  border-radius: 50%; background: var(--amber);
}
.cor__aviso--ruim::before { background: var(--red); }
.input.is-invalid, .select.is-invalid, .textarea.is-invalid { border-color: var(--red); }

.cor-pop {
  position: fixed; z-index: 400;
  width: min(288px, calc(100vw - 16px));
  padding: 12px; border-radius: 14px;
  background: var(--surface); border: 1px solid var(--border);
  box-shadow: var(--sh-3);
  display: flex; flex-direction: column; gap: 10px;
}
.cor-pop__sv {
  position: relative; height: 132px; border-radius: 10px;
  cursor: crosshair; touch-action: none; overflow: hidden;
}
.cor-pop__sv-branco, .cor-pop__sv-preto { position: absolute; inset: 0; }
.cor-pop__sv-branco { background: linear-gradient(to right, #fff, transparent); }
.cor-pop__sv-preto { background: linear-gradient(to top, #000, transparent); }
.cor-pop__alvo {
  position: absolute; width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid #fff; box-shadow: 0 0 0 1px rgba(0, 0, 0, .4);
  transform: translate(-50%, -50%); pointer-events: none;
}
.cor-pop__linha { display: flex; align-items: center; gap: 8px; }
.cor-pop__previa { width: 32px; height: 32px; flex: 0 0 32px; border-radius: 8px; border: 1px solid var(--border); }
.cor-pop__matiz {
  flex: 1; height: 12px; -webkit-appearance: none; appearance: none;
  border-radius: 999px; outline: none;
  background: linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00);
}
.cor-pop__matiz::-webkit-slider-thumb {
  -webkit-appearance: none; width: 16px; height: 16px; border-radius: 50%;
  background: #fff; border: 2px solid var(--border); box-shadow: var(--sh-1); cursor: grab;
}
.cor-pop__matiz::-moz-range-thumb {
  width: 16px; height: 16px; border-radius: 50%; background: #fff;
  border: 2px solid var(--border); cursor: grab;
}
.cor-pop__hex { flex: 1; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; text-transform: uppercase; }
.cor-pop__bolinhas { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.cor-pop__bola {
  width: 24px; height: 24px; border-radius: 50%; padding: 0; cursor: pointer;
  border: 1px solid var(--border); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .14);
}
.cor-pop__bola:hover { transform: scale(1.12); }
.cor-pop__acoes { display: flex; gap: 8px; justify-content: flex-end; }

/* prévia das duas cores juntas */
.cor-previa { border: 1px solid var(--border); border-radius: 14px; overflow: hidden; }
.cor-previa__topo { padding: 14px 16px; }
.cor-previa__titulo { font-weight: 700; font-size: 16px; margin-bottom: 2px; }
.cor-previa__sub { font-size: 12px; opacity: .82; }
.cor-previa__corpo { padding: 14px 16px; display: flex; flex-direction: column; gap: 10px; }
.cor-previa__card {
  border-radius: 10px; padding: 12px; font-size: 13px;
  border: 1px solid var(--border); background: var(--surface); color: var(--text);
}
.cor-previa__botoes { display: flex; gap: 8px; flex-wrap: wrap; }
.cor-previa__bt { border: 0; border-radius: 10px; padding: 9px 16px; font-weight: 600; font-size: 13px; cursor: default; }
.cor-previa__bt--2 { border: 1px solid currentColor; background: transparent; }

@media (max-width: 560px) {
  .cor__campo { flex-wrap: wrap; }
  .cor__hex { flex: 1 1 100px; }
  .cor-pop__sv { height: 116px; }
}


/* =============================================== IDENTIDADE VISUAL === */
.ident { display: flex; flex-direction: column; gap: 12px; }

.ident__bloco { display: flex; flex-direction: column; gap: 8px; }

/* dois blocos baixos dividem a linha, para a etapa caber sem rolagem */
.ident__dupla { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; }
.ident__dupla .ident__bloco { min-width: 0; }
.ident__dupla .ident__marca { flex: 1; }

/* Cores à esquerda, prévia à direita: muda a cor e vê o efeito ao lado. */
.ident__dupla--cores .ident__cores { grid-template-columns: 1fr; gap: 9px; }
.ident__dupla--cores .cor-previa { position: sticky; top: 0; }
.ident__titulo {
  font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-3);
}

/* ------------------------------------------------------------- marca */
.ident__marca {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 14px; border-radius: var(--r-lg);
  background: var(--surface-2); border: 1px solid var(--border);
}
.ident__logo {
  width: 60px; height: 60px; flex: 0 0 60px;
  border-radius: var(--r-lg); overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface); border: 1px dashed var(--border-strong);
  font-size: 20px; font-weight: 700; color: var(--text-3);
}
.ident__logo img { width: 100%; height: 100%; object-fit: cover; }
.ident__logo.is-cheio { border-style: solid; }
.ident__marca-txt { min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.ident__marca-txt b { font-size: 14px; }

/* ------------------------------------------------------------- cores */
.ident__cores { display: grid; grid-template-columns: 1fr 1fr minmax(136px, auto); gap: 12px; align-items: start; }
.ident__cores .field { margin: 0; }

.cor__campo {
  display: flex; align-items: center; gap: 8px;
  height: 44px; padding: 4px 4px 4px 5px;
  border: 1px solid var(--border); border-radius: var(--r);
  background: var(--surface); transition: border-color .15s, box-shadow .15s;
}
.cor__campo:focus-within {
  border-color: var(--border-strong);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 12%, transparent);
}
.cor__amostra {
  width: 34px; height: 34px; flex: 0 0 34px;
  border-radius: var(--r-sm); border: 1px solid var(--border);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .18);
  cursor: pointer; padding: 0; transition: transform .12s;
}
.cor__amostra:hover { transform: scale(1.06); }
.cor__hex {
  flex: 1 1 auto; min-width: 0; height: 34px; border: 0; background: transparent;
  padding: 0 2px; font-size: 13.5px; letter-spacing: .03em;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; text-transform: uppercase;
}
.cor__hex:focus { outline: none; box-shadow: none; }
.cor__campo .btn { flex: 0 0 auto; }
.cor__campo.is-invalid { border-color: var(--red); }

/* ------------------------------------------------------------- tema */
.ident__tema { display: inline-flex; padding: 3px; gap: 3px; border-radius: var(--r); background: var(--surface-3); }
.ident__tema button {
  height: 34px; padding: 0 16px; border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--text-2);
  font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.ident__tema button.is-on { background: var(--surface); color: var(--text); box-shadow: var(--sh-1); }

/* ---------------------------------------------------------- prévia */
.cor-previa {
  border: 1px solid var(--border); border-radius: var(--r-lg);
  overflow: hidden; box-shadow: var(--sh-2); background: var(--surface);
}
.cor-previa__chrome {
  display: flex; align-items: center; gap: 6px;
  padding: 6px 11px; background: var(--surface-3); border-bottom: 1px solid var(--border);
}
.cor-previa__chrome i { width: 8px; height: 8px; border-radius: 50%; background: var(--border-strong); }
.cor-previa__url {
  margin-left: 6px; font-size: 11px; color: var(--text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cor-previa__topo { padding: 11px 14px 12px; display: flex; align-items: center; gap: 10px; }
.cor-previa__logo {
  width: 36px; height: 36px; flex: 0 0 36px; border-radius: 11px; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 15px;
  background: rgba(255, 255, 255, .16); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .22);
}
.cor-previa__logo img { width: 100%; height: 100%; object-fit: cover; }
.cor-previa__titulo { font-weight: 700; font-size: 15px; letter-spacing: -.01em; }
.cor-previa__sub { font-size: 11.5px; opacity: .8; margin-top: 1px; }
.cor-previa__corpo { padding: 10px 14px 12px; background: var(--surface-2); display: flex; flex-direction: column; gap: 8px; }
.cor-previa__card {
  display: flex; align-items: center; gap: 12px;
  padding: 9px 12px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--border); box-shadow: var(--sh-1);
}
.cor-previa__card b { font-size: 13px; }
.cor-previa__card span { font-size: 12px; color: var(--text-3); }
.cor-previa__preco { margin-left: auto; font-weight: 700; font-size: 14px; white-space: nowrap; }
.cor-previa__botoes { display: flex; gap: 10px; flex-wrap: wrap; }
.cor-previa__bt {
  height: 34px; padding: 0 16px; border: 0; border-radius: var(--r);
  font: inherit; font-size: 13px; font-weight: 600; cursor: default;
  display: inline-flex; align-items: center; box-shadow: var(--sh-1);
}
.cor-previa__bt--2 { background: transparent; box-shadow: none; border: 1.5px solid currentColor; }

/*
 * Achado real de QA: a prévia sempre seguia o tema DESTE painel — quem
 * configurava com o painel em escuro via a prévia escura mesmo tendo
 * marcado "Claro" para o site. `data-theme` aqui é do próprio card
 * (onboarding.js escreve o valor escolhido no formulário, nunca herda de
 * `<html data-theme>`), e redefine só os tokens que a prévia usa —
 * mesma técnica de escopo de `/super`, sem tocar `:root` nem `[data-theme]`
 * do documento.
 */
.cor-previa[data-theme='light'] {
  --surface: #FBF7F1; --surface-2: #F6EFE7; --surface-3: #E7DBCE;
  --border: #D4C7B6; --border-strong: #C0B09A;
  --text: #17130F; --text-2: #685B49; --text-3: #7A6B57;
}
.cor-previa[data-theme='dark'] {
  --surface: #181611; --surface-2: #11100E; --surface-3: #211B13;
  --border: #30302D; --border-strong: #45443F;
  --text: #F7F2EA; --text-2: #A09F9D; --text-3: #85837F;
}

/* --------------------------------------------------------- rodapé */
.ident .textarea { min-height: 52px; }
.ident .field__hint { margin-top: 3px; }

.card__foot.card__foot--passos {
  display: flex; align-items: center; gap: 10px; padding: 12px 16px;
  /* Auditoria WebKit (Mobile QA V18.2): sticky bottom:0 sem safe-area
     fica atrás do home indicator do iPhone — mesmo ajuste que .modal__foot
     já tinha (mais abaixo neste arquivo), só que este rodapé nunca tinha
     recebido. */
  padding-bottom: calc(12px + env(safe-area-inset-bottom));
  position: sticky; bottom: 0; z-index: 5;
}
.card__foot--passos .spacer { flex: 1; }

@media (max-width: 640px) {
  .ident { gap: 18px; }
  .ident__dupla { grid-template-columns: 1fr; gap: 18px; }
  .ident__cores { grid-template-columns: 1fr; gap: 16px; }
  .ident__marca { flex-direction: column; align-items: flex-start; gap: 14px; }
  .ident__logo { width: 72px; height: 72px; flex-basis: 72px; }
  .cor-previa__topo { padding: 16px; }
  .cor-previa__corpo { padding: 14px 16px 16px; }
  .cor-previa__card { flex-wrap: wrap; }
  .cor-previa__preco { margin-left: 0; }
  .cor-previa__bt { flex: 1 1 auto; justify-content: center; }
  /* Mesmo achado já registrado acima pra .grid--cards .card__foot:
     "Voltar" + "Pular" + "Continuar" (+ spacer) numa linha sem quebra
     não cabem em ~290px — botão sem flex-wrap não encolhe abaixo do
     próprio conteúdo e estoura a página. Quebrar é inofensivo aqui: o
     rodapé é sticky, na pior hipótese fica com 2 linhas, nunca corta. */
  .card__foot--passos { flex-wrap: wrap; row-gap: 8px; }
  .card__foot--passos .btn { flex: 0 1 auto; }
}

/* ============================================ HORÁRIO DA SEMANA === */
.hora { display: flex; flex-direction: column; gap: 12px; }

.hora__atalhos {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 12px; border-radius: var(--r);
  background: var(--surface-2); border: 1px solid var(--border);
  font-size: 12.5px; color: var(--text-2);
}
.hora__atalhos b { color: var(--text); font-weight: 600; }
.hora__atalhos .spacer { flex: 1; }

.hora__lista { display: flex; flex-direction: column; }

.hora__dia {
  display: grid;
  grid-template-columns: 128px 92px 12px 92px 1fr;
  align-items: center; gap: 8px;
  padding: 7px 2px; border-bottom: 1px solid var(--border);
}
.hora__dia:last-child { border-bottom: 0; }
.hora__dia.is-fechado .hora__campo { display: none; }

.hora__nome { display: flex; align-items: center; gap: 9px; min-width: 0; }
.hora__nome .switch__label { font-size: 13.5px; font-weight: 500; }
.hora__ate { text-align: center; color: var(--text-3); font-size: 12px; }
.hora__campo { height: 34px; padding: 0 8px; font-size: 13px; width: 100%; }

.hora__pausa { display: flex; align-items: center; gap: 8px; min-width: 0; }
.hora__pausa .hora__campo { width: 92px; }
.hora__rotulo { font-size: 11.5px; color: var(--text-3); white-space: nowrap; }
.hora__semPausa {
  height: 28px; padding: 0 10px; border-radius: var(--r-full);
  border: 1px dashed var(--border-strong); background: transparent;
  color: var(--text-3); font: inherit; font-size: 11.5px; cursor: pointer; white-space: nowrap;
}
.hora__semPausa:hover { border-style: solid; color: var(--text-2); }

.hora__fechado {
  grid-column: 2 / -1;
  font-size: 12.5px; color: var(--text-3);
}
.hora__dia:not(.is-fechado) .hora__fechado { display: none; }

@media (max-width: 640px) {
  /*
   * Achado real de QA (onboarding a 390px): depois que .hora__nome e
   * .hora__pausa pulam para a própria linha inteira (grid-column:1/-1),
   * sobram exatamente 3 itens nesta linha — abre, seta, fecha. O molde
   * antigo tinha 4 colunas (1fr auto 12px auto) para só 3 itens: "fecha"
   * caía na faixa de 12px pensada para a seta, e o campo de hora
   * renderizava praticamente invisível (~18px, sem espaço nem para o
   * formato hh:mm). 3 colunas para 3 itens, seta no meio, é o que casa
   * com o HTML de verdade.
   */
  .hora__dia {
    grid-template-columns: 1fr 12px 1fr;
    row-gap: 6px; padding: 10px 2px;
  }
  .hora__nome { grid-column: 1 / -1; }
  /*
   * Achado real (iPhone físico, Mobile QA V18.3): com pausa preenchida
   * (rótulo "pausa" + 2 campos de hora + seta + botão "sem pausa"),
   * a linha soma ~330px de conteúdo contra ~320px realmente
   * disponíveis em 390px de tela — a métrica da fonte do sistema
   * (San Francisco) no Safari real é ligeiramente mais larga que a
   * fonte que o ambiente de teste usa, o suficiente pra estourar por
   * uma margem pequena que não apareceu em teste automatizado nenhum.
   * flex-wrap dá uma saída segura: se não couber tudo numa linha, quebra
   * em vez de vazar — o mesmo padrão usado no resto do painel.
   */
  .hora__pausa { grid-column: 1 / -1; padding-left: 2px; flex-wrap: wrap; row-gap: 6px; }
  .hora__pausa .hora__campo { width: 84px; }
  .hora__fechado { grid-column: 1 / -1; }
  .hora__atalhos { font-size: 12px; }
}

/* ============================================== PROFISSIONAIS ===== */
.prof { display: flex; flex-direction: column; gap: 12px; }

.prof__sozinho {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 12px; border-radius: var(--r);
  background: var(--surface-2); border: 1px solid var(--border);
}
.prof__sozinho .field__hint { margin: 0; }

.prof__lista { display: flex; flex-direction: column; gap: 6px; }
/* Achado de auditoria: caixa dentro de caixa — .prof__item repetia
   border+background de .card, mas só aparece aninhado dentro de
   .card > .card__body (onboarding.js), que já dá a separação visual. */
.prof__item {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: var(--r);
  background: transparent; border-bottom: 1px solid var(--border);
}
.prof__item:last-child { border-bottom: 0; }
.prof__item.is-editando { border-color: var(--border-strong); box-shadow: var(--sh-1); }
.prof__txt { min-width: 0; flex: 1 1 auto; }
.prof__nome { font-size: 13.5px; font-weight: 600; }
.prof__sub { font-size: 11.5px; color: var(--text-3); }
.prof__acesso {
  font-size: 10.5px; padding: 2px 7px; border-radius: var(--r-full);
  border: 1px solid var(--border); color: var(--text-3); white-space: nowrap;
}
.prof__acesso--on { color: var(--green); border-color: color-mix(in srgb, var(--green) 40%, transparent); }

/*
 * Duas linhas com colunas de peso diferente. O alinhamento e pelo TOPO,
 * nao pelo rodape: o e-mail tem texto de ajuda embaixo e, alinhado pela
 * base, empurrava o proprio campo 45px acima do WhatsApp. Com o topo fixo
 * e rotulo de altura constante, todos os inputs caem na mesma linha e a
 * ajuda cresce para baixo sem mover nada.
 */
.prof__form {
  display: grid; gap: 10px 12px; align-items: start;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1.25fr) 104px;
}
.prof__form--2 { grid-template-columns: minmax(0, 1.15fr) minmax(0, 2fr) 128px; margin-top: 12px; }

.prof__form .field { margin: 0; display: flex; flex-direction: column; }
.prof__form .field__label {
  height: 18px; line-height: 18px; margin: 0 0 6px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.prof__form .input { height: 40px; }
.prof__form .field__hint { margin-top: 5px; line-height: 1.35; }

/* o botao nao tem rotulo: desce o mesmo tanto para casar com os inputs */
.prof__acoes { display: flex; gap: 6px; padding-top: 24px; }
.prof__acoes .btn { height: 40px; }

@media (max-width: 640px) {
  .prof__form, .prof__form--2 { grid-template-columns: 1fr; gap: 10px; }
  .prof__acoes { width: 100%; padding-top: 2px; }
  .prof__acoes .btn { flex: 1; }
  .prof__item { flex-wrap: wrap; }
}

/* ================================================== SERVIÇOS ====== */
.serv { display: flex; flex-direction: column; gap: 12px; }

.serv__lista { display: flex; flex-direction: column; gap: 6px; }
.serv__item {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: var(--r);
  background: transparent; border-bottom: 1px solid var(--border);
}
.serv__item:last-child { border-bottom: 0; }
.serv__item.is-editando { border-color: var(--border-strong); box-shadow: var(--sh-1); }
.serv__ico { color: var(--brand-text, var(--brand)); display: flex; flex: 0 0 auto; }
.serv__txt { min-width: 0; flex: 1 1 auto; }
.serv__nome { font-size: 13.5px; font-weight: 600; display: flex; align-items: center; gap: 6px; }
.serv__sub { font-size: 11.5px; color: var(--text-3); }
.serv__preco { font-size: 13.5px; font-weight: 700; white-space: nowrap; }
.serv__acoes { display: flex; gap: 4px; flex: 0 0 auto; }
.serv__badge {
  font-size: 10px; font-weight: 600; padding: 1px 6px; border-radius: var(--r-full);
  background: var(--amber-bg); color: var(--amber); white-space: nowrap;
}

.serv__form {
  display: grid; gap: 10px 12px; align-items: start;
  /* Categoria em largura fixa: "Sem categoria" ocupa 103px de texto mais
     44px de recuo da seta do select. Abaixo disso o navegador corta e o
     rótulo aparece pela metade. */
  grid-template-columns: minmax(0, 1fr) 196px 108px 108px;
}
.serv__form .field { margin: 0; display: flex; flex-direction: column; }
.serv__form .field__label { height: 18px; line-height: 18px; margin: 0 0 6px; white-space: nowrap; }
.serv__form .input, .serv__form .select { height: 40px; }
.serv__cat { display: flex; gap: 6px; }
.serv__cat .select { flex: 1 1 auto; min-width: 0; }
.serv__cat .btn { height: 40px; width: 40px; flex: 0 0 40px; }

.serv__quem {
  display: flex; flex-wrap: wrap; gap: 6px 14px;
  padding: 9px 11px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--border);
}
.serv__quem .check { font-size: 13px; }
.serv__todos { font-weight: 600; }
.serv__todos::after {
  content: ''; width: 1px; height: 14px; margin-left: 8px;
  background: var(--border); display: inline-block; vertical-align: -2px;
}

.serv__rodape { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 12px; }
.serv__rodape .field__hint { margin: 0; }
.serv__rodape .spacer { flex: 1; }
.serv__rodape .btn { height: 40px; }

@media (max-width: 640px) {
  .serv__form { grid-template-columns: 1fr 1fr; }
  .serv__form .field:first-child, .serv__form .field:nth-child(2) { grid-column: 1 / -1; }
  .serv__item { flex-wrap: wrap; }
  .serv__preco { margin-left: auto; }
  .serv__rodape .btn { flex: 1 1 auto; }
  .serv__rodape .spacer { display: none; }
}

/* ================================================= PAGAMENTO ====== */
.pag { display: flex; flex-direction: column; gap: 16px; }
.pag__bloco { display: flex; flex-direction: column; gap: 8px; }

.pag__formas {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 16px;
  padding: 11px 13px; border-radius: var(--r);
  background: var(--surface-2); border: 1px solid var(--border);
}
.pag__forma { margin: 0; }
.pag__forma .switch__label { font-size: 13.5px; }

.pag__grade {
  display: grid; gap: 10px 12px; align-items: start; margin-top: 10px;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr);
}
.pag__grade .field { margin: 0; display: flex; flex-direction: column; }
.pag__grade .field__label { height: 18px; line-height: 18px; margin: 0 0 6px; white-space: nowrap; }
.pag__grade .input, .pag__grade .select { height: 40px; }
#f6dica { display: block; margin-top: 8px; }

@media (max-width: 640px) {
  .pag__formas { grid-template-columns: 1fr; }
  .pag__grade { grid-template-columns: 1fr 1fr; }
  .pag__grade .field:first-child { grid-column: 1 / -1; }
}

/* ================================================== REVISÃO ======= */
.rev { display: flex; flex-direction: column; gap: 14px; }

/*
 * icon() devolve <svg> sem width/height: quem dimensiona é o contexto
 * (.btn svg, .nav__item svg...). Fora de um desses, o SVG estica para
 * preencher o pai — aqui o alerta da pendência virou um ícone de 374px.
 */
.rev svg { width: 17px; height: 17px; flex: 0 0 17px; }
.rev__selo svg { width: 21px; height: 21px; flex-basis: 21px; }
.rev__atalho svg { width: 18px; height: 18px; flex-basis: 18px; }

.rev__topo { display: flex; align-items: center; gap: 13px; }
.rev__selo {
  width: 42px; height: 42px; flex: 0 0 42px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
.rev__selo.is-ok { background: var(--green-bg); color: var(--green); }
.rev__selo.is-parcial { background: var(--amber-bg); color: var(--amber); }
.rev__selo.is-critico { background: var(--red-bg); color: var(--red); }
.rev__titulo { margin: 0; font-size: 15px; font-weight: 700; letter-spacing: -.01em; }
.rev__sub { margin: 2px 0 0; font-size: 13px; color: var(--text-2); }

.rev__pendencias { display: flex; flex-direction: column; gap: 6px; }
.rev__pend {
  display: flex; align-items: center; gap: 9px; width: 100%; text-align: left;
  padding: 9px 11px; border-radius: var(--r); cursor: pointer;
  font: inherit; font-size: 13px; color: var(--text);
  border: 1px solid var(--border); background: var(--surface);
}
.rev__pend--grave { border-color: color-mix(in srgb, var(--red) 45%, transparent); background: var(--red-bg); }
.rev__pend--grave > svg { color: var(--red); }
.rev__pend--aviso { border-color: color-mix(in srgb, var(--amber) 45%, transparent); background: var(--amber-bg); }
.rev__pend--aviso > svg { color: var(--amber); }
.rev__pend span:first-of-type { flex: 1 1 auto; min-width: 0; }
.rev__ir { font-size: 12px; font-weight: 600; text-decoration: underline; white-space: nowrap; }
.rev__pend:hover { filter: brightness(.98); }

.rev__grade { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px 12px; }
.rev__item { display: flex; align-items: center; gap: 9px; padding: 7px 2px; min-width: 0; }
.rev__marca { display: flex; flex: 0 0 auto; }
.rev__item.is-ok .rev__marca { color: var(--green); }
.rev__item.is-falta .rev__marca { color: var(--text-3); }
.rev__txt { min-width: 0; }
.rev__rotulo { font-size: 13px; font-weight: 600; }
.rev__detalhe { font-size: 11.5px; color: var(--text-3); }
.rev__item.is-falta .rev__rotulo { color: var(--text-2); font-weight: 500; }

.rev__link { display: flex; flex-direction: column; }
.rev__linkCampo { display: flex; gap: 8px; }
.rev__linkCampo .input { flex: 1 1 auto; min-width: 0; font-size: 12.5px; }
.rev__linkCampo .btn { height: 40px; flex: 0 0 auto; }

.rev__atalhos { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.rev__atalho {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 11px 8px; text-decoration: none; color: var(--text);
}
.rev__atalho span:first-child { color: var(--brand-text, var(--brand)); display: flex; }

@media (max-width: 640px) {
  .rev__grade { grid-template-columns: 1fr; gap: 2px; }
  .rev__atalhos { grid-template-columns: 1fr; }
  .rev__linkCampo { flex-wrap: wrap; }
  .rev__linkCampo .input { flex: 1 1 100%; }
}

/* ============================================== CONFIGURAÇÕES ===== */
.cfg { display: flex; flex-direction: column; gap: 22px; }
.cfg__secao { display: flex; flex-direction: column; gap: 10px; }
.cfg__cabeca { display: flex; align-items: center; gap: 8px; }
.cfg__cabeca svg { width: 16px; height: 16px; flex: 0 0 16px; color: var(--brand-text, var(--brand)); }
.cfg__cabeca h2 { margin: 0; font-size: 13px; font-weight: 700; letter-spacing: .02em; }

.cfg__grade { display: grid; grid-template-columns: repeat(auto-fill, minmax(268px, 1fr)); gap: 8px; }
.cfg__item {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 13px; border-radius: var(--r);
  border: 1px solid var(--border); background: var(--surface);
  color: var(--text); text-decoration: none;
  transition: border-color .12s, transform .12s;
}
a.cfg__item:hover { border-color: var(--border-strong); transform: translateY(-1px); }
.cfg__item.is-vazio { opacity: .55; }
.cfg__txt { min-width: 0; flex: 1 1 auto; }
.cfg__nome { font-size: 13.5px; font-weight: 600; display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.cfg__nota { font-size: 11.5px; color: var(--text-3); margin-top: 1px; }
.cfg__seta { display: flex; flex: 0 0 auto; color: var(--text-3); }
.cfg__seta svg { width: 15px; height: 15px; }
.cfg__tag {
  font-size: 10px; font-weight: 600; padding: 1px 6px; border-radius: var(--r-full);
  background: var(--blue-bg); color: var(--blue); white-space: nowrap;
}
.cfg__tag--vazio { background: var(--surface-3); color: var(--text-3); }

@media (max-width: 640px) { .cfg__grade { grid-template-columns: 1fr; } }

/* ================================================= UNIDADES / EQUIPE == */
/* .input--sm e .select--sm vêm de servicos.css, que o painel já carrega. */

.uni__form .uni__linha { display: flex; gap: 10px; flex-wrap: wrap; }
.uni__form .field { flex: 1 1 150px; min-width: 0; }
.uni__acoes { display: flex; flex-direction: column; gap: 8px; }
.uni__acoes .btn { justify-content: flex-start; }

.uni__horas { display: flex; flex-direction: column; gap: 4px; }
.uni__dia {
  display: flex; align-items: center; gap: 10px;
  padding: 5px 8px; border-radius: var(--r-sm);
}
.uni__dia:nth-child(odd) { background: var(--surface-2); }
.uni__dia__nome { flex: 0 0 104px; font-size: 13px; }
.uni__dia__horas { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.uni__dia__horas .input { width: 96px; }
.uni__dia__pausa { margin-left: 6px; }
.uni__dia__fechado { display: none; }
.uni__dia.is-fechado .uni__dia__horas { display: none; }
.uni__dia.is-fechado .uni__dia__fechado { display: inline; }

.eq__filtros { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }
.eq__filtros .input { flex: 1 1 200px; max-width: 280px; }
.eq__pessoa { display: flex; align-items: center; gap: 10px; }
.eq__form .field { display: block; margin-bottom: 14px; }
.eq__unidades {
  display: flex; flex-direction: column; gap: 7px;
  margin: 8px 0 0 24px; padding-left: 12px; border-left: 2px solid var(--border);
}

/* ------------------------------------------------------- permissões -- */
.perm__topo { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.perm__aviso {
  display: flex; gap: 12px; align-items: flex-start; line-height: 1.55; font-size: 13.5px;
  padding: 14px; border-radius: var(--r); background: var(--amber-bg); color: var(--text);
}
.perm__aviso svg { width: 20px; height: 20px; flex: 0 0 20px; color: var(--amber); }
.perm__grade { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 14px; }
.perm__mod { border: 1px solid var(--border); border-radius: var(--r); padding: 10px 12px; }
.perm__modTit {
  font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-3); margin-bottom: 8px;
}
.perm__item {
  display: flex; align-items: center; gap: 8px; padding: 5px 0; cursor: pointer; font-size: 13px;
}
.perm__item input { width: 16px; height: 16px; flex: 0 0 16px; accent-color: var(--brand); }
.perm__item input:disabled { cursor: not-allowed; }
.perm__nome { flex: 1 1 auto; min-width: 0; }
.perm__tag {
  font-size: 9.5px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase;
  padding: 1px 5px; border-radius: var(--r-full);
  background: var(--surface-3); color: var(--text-3); white-space: nowrap;
}
.perm__tag--add { background: var(--green-bg); color: var(--green); }
.perm__tag--rem { background: var(--red-bg); color: var(--red); }
.perm__item.is-add .perm__nome { font-weight: 600; }
.perm__item.is-rem .perm__nome { color: var(--text-3); text-decoration: line-through; }

/* ------------------------------------------------------------ cargos - */
.cargo__grade { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 10px; }
.cargo__card { border: 1px solid var(--border); border-radius: var(--r); background: var(--surface); padding: 13px 14px; }
.cargo__nome { font-size: 14px; font-weight: 700; display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.cargo__nome svg { width: 11px; height: 11px; }
.cargo__desc { font-size: 11.5px; color: var(--text-3); margin-top: 3px; line-height: 1.45; min-height: 33px; }
.cargo__nums { display: flex; gap: 14px; margin-top: 8px; font-size: 12px; color: var(--text-2); }
.cargo__topo { display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; }

.matriz th.matriz__c, .matriz td.matriz__c { text-align: center; width: 92px; }
.matriz__mod td {
  background: var(--surface-3); font-size: 11px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; color: var(--text-3); padding: 6px 14px;
}
.matriz__sim { display: inline-flex; color: var(--green); }
.matriz__sim svg { width: 15px; height: 15px; }
.matriz__nao { color: var(--border-strong); }

@media (max-width: 640px) {
  .eq__filtros .input, .eq__filtros .select { flex: 1 1 100%; max-width: none; }
  .perm__grade { grid-template-columns: 1fr; }
  .cargo__grade { grid-template-columns: 1fr; }
  .cargo__desc { min-height: 0; }
  .uni__form .field { flex: 1 1 100%; }
  .uni__dia { flex-wrap: wrap; gap: 6px; }
  .uni__dia__nome { flex: 1 1 100%; }
  .uni__dia__horas .input { width: 84px; }
}

/* ============================================= BLOQUEIOS / AUSÊNCIAS == */
.blk__filtros { display: flex; gap: 20px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 14px; }
.blk__grupo { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
/*
 * Fase 3.1, achado do print real: `.select`/`.input` têm `width:100%` na
 * base (ver regra de `.input, .select, .textarea`) — sem um teto aqui,
 * cada um ocupava a linha inteira sozinho e a barra virava formulário
 * empilhado (Profissional 100%, Tipo 100%, Busca 100%), não uma fileira
 * de filtros. Mesma correção que `.ags__filtros`/`.filterbar` já tinham.
 *
 * Fase 3.2, achado do print real: esse MESMO teto de 200px, aplicado
 * também à busca, cortava o placeholder mais comprido ("Buscar por
 * motivo ou profissional"). Select continua com teto — não precisa
 * esticar; busca (.blk__busca) ganha uma regra própria, mais larga e
 * flexível, logo abaixo.
 */
.blk__filtros .select { width: auto; max-width: 200px; }
.blk__grupo--busca { flex: 1 1 260px; }
.blk__busca { width: auto; flex: 1 1 220px; min-width: 180px; max-width: 340px; }
.blk__campo { display: flex; flex-direction: column; gap: 2px; }
.blk__campo .input { width: auto; }
.blk__form .field { display: block; margin-bottom: 12px; }
/* Achado de auditoria: só a margem do .field era tratada aqui — faltava a
   regra que dá display:flex à própria .uni__linha (existe só para
   .uni__form, achado real), então os campos empilhavam em vez de ficar
   em linha. */
.blk__form .uni__linha { display: flex; gap: 10px; flex-wrap: wrap; }
.blk__form .uni__linha .field { margin-bottom: 0; }
.table tr.is-passado { opacity: .5; }
.table tr.blk__linha.is-passado { opacity: 1; background: var(--surface-2); }
.table tr.blk__linha.is-passado td { color: var(--text-2); }
.table tr.blk__linha.is-passado .badge,
.table tr.blk__linha.is-passado .btn { opacity: .8; }

.blk__conf { margin-top: 14px; }
.blk__ok {
  display: flex; align-items: center; gap: 8px; font-size: 13px;
  color: var(--green); padding: 10px 12px; border-radius: var(--r); background: var(--green-bg);
}
.blk__ok svg { width: 16px; height: 16px; flex: 0 0 16px; }
.blk__alerta { border: 1px solid var(--amber); border-radius: var(--r); overflow: hidden; }
.blk__alerta__topo {
  display: flex; align-items: center; gap: 8px; font-size: 13.5px;
  padding: 10px 12px; background: var(--amber-bg);
}
.blk__alerta__topo svg { width: 17px; height: 17px; flex: 0 0 17px; color: var(--amber); }
.blk__alerta__txt {
  font-size: 12px; color: var(--text-2); line-height: 1.5; padding: 9px 12px;
  border-bottom: 1px solid var(--border);
}
.table--mini th, .table--mini td { padding: 7px 12px; }
.hour-row__casa { flex: 0 0 auto; margin-left: auto; }

@media (max-width: 640px) {
  /* Mesma correção de .filterbar/.pp__trigger: período + tipo/profissional
     cabem lado a lado até 320px, sem empilhar cada um em 100%. */
  .blk__filtros > * { flex: 1 1 150px; min-width: 0; }
  .blk__filtros .select { max-width: none; }
  .blk__campo .input { width: 100%; }
  .hour-row__casa { margin-left: 0; }
}

/* ---- terceiro nível do menu: subgrupo dentro de grupo -------------- */
/* A linha vertical de cada nível já vem de .nav__filhos; aqui só se
   aperta o passo para a árvore não escorrer para a direita. */
.nav__filhos .nav__filhos { margin-left: 8px; padding-left: 10px; }
.nav__item--n2 { font-size: 13px; padding: 6px 10px; }
.nav__filhos .nav__filhos .nav__item { font-size: 13px; padding: 6px 10px; }
.nav__pasta--n1 > .nav__cabeca { font-weight: 500; color: var(--text-3); }
.nav__pasta--n1.is-aberta > .nav__cabeca { color: var(--text-2); font-weight: 600; }
.nav__pasta--n1 > .nav__cabeca .nav__seta svg { width: 13px; height: 13px; }

/* ---- registro de atividade ---------------------------------------- */
.aud__filtros { display: flex; gap: 8px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 14px; }
.aud__filtros .select, .aud__filtros .input { max-width: 200px; }

@media (max-width: 640px) {
  .aud__filtros > * { flex: 1 1 100%; }
  .aud__filtros .select, .aud__filtros .input { max-width: none; }
}

/* ============================== PEÇAS QUE FALTAVAM NO DESIGN SYSTEM == */
/* Todas estas classes já eram escritas pelas telas e nunca existiram no
   CSS. O efeito era o mesmo em todas: o navegador ignorava a classe e o
   conteúdo caía como texto cru, encostado à esquerda. */

/* Abas — cinco telas usavam .tabs/.tab, que só existiam como .proftabs
   dentro da ficha do profissional. Mesma aparência, agora para todas. */
/*
 * Abas. Havia DUAS implementações idênticas com nomes diferentes:
 * `.tabs/.tab` aqui e `.proftabs/.proftab` em profissionais.css — mesmo
 * padding, mesma fonte, mesma borda ativa, copiadas linha a linha. Onze
 * telas usavam uma, nove usavam a outra, e mexer no visual das abas exigia
 * lembrar das duas.
 *
 * Agora é uma regra só com os dois seletores. A marcação das telas não
 * mudou — `.proftabs` continua valendo — e o CSS duplicado saiu.
 */
.tabs, .proftabs {
  display: flex; gap: 4px; overflow-x: auto; padding-bottom: 2px;
  border-bottom: 1px solid var(--border); scrollbar-width: none;
}
.tabs::-webkit-scrollbar, .proftabs::-webkit-scrollbar { display: none; }
/*
 * Achado real (varredura de design, print do usuário): só .proftabs tinha
 * margin-bottom — .tabs (usada em 9 telas) ficava colada no conteúdo
 * seguinte, mesmo tendo a MESMA regra de aparência das duas classes em
 * todo o resto do arquivo. Unificado aqui — mesma respiração para as duas.
 */
.tabs, .proftabs { margin-bottom: var(--sp-4); }
.tab, .proftab {
  display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
  border: 0; background: transparent; color: var(--text-2);
  padding: 9px 13px; border-radius: var(--r-sm) var(--r-sm) 0 0;
  font-size: 13.5px; font-weight: 600; cursor: pointer;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  font-family: inherit;
  transition: color .12s, background .12s, border-color .12s;
}
.tab:hover, .proftab:hover { color: var(--text); background: var(--surface-2); }
.tab.is-active, .proftab.is-active {
  color: var(--nav-active-ink); font-weight: 800;
  border-bottom-color: var(--nav-active-border);
  box-shadow: inset 0 -2px 0 0 var(--nav-active-glow);
}
.tab svg, .proftab svg { width: 16px; height: 16px; flex: 0 0 16px; }
/* Contador dentro da aba: "Fila 12". Discreto, e some quando é zero — a
   tela decide isso, aqui só existe o estilo. */
.tab__n, .proftab__n {
  background: color-mix(in srgb, currentColor 15%, transparent);
  border-radius: var(--r-full); padding: 0 6px;
  font-size: 11px; font-variant-numeric: tabular-nums; font-weight: 700;
}

/* Coluna de número: nove telas marcavam .right em <th>/<td> esperando
   alinhamento à direita, e recebiam alinhamento à esquerda. */
.right { text-align: right; font-variant-numeric: tabular-nums; }
/* .table th ja define text-align: left, e vence .right sozinho */
.table th.right, .table td.right { text-align: right; white-space: nowrap; }

/* Link dentro de texto e de tabela */
.link {
  color: var(--blue); font-weight: 600; text-decoration: none;
  cursor: pointer; border-bottom: 1px solid transparent;
}
.link:hover { border-bottom-color: currentColor; }

/* Rótulo de seção reaproveitado fora do menu (agrupamentos de lista) */
.nav__label {
  font-size: 11px; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--text-3);
  padding: 10px 10px 4px;
}

/* Lista simples de itens em cartão (comanda, resumos) */
.list { list-style: none; margin: 0; padding: 0; }
.list__item {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 0; border-bottom: 1px solid var(--border); font-size: 13.5px;
}
.list__item:last-child { border-bottom: 0; }

/*
 * Gate V3.4 (QA global) — sem `width`, um container `display:flex` não
 * herda automaticamente 100% do pai como um `<div>` comum herdaria:
 * ele mede pelo conteúdo (mesma causa raiz já documentada acima para o
 * gráfico do Financeiro). A tabela de itens da comanda (`#pdvItems`)
 * tem colunas o bastante para passar de 800px — sem `width: 100%` aqui,
 * `.pdv__main` "abraçava" essa largura e o scroll horizontal vazava pra
 * página inteira em vez de ficar contido no `.table-wrap` (que já tem
 * `overflow-x: auto` — só não tinha o que conter, porque o pai dele
 * cresceu junto). Achado em `/comandas/:id` a 375px durante o QA global.
 */
.pdv__main { display: flex; flex-direction: column; gap: 2px; min-height: 60px; width: 100%; min-width: 0; }
.input--lg { height: 46px; font-size: 16px; font-weight: 600; letter-spacing: .04em; }
.auth__err { padding: 10px 12px; border-radius: var(--r-sm); font-size: 13px; line-height: 1.45; }

/* -------------------------------------------- listagem de agendamentos */
/* Fase 3.1: período/filtros/busca liam como um formulário de 7 campos
   iguais em fila. Agrupar por respiro (gap maior ENTRE grupos que DENTRO
   deles) separa sem precisar de rótulo "Período" / "Filtros" / "Busca". */
/*
 * Achado real (print do usuário): com align-items:flex-end e
 * .ags__grupo sem flex-shrink:0, o grupo de 4 selects (unidade/
 * profissional/serviço/situação) encolhia abaixo da largura que
 * precisava, splitava sozinho em 2 linhas internas, e o período/busca
 * (bem mais baixos) ficavam alinhados pelo RODAPÉ contra a linha mais
 * alta — a 4ª select "sobrava" isolada ao lado do período, com a busca
 * empurrada lá longe à direita. flex-shrink:0 faz o grupo manter a
 * largura natural (e virar UM bloco só pra próxima linha, se não
 * couber, em vez de espremer/splitar por dentro); align-items:flex-start
 * alinha todo mundo pelo TOPO, então quando algo quebra linha o efeito
 * é "grupo inteiro desceu", não "um controle solto no meio do nada".
 */
.ags__filtros { display: flex; gap: 20px; flex-wrap: wrap; align-items: flex-start; margin-bottom: 14px; }
.ags__grupo { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; flex-shrink: 0; }
.ags__filtros .select { max-width: 190px; }
/* Busca merece mais espaço que um select (regra geral de filterbar já
   usada em Bloqueios/etc.) — 190px cortava "Cliente ou telefone" apertado. */
.ags__filtros .input { width: 240px; max-width: 240px; }
/*
 * flex-shrink:0 sozinho não bastou: um item flex que por dentro TAMBÉM é
 * wrap tem seu tamanho mínimo automático calculado pelo maior filho, não
 * pela soma — o grupo de 4 selects continuava cabendo só 3 e meio antes
 * de "decidir" quebrar por dentro. Sem ambiguidade nenhuma nowrap: vira
 * uma única barra rígida (784px pros 4 selects), e é ELA que quebra
 * inteira pra própria linha se não couber — nunca um select sozinho.
 *
 * O breakpoint NÃO pode ser "sidebar vira gaveta" (900px): a partir dali
 * a barra lateral CONTINUA visível e ocupando ~252px até bem mais largo
 * — medido ao vivo em 932px, sobravam só ~630px de conteúdo, e a barra
 * rígida de 784px não cabia nem sozinha na própria linha. O corte real
 * tem que somar sidebar (252px) + padding da página (~40px) + os 784px
 * da barra rígida ⇒ só a partir de ~1076px o nowrap tem onde caber; o
 * valor abaixo dá folga.
 */
@media (min-width: 1100px) {
  .ags__grupo { flex-wrap: nowrap; }
}
/*
 * Achado real (varredura landscape, 667×375 e 932×430, e depois 932×430
 * de novo com a sidebar expandida): abaixo de 1100px (ver acima), sem
 * nowrap nem o tratamento mobile de largura total, .ags__grupo ficava
 * sem nenhuma das duas correções.
 *
 * Duas tentativas antes desta: só min-width:0 resolvia por coincidência
 * de geometria em 667px (só 1 select cabia por linha interna, dando uma
 * largura medida pequena o bastante) mas voltava a estourar em 932px
 * (2 selects cabem por linha interna ali, e essa largura maior somada ao
 * que já vinha antes do grupo na mesma linha ultrapassava o viewport).
 * A causa raiz: um flex item que por dentro TAMBÉM é flex-wrap tem seu
 * tamanho intrínseco calculado de um jeito que não informa corretamente
 * a decisão de quebra de linha do CONTAINER PAI — o grupo às vezes fica
 * na mesma linha que período/busca quando na verdade não cabe mais.
 *
 * flex:1 1 100% remove a ambiguidade: força o grupo inteiro a ocupar
 * sozinho o resto da própria linha (nunca dividir linha com período ou
 * busca) — depois disso, o flex-wrap INTERNO do grupo arruma os 4
 * selects em quantas linhas próprias couberem, sem afetar mais nada.
 */
@media (max-width: 1099px) {
  .ags__grupo { min-width: 0; flex: 1 1 100%; }
}
.table tbody tr[data-appt] { cursor: pointer; }
.table tbody tr[data-appt]:hover { background: var(--surface-2); }

@media (max-width: 640px) {
  .ags__filtros > * { flex: 1 1 100%; }
  .ags__filtros .select, .ags__filtros .input { max-width: none; }
}

/* Agendamentos no celular: cartão por atendimento, não a mesma tabela de
   8 colunas espremida com rolagem lateral. */
.ags__lista-mobile { display: none; }
.ags__cartao-dia { padding: 10px 14px 4px; font-size: 12px; font-weight: 650; color: var(--text-2); }
.ags__cartao {
  display: block; width: 100%; text-align: left; background: transparent; border: 0;
  border-top: 1px solid var(--border); padding: 12px 14px; cursor: pointer; font: inherit; color: inherit;
}
.ags__cartao-dia + .ags__cartao { border-top: 0; }
.ags__cartao:hover { background: var(--surface-2); }
.ags__cartao__topo { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }

@media (max-width: 720px) {
  .ags__tabela { display: none; }
  .ags__lista-mobile { display: block; }
}

.prof__unidades { display: flex; flex-wrap: wrap; gap: 8px 18px; margin-top: 6px; }

/* ------------------------------------------------ horários da equipe */
.hr__tabela th.hr__col, .hr__tabela td.hr__col { text-align: center; width: 86px; padding: 8px 4px; }
.hr__tabela .is-fds { background: var(--surface-2); }
.hr__casa-linha td { background: var(--surface-3); }
.hr__casa-linha svg { width: 13px; height: 13px; vertical-align: -2px; }
.hr__hora { font-size: 12.5px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.hr__casa { font-size: 12.5px; color: var(--text-3); font-variant-numeric: tabular-nums; white-space: nowrap; }
.hr__pausa { font-size: 10.5px; color: var(--text-3); margin-top: 1px; }
.hr__folga { font-size: 11.5px; color: var(--amber); font-weight: 600; }
.hr__fechado { color: var(--text-3); }

@media (max-width: 640px) {
  .hr__tabela th.hr__col, .hr__tabela td.hr__col { width: 74px; }
  .hr__hora, .hr__casa { font-size: 11.5px; }
}

/* ---------------------------------------------------------- ranking - */
.rk__filtros { display: flex; gap: 8px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 14px; }
.rk__podio { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px; }
.rk__card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
  box-shadow: var(--sh-1); padding: 18px 16px; text-align: center; position: relative;
}
.rk__card--1 { border-color: var(--amber); }
.rk__medalha { font-size: 26px; line-height: 1; margin-bottom: 6px; }
.rk__card .avatar { margin: 0 auto 8px; }
.rk__nome { font-size: 14.5px; font-weight: 700; }
.rk__valor { font-size: 22px; font-weight: 800; letter-spacing: -.02em; margin-top: 4px; }
.rk__sub { font-size: 11.5px; color: var(--text-3); margin-top: 3px; }
.rk__premios { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.rk__premios li { display: flex; gap: 10px; align-items: center; font-size: 13.5px; }
.table .center { text-align: center; }

@media (max-width: 640px) {
  /* Mesma correção de .filterbar/.pp__trigger: período + unidade/categoria
     cabem lado a lado até 320px, sem empilhar cada um em 100%. */
  .rk__filtros > * { flex: 1 1 150px; min-width: 0; }
  .rk__podio { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------- pacotes - */
.pk__itens { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 8px; }
.pk__item { display: flex; align-items: center; gap: 10px; }
.pk__item .check { flex: 1 1 auto; min-width: 0; }
.pk__saldo { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--border); }
.pk__saldo:last-child { border-bottom: 0; }

@media (max-width: 640px) { .pk__itens { grid-template-columns: 1fr; } }

/* -------------------------------------------------- dashboard: hierarquia */
/* Quatro números grandes respondem "como foi o período"; o resto continua
   inteiro, em uma faixa mais discreta. Nenhuma métrica foi removida. */
.kpis--destaque .kpi__value { font-size: 30px; }
.kpis--destaque > .kpi { min-height: 108px; }
.dash__sub {
  font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--text-3); margin: 20px 0 8px;
}
.kpis--compacto { gap: 10px; }
.kpis--compacto > .kpi { min-height: 0; padding: 12px 14px; }
.kpis--compacto .kpi__value { font-size: 19px; margin-top: 3px; }
.kpis--compacto .kpi__hint { font-size: 12px; }

/* Fila do Operacional — cartão achatado por status (não é .kpi: sem
   ícone, sem corpo grande), exatamente a estrutura da V76. */
.queue-grid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 10px; }
.queue-card {
  min-height: 64px; padding: 13px 14px; border-radius: 12px;
  border: 1px solid rgba(212, 162, 96, .24);
  background:
    repeating-linear-gradient(135deg, var(--card-texture) 0 1px, transparent 1px 8px),
    var(--dash-kpi-body);
}
.queue-card span {
  display: flex; align-items: center; gap: 7px; color: var(--dash-kpi-label); font-size: 11px;
}
.queue-card span::before {
  content: ''; width: 7px; height: 7px; border-radius: 50%;
  background: var(--queue-color, var(--text-3));
  box-shadow: 0 0 10px color-mix(in srgb, var(--queue-color, var(--text-3)) 50%, transparent);
}
.queue-card strong { display: block; margin-top: 5px; font-size: 19px; color: var(--text); }
@media (max-width: 1024px) { .queue-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 640px) { .queue-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ------------------------------------------- dashboard: Visão geral --- */
.dash__resumo3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.dash__resumo3 > * { min-width: 0; }
.dash__rank-list { display: flex; flex-direction: column; gap: 10px; }
.dash__rank-row { display: flex; align-items: center; gap: 10px; }
.dash__rank {
  flex: 0 0 auto; width: 20px; text-align: center; font-size: 12px; font-weight: 700; color: var(--text-3);
}
.dash__rank--ouro, .dash__rank--prata, .dash__rank--bronze {
  width: 19px; height: 19px; border-radius: 999px; display: grid; place-items: center;
  /* Ouro/prata/bronze são cores de MEDALHA (1º/2º/3º), fixas de propósito
     nos dois temas — não são a marca. O texto usa --brand-fg só porque
     esse token é escuro em claro e em escuro, garantindo contraste sobre
     os três gradientes sem virar mais um hex solto. */
  font-size: 10.5px; font-weight: 900; color: var(--brand-fg);
  border: 1px solid rgba(255, 255, 255, .18);
  box-shadow: 0 6px 14px rgba(0, 0, 0, .22), inset 0 1px 0 0 rgba(255, 255, 255, .35);
}
.dash__rank--ouro { background: linear-gradient(#ffd978, #f0b83d); }
.dash__rank--prata { background: linear-gradient(#e4e7ea, #b7bec4); }
.dash__rank--bronze { background: linear-gradient(#d69b6d, #a86a3f); }
.dash__rank-barra {
  flex: 1 1 100px; min-width: 40px; height: 6px; border-radius: 999px;
  background: var(--surface-3); overflow: hidden;
}
.dash__rank-barra > span {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--icon-accent), color-mix(in srgb, var(--icon-accent) 80%, transparent));
}
@media (max-width: 640px) { .dash__rank-barra { display: none; } }

/* Agenda do dia como linha do tempo — um ponto colorido por status, a
   mesma cor de APPT_STATUS que já vale na agenda e no operacional. */
.timeline { display: flex; flex-direction: column; }
.timeline__item { display: flex; gap: 12px; }
.timeline__hora { flex: 0 0 auto; width: 42px; font-size: 12.5px; padding-top: 2px; }
.timeline__linha { flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; }
.timeline__linha span { width: 8px; height: 8px; border-radius: 50%; margin-top: 4px; flex: 0 0 auto; }
.timeline__item:not(:last-child) .timeline__linha::after {
  content: ''; width: 1px; flex: 1 1 auto; background: var(--border); margin-top: 4px;
}
.timeline__corpo { flex: 1 1 auto; min-width: 0; padding-bottom: 16px; }
.timeline__item:last-child .timeline__corpo { padding-bottom: 0; }

/* Donut só de CSS: conic-gradient para as fatias, um círculo da cor da
   superfície por cima pra abrir o buraco — sem SVG, sem lib de gráfico. */
.donut-wrap { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.donut {
  width: 120px; height: 120px; border-radius: 50%; flex: 0 0 auto; position: relative;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .04), 0 10px 28px rgba(0, 0, 0, .16);
}
.donut__centro {
  position: absolute; inset: 17px; background: var(--card); border-radius: 50%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
}
.donut__total { font-size: 18px; font-weight: 750; line-height: 1.1; }
.donut__legenda { display: flex; flex-direction: column; gap: 7px; flex: 1 1 160px; min-width: 0; }
.donut__item { display: flex; align-items: center; gap: 7px; font-size: 12.5px; }
.donut__item .truncate { flex: 1 1 auto; }
.donut__dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }

/*
 * Linhas 2 e 3 da "Visão geral": 3 cartões por linha que precisam
 * terminar exatamente na mesma altura. auto-fit/minmax (o .grid--3 do
 * resto do painel) cria faixas fantasmas em telas largas — 5 faixas
 * para 3 itens, por exemplo — e o alinhamento vertical do stretch do
 * grid não alcança o .card, só o slot: o slot esticava certo, o card
 * dentro dele ficava do tamanho do próprio conteúdo. Escopado aqui, não
 * em .card global, pra não mexer em nenhuma outra tela.
 */
.dash__linha { grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: stretch; }
.dash__linha .card {
  height: 100%; display: flex; flex-direction: column; box-sizing: border-box;
}
.dash__linha .card__head { flex: 0 0 auto; min-height: 60px; }
.dash__linha .card__title {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
}
.dash__linha .card__body {
  flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0;
}
/* Só o estado vazio centraliza — lista e donut ficam ancorados no topo,
   que é como conteúdo real de verdade costuma se comportar num cartão
   mais alto que o próprio conteúdo. */
.dash__linha .card__body > .empty { margin: auto 0; }

/* Cada linha é uma composição fechada: o card vazio acompanha o par mais
   alto e centraliza seu estado, em vez de encolher e abrir um buraco. */
.dash__linha > div { min-width: 0; }
.dash__linha > div > .card { width: 100%; }

@media (max-width: 900px) {
  .dash__linha { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
  .dash__linha { grid-template-columns: 1fr; }
}

/*
 * Redesign Fase 3 — Visão geral vira 3 linhas de 2 cartões (a primeira
 * assimétrica: Agendamentos do dia maior que Resumo financeiro), em vez
 * de 2 linhas de 3 cartões iguais. Regra própria no fim do arquivo — não
 * depende de onde `.dash__linha` aparece acima — porque senão o mobile
 * herdaria a ordem errada e voltaria a mostrar 2 colunas espremidas.
 */
.dash__linha--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.dash__linha--assimetrica { grid-template-columns: 1.6fr 1fr; }
@media (max-width: 640px) {
  .dash__linha--2, .dash__linha--assimetrica { grid-template-columns: 1fr; }
}

/* Endereço no cadastro do cliente: fechado por padrão, porque é opcional e
   sete campos abertos empurrariam tags e observações para fora da vista.
   Abre sozinho quando já existe endereço salvo. */
.cl__endereco { border: 1px solid var(--border); border-radius: var(--r-md); padding: 10px 12px; }
.cl__endereco > summary {
  cursor: pointer; font-size: 12.5px; font-weight: 700; color: var(--text-2);
  list-style: none; user-select: none;
}
.cl__endereco > summary::-webkit-details-marker { display: none; }
.cl__endereco > summary::before { content: '▸ '; color: var(--text-3); }
.cl__endereco[open] > summary::before { content: '▾ '; }
.cl__endereco[open] > summary { margin-bottom: 2px; }

/* Número que precisa doer: atraso e falha de cobrança. Cor sozinha não
   basta (daltonismo, impressão em cinza) — nas telas que usam isto o texto
   ao lado sempre diz o que é. */
.text-red { color: var(--red); }

/* Linha de PREVISÃO no calendário de recebíveis. Fica visivelmente mais
   apagada que cobrança de verdade: é expectativa, não compromisso, e as
   duas na mesma cor fariam somar dinheiro que ninguém deve ainda. */
.rec--prev td { opacity: .68; font-style: italic; }

/* Mapa de ocupação (Horários de pico). Célula quadrada e compacta: são até
   24 colunas, e padding de tabela normal empurraria o mapa para fora da
   tela mesmo no desktop. A rolagem fica no .table-wrap, como nas demais. */
/* Layout automático de propósito. Com table-layout:fixed o navegador
   redistribui a largura disponível entre as colunas e ignora o valor
   declarado: no celular as 12 colunas viravam 26px cada e o mapa ficava
   ilegível em vez de rolar. Com layout automático + min-width na célula, a
   tabela cresce até o tamanho que precisa e quem rola é o .table-wrap.
   Isso NÃO é `width:auto`, é `width:100%` com um teto: os dois usam
   layout automático (nenhum vira table-layout:fixed), a diferença é se a
   tabela PARA no tamanho mínimo do conteúdo ou continua esticando até
   preencher o card. Fase 3.1, achado do print real: com `auto` o mapa
   carimbava uns 400px no canto esquerdo de um card de 1200px de largura,
   sobrando quase metade do card vazio. `100%` sozinho resolvia isso mas
   esticava CADA célula até ficar um retângulo bem achatado num monitor
   grande — `max-width` na célula (abaixo) não pega em table-layout
   automático, é limitação conhecida do próprio CSS de tabela, não bug
   daqui; o teto que funciona de verdade é na TABELA. Com min-width por
   célula ainda de pé, o celular continua estourando além do teto e
   rolando dentro do `.table-wrap`, exatamente como antes. */
/* Sem teto: o pedido explícito é usar quase toda a largura do card, e
   com 7 colunas fixas (dia da semana) não existe mais o risco de célula
   virar um retângulo achatado num monitor grande — o max-width por
   célula abaixo já cuida disso. */
.heat { width: 100%; }
.heat th, .heat td { padding: 0; }
.heat thead th { padding: 0 0 4px; }
/* Com table-layout:fixed quem define a largura da coluna é a PRIMEIRA linha,
   que aqui é o cabeçalho. Declarar a largura só no td não adianta: a coluna
   sai com a largura que o th receber. */
.heat__hora { min-width: 56px; max-width: 64px; }
.heat__h {
  min-width: 64px; max-width: 220px; font-size: 11.5px; font-weight: 700;
  letter-spacing: .03em; text-transform: uppercase; color: var(--text-3); text-align: center;
}
.heat tbody th {
  text-align: left; font-size: 13px; font-weight: 650; padding-right: 12px;
  white-space: nowrap; color: var(--text-2); font-variant-numeric: tabular-nums;
  height: var(--heat-row-h, 44px);
}
/*
 * `--heat-row-h` é escrita via JS (horarios-pico.js, `ajustarAlturaHeatmap`)
 * medindo o espaço real que sobra na viewport — só em desktop, onde "a
 * tela inteira sem rolar" é exigência. Sem JS ainda rodado (ou fora do
 * desktop) cai no fallback de 44px, que é só o ponto de partida — a
 * media query de celular abaixo pisa por cima dele de qualquer jeito.
 */
.heat__cel {
  min-width: 64px; max-width: 220px; height: var(--heat-row-h, 44px);
  text-align: center; vertical-align: middle;
  font-size: 14px; font-weight: 750; font-variant-numeric: tabular-nums;
  border: 2px solid var(--surface); border-radius: var(--r-sm);
  transition: border-color .12s, box-shadow .12s;
}
.heat__cel:not(.heat__cel--off):hover { box-shadow: inset 0 0 0 2px var(--on-solid); opacity: .92; }
/* Linha comprimida (viewport baixa): letra desce um degrau, nunca dois —
   piso é 11px, ainda legível. */
.heat--compact .heat__cel { font-size: 11px; font-weight: 700; }
.heat--compact .heat tbody th, .heat--compact.heat tbody th { font-size: 11.5px; }
/* Com `.heat` esticando pra 100% (ver acima), poucas colunas num card
   largo estufariam cada célula bem além do quadrado — max-width segura
   isso, e esta regra centraliza a tabela no espaço que sobrar em vez de
   deixá-la grudada à esquerda com um vão vazio do lado direito. */
.table-wrap:has(.heat) { display: flex; justify-content: center; }
/* Fechado tem tratamento próprio: fundo neutro e borda tracejada. Sem isso
   ele viraria "0% de ocupação", que é outra informação. */
.heat__cel--off { background: var(--surface-2); border: 2px dashed var(--border); }
.heat__legenda { gap: 12px; flex-wrap: wrap; }
@media (max-width: 720px) {
  .heat__cel, .heat__h { min-width: 38px; max-width: 60px; }
  .heat__hora { min-width: 40px; max-width: 44px; }
  .heat__cel, .heat tbody th { height: 34px; }
  .heat__cel { font-size: 11px; }
  .heat tbody th { font-size: 11.5px; padding-right: 6px; }
}

/* ------------------------------------------------- FILTERBAR (Horários
   de pico — mesmo padrão de filtro que o resto do painel: periodPicker
   + selects direto em .filterbar, sem rótulo em cima nem botão
   "Aplicar"; só o respiro entre os controles é próprio desta tela). */
.hp-filterbar { gap: 12px; }
@media (max-width: 640px) {
  /* Pedido explícito: 2 colunas no celular pra essa tela (o padrão
     global de .kpis vira 1 coluna abaixo de 640px — aqui o seletor mais
     específico (.hp-kpis .kpis) vence sem tocar nas outras telas). */
  .hp-kpis .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---------------------------------------------- ESPAÇO VERTICAL, DESKTOP
   Horários de pico precisa caber numa tela só (>=1024px, sem rolar) —
   isso só sobra reduzindo o respiro FIXO em volta do mapa, não a área
   dele. Escopado por classe pra nenhuma outra tela herdar o aperto. */
@media (min-width: 1024px) {
  .hp-page { padding-top: 14px; padding-bottom: 14px; }
  .hp-page .page-head { margin-bottom: 12px; }
  .hp-filterbar { margin-bottom: 10px; }
  .hp-kpis .kpis { margin-bottom: 10px; }
  .hp-kpis .kpis--compacto > .kpi { padding: 9px 12px; }
  .heat__card { margin-top: 8px; }
  .heat__card .card__head { padding: 10px 16px; }
  .heat__card .card__body { padding: 10px 16px 6px; }
  .heat__card .card__body > .mt-2 { margin-top: 4px; }
}

.dash__data { display: flex; flex-direction: column; gap: 2px; }

@media (max-width: 640px) {
  .kpis--destaque .kpi__value { font-size: 24px; }
  .kpis--destaque > .kpi { min-height: 0; }
  .page--dashboard .kpis--destaque .kpi__value {
    overflow-wrap: normal; word-break: normal; white-space: nowrap;
    font-size: clamp(19px, 6.4vw, 24px);
  }
  .page--dashboard .kpis--compacto .kpi__value {
    overflow-wrap: normal; word-break: normal; white-space: nowrap;
    font-size: clamp(16px, 5.8vw, 22px);
  }
  .dash__data { flex: 1 1 45%; }
  /* Os 4 KPIs de "Visão geral" pedem 2 colunas mesmo no mobile — 1 coluna
     só aqui deixaria 4 cartões grandes empilhados antes de qualquer outro
     conteúdo da tela. */
  .kpis--destaque { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Fidelidade: "Participantes"/"Pontos disponíveis"/"Recompensas
     resgatadas" têm palavra única longa demais pra coluna de 2 — mesma
     saída que Dashboard já usa (ver .page--dashboard em dashboard.css). */
  .page--fidelidade .kpis--destaque { grid-template-columns: 1fr; }
  /* Assinaturas: badges "X cobrança(s) falharam"/"X cancelamento(s)" no
     rodapé não cabem nos 114px da coluna de 2 — mesmo caso acima. */
  .page--assinaturas .kpis--destaque { grid-template-columns: 1fr; }
}

/* ------------------------------------------------ resumo da equipe */
.prof__resumo {
  display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 14px;
}
.prof__resumo-item {
  display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-full); padding: 7px 15px;
}
.prof__resumo-num { font-size: 17px; font-weight: 700; letter-spacing: -.02em; }
.prof__resumo-lbl { font-size: 12.5px; color: var(--text-2); }

@media (max-width: 640px) {
  .prof__resumo-item { flex: 1 1 100%; border-radius: var(--r); justify-content: flex-start; }
}

/* ------------------------------------------------------------ MEU PLANO */
.pl__nome { font-size: 20px; font-weight: 700; }
.pl__limite { margin-top: 14px; }
.pl__limite:first-of-type { margin-top: 6px; }
.pl__recursos {
  display: grid; gap: 6px 14px;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
}
.pl__rec { display: flex; align-items: center; gap: 7px; font-size: 13px; }
.pl__rec svg { width: 15px; height: 15px; flex: none; }
.pl__rec--sim { color: var(--text); }
.pl__rec--sim svg { color: var(--green); }
/* Recurso que não está no plano fica visível, e apagado. Esconder faria a
   casa nunca descobrir que existe — e é justamente o que se quer vender. */
.pl__rec--nao { color: var(--text-3); }

/* -------------------------------------------------------- BAR / COZINHA */
.prep__resumo { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }
.prep__grade {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
}
.prep__card {
  border: 1px solid var(--border); border-left: 4px solid var(--border);
  border-radius: var(--r-sm); padding: 12px 14px; background: var(--surface-2);
}
/* A cor é a fila inteira lida de longe: quem está no fundo da loja
   precisa saber o que fazer sem chegar perto do tablet. */
.prep__card--pendente { border-left-color: var(--text-3); }
.prep__card--fazendo  { border-left-color: var(--amber); }
.prep__card--pronto   { border-left-color: var(--green); }
.prep__qty { font-weight: 700; margin-right: 6px; }
.prep__nome { font-weight: 600; }
.prep__espera { font-size: 12px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.prep__espera--tarde { color: var(--red); font-weight: 700; }

/* =====================================================================
   DESIGN SYSTEM — as peças que todas as telas compartilham
   ---------------------------------------------------------------------
   Escrito depois de percorrer as 54 telas do painel. O que estava
   duplicado virou uma regra só; o que cada tela inventava sozinha (barra
   de filtros, título de seção, estado vazio) ganhou um padrão.

   Nada aqui muda comportamento: são classes novas e refinamentos de
   classes que já existiam. Marcação antiga continua válida.
   ===================================================================== */

/* ------------------------------------------------- CABEÇALHO DE PÁGINA */
/*
 * A estrutura é sempre a mesma: identificação à esquerda, ações à direita.
 * A descrição é o que faltava — 39 telas tinham só o <h1>, e "Financeiro"
 * sozinho não diz se aquela tela é o DRE, o caixa ou as contas a pagar.
 */
.page-head {
  display: flex; align-items: flex-start; gap: var(--sp-2);
  flex-wrap: wrap; margin-bottom: var(--sp-4);
}
/*
 * Achado real (harness QA V18.2, super admin, 320px): flex:0 0 auto
 * proíbe o <h1> de encolher — ele mantém a largura de uma linha só
 * inteira mesmo sem espaço, e como ninguém aqui pediu white-space:
 * nowrap, o texto SÓ não quebra porque flex-shrink:0 nunca deixa a
 * caixa ficar menor que o conteúdo inteiro. Título curto ("Dashboard")
 * nunca mostrou o problema; "Configurações da plataforma" estourou a
 * tela em 29px. flex:1 1 auto + min-width:0 deixa a quebra de linha
 * (que o CSS já permitia) realmente acontecer.
 */
.page-head h1 { flex: 1 1 auto; min-width: 0; }
.page-head__id { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.page-head__id .inline { gap: var(--sp-1); }
.page-head__desc {
  font-size: 13px; color: var(--text-2); line-height: 1.45;
  /* Fase "cabeçalhos" — achado real: 62ch (~496px) prendia a descrição a
     uma faixa estreita mesmo quando sobrava mais de 200px vazios antes
     das ações começarem. `page-head__id` é `flex:0 1 auto` (some não
     force largura), então soltar este teto é o que basta pra ele ocupar
     o espaço de verdade disponível — sem crescer além do razoável nem
     brigar com as ações quando a tela aperta (flex-wrap cuida disso). */
  max-width: 820px;
}
/* Ações: agrupadas, alinhadas ao topo, nunca cortadas no celular. */
.page-head__actions {
  display: flex; align-items: center; gap: var(--sp-1);
  flex-wrap: wrap; margin-left: auto;
}
@media (max-width: 640px) {
  .page-head { gap: var(--sp-1); }
  .page-head__actions { margin-left: 0; width: 100%; }
  .page-head__actions > .btn { flex: 1 1 auto; }
  .page-head__desc { font-size: 12.5px; }
}

/* -------------------------------------------------- TÍTULO DE SEÇÃO */
/* Era `.dash__sub`, só no dashboard. Separar "destaque" de "secundário"
   é o que impede uma tela de virar doze números com o mesmo peso, e isso
   serve para Financeiro, Produtos e Assinaturas do mesmo jeito. */
.section-title, .dash__sub {
  font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--text-3); margin: var(--sp-5) 0 var(--sp-2);
  display: flex; align-items: center; gap: var(--sp-1);
}
.section-title:first-child, .dash__sub:first-child { margin-top: 0; }
.section-title svg { width: 14px; height: 14px; opacity: .7; }
.drill-ico svg { width: 12px; height: 12px; opacity: .6; }
.section-title__linha { flex: 1 1 auto; height: 1px; background: var(--border); }

/* ------------------------------------------------------ BARRA DE FILTROS */
/*
 * Cada tela montava a própria linha de filtros com `.inline inline--wrap`
 * e larguras a olho: em 1440px alguns campos esticavam para 400px e
 * outros ficavam com 90px, na mesma linha.
 *
 * Aqui todos os campos têm a mesma base e crescem juntos. A busca é a
 * única que ganha prioridade de largura, porque é o campo que se usa.
 */
/*
 * align-items: flex-start, não center — quando um grupo tem mais campos
 * do que cabe na linha (ex.: unidade+profissional+serviço+segmento) ele
 * quebra em 2 linhas por dentro e fica mais alto que os outros grupos;
 * com "center" os grupos de 1 linha (período, busca) flutuavam soltos no
 * meio do vão entre as duas linhas do grupo mais alto, em vez de
 * alinhados com a primeira linha de campos.
 */
.filterbar {
  display: flex; align-items: flex-start; gap: var(--sp-1);
  flex-wrap: wrap; margin-bottom: var(--sp-3);
}
/* Fase 3.2 — mesma ideia de .ags__grupo/.blk__grupo, versão genérica
   pra qualquer tela que já usa `.filterbar`: grupo (período/histórico,
   filtros, busca) com respiro MAIOR entre grupos que dentro de cada um,
   sem precisar de rótulo "Período"/"Filtros" escrito. */
.filterbar--agrupada { gap: 20px; }
.filterbar__grupo { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.filterbar > .input,
.filterbar > .select,
.filterbar__grupo > .input,
.filterbar__grupo > .select { flex: 1 1 168px; min-width: 132px; max-width: 260px; height: 38px; }
.filterbar > .filterbar__busca { flex: 2 1 240px; max-width: 380px; }
.filterbar > .btn { flex: 0 0 auto; }
.filterbar__sep { flex: 1 1 auto; }
/* Contador de filtros ativos: "Filtros (3)". Sem ele o usuário não
   descobre por que a lista está curta. */
.filterbar__n {
  background: var(--brand-action); color: var(--brand-fg);
  border-radius: var(--r-full); padding: 0 6px; margin-left: 2px;
  font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums;
}
/* Busca com lupa dentro do campo. */
.searchbox { position: relative; display: flex; flex: 2 1 240px; max-width: 380px; }
.searchbox > .input { padding-left: 34px; height: 38px; }
.searchbox > svg {
  position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; color: var(--text-3); pointer-events: none;
}
@media (max-width: 640px) {
  /*
   * Redesign V3, Fase 2: até aqui TODO select/input de `.filterbar` virava
   * 100% da largura no celular, então período + 1 filtro (ex.: profissional)
   * sempre empilhava, mesmo cabendo os dois lado a lado — a mesma regra de
   * `.pp__trigger` ali em cima. Sem o teto de 100%, os controles herdam o
   * flex-basis de sempre (168px, ver regra de desktop, algumas linhas
   * acima) e encolhem/​quebram linha sozinhos conforme o espaço real —
   * 2 cabem tranquilo até 320px, 3+ quebram em duas fileiras em vez de
   * uma por campo. Busca continua 100% (digitar precisa de espaço).
   */
  .searchbox { flex: 1 1 100%; max-width: none; }
}

/* ================================================================
   PERIOD PICKER — período único, reutilizável em todo o painel
   (componente em ui.js: periodPicker()) — ver comentário lá para o porquê.
   ================================================================ */
.pp__trigger { justify-content: space-between; min-width: 216px; }
.pp__trigger svg:last-child { opacity: .55; width: 15px; height: 15px; flex: 0 0 auto; }
.pp__trigger span { flex: 1 1 auto; text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.pp__painel { width: max-content; max-width: calc(100vw - 24px); }
.pp__painel--flutuante {
  position: fixed; z-index: 210;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--sh-3);
  /* Coluna: se ui.js travar a altura (viewport baixa demais pro painel
     inteiro), só o corpo rola — o rodapé (Cancelar/Aplicar) nunca some. */
  display: flex; flex-direction: column;
}
.pp__corpo { display: flex; gap: var(--sp-4); padding: var(--sp-4); flex: 1 1 auto; overflow-y: auto; min-height: 0; }
.pp__atalhos { display: flex; flex-direction: column; gap: 3px; flex: 0 0 152px; }
.pp__atalho {
  text-align: left; padding: 8px 10px; border-radius: var(--r-sm);
  border: 0; background: transparent; color: var(--text-2);
  font: inherit; font-size: 13.5px; font-weight: 550; cursor: pointer;
}
.pp__atalho:hover { background: var(--surface-3); color: var(--text); }
/* Pendente até "Aplicar" confirmar — mesma cor do dia selecionado no
   calendário ao lado (.pp__dia--ponta), pra ler como "a mesma escolha". */
.pp__atalho.is-active, .pp__atalho.is-active:hover { background: var(--brand-action); color: var(--brand-fg); font-weight: 650; }
.pp__cal-nav { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--sp-2); gap: 8px; }
.pp__cal-meses { display: flex; gap: 8px; font-size: 13.5px; font-weight: 650; text-transform: capitalize; }
.pp__cal-sep { opacity: .4; font-weight: 400; }
.pp__grades { display: flex; gap: var(--sp-4); }
.pp__mes { width: 224px; }
.pp__dow, .pp__grid { display: grid; grid-template-columns: repeat(7, 1fr); }
.pp__dow span { text-align: center; font-size: 11px; color: var(--text-3); padding-bottom: 4px; }
.pp__grid { gap: 2px; }
.pp__dia {
  aspect-ratio: 1; border: 0; background: transparent; color: var(--text);
  border-radius: var(--r-sm); font: inherit; font-size: 13px; cursor: pointer;
}
.pp__dia:hover:not(:disabled) { background: var(--surface-3); }
.pp__dia:disabled { color: var(--text-disabled); cursor: default; }
.pp__dia--fora { visibility: hidden; }
.pp__dia--hoje { font-weight: 700; box-shadow: inset 0 0 0 1px var(--border-strong); }
.pp__dia--meio { background: color-mix(in srgb, var(--brand) 14%, transparent); border-radius: 0; }
.pp__dia--ponta { background: var(--brand-action); color: var(--brand-fg); font-weight: 650; }
.pp__rodape { display: flex; justify-content: flex-end; gap: 8px; padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--border); flex: 0 0 auto; }

@media (max-width: 640px) {
  /*
   * Redesign V3, Fase 2: o gatilho não pode mais tomar a linha inteira
   * por padrão — antes disso, QUALQUER tela com período + outro(s)
   * filtro(s) empilhava tudo, um campo por linha, mesmo tendo espaço de
   * sobra. `flex:1 1 140px` (em vez do `width:100%` de antes) deixa 2-3
   * campos dividirem a fileira quando cabem, e ainda quebra linha
   * sozinho quando são muitos (3-4 selects não ficam espremidos numa
   * fileira só — ver `.filterbar--compacta` logo abaixo pro caso
   * garantido de só 2 itens, onde nunca deve quebrar).
   *
   * Precisa ser `.filterbar > .pp__trigger` (não só `.pp__trigger`): o
   * gatilho é um `<button class="btn pp__trigger">`, e `.filterbar > .btn`
   * (acima, regra de sempre pra botão de ação não esticar) tem a MESMA
   * especificidade de duas classes — só ganhando por especificidade
   * também (não só posição no arquivo) o corte de 100% realmente sai.
   */
  .pp__trigger { flex: 1 1 140px; min-width: 0; width: auto; }
  .filterbar > .pp__trigger { flex: 1 1 140px; min-width: 0; width: auto; }

  /*
   * Achado testando 320px de verdade: mesmo com flex-basis pequeno, a
   * decisão de quebrar linha do flexbox olha pro basis + min-width de
   * CADA item, não pro quanto ele consegue encolher — período (140px) +
   * select no piso de 132px passava dos ~292px úteis em 320px e quebrava
   * do mesmo jeito. `.filterbar--compacta` é só pra telas que GARANTEM no
   * máximo 2 controles sempre visíveis (período + 1 select — Dashboard,
   * Meu painel, Avaliações, Financeiro): `flex-basis:0` tira esse cálculo
   * da jogada (a base pra decidir quebra vira zero pros dois, cabe
   * sempre), e quem decide a largura de verdade depois é o flex-grow.
   * NÃO usar em telas com 3+ filtros sempre visíveis — cramaria tudo
   * numa fileira ilegível em vez de quebrar (o objetivo ali é o oposto).
   */
  .filterbar--compacta { flex-wrap: nowrap; }
  .filterbar--compacta > .pp__trigger { flex: 1 1 0; min-width: 0; width: auto; }
  .filterbar--compacta > .select, .filterbar--compacta > .input { flex: 1.2 1 0; min-width: 0; max-width: none; }
  .pp__painel { width: 100%; }
  .pp__corpo { flex-direction: column; padding: 0; gap: var(--sp-3); }
  .pp__atalhos { flex-direction: row; flex-wrap: nowrap; flex: 0 0 auto; gap: 4px; }
  /*
   * 5 atalhos canônicos (Hoje/Ontem/7 dias/30 dias/Máximo, ver ppPresets()
   * em ui.js) numa fileira só, sem rolagem — pedido explícito. "flex:1 1 0"
   * dá a mesma largura pros 5; padding/fonte/gap um pouco menores só aqui
   * (o resto do painel usa .btn no tamanho normal). Achado testando
   * 320px de verdade: "Máximo" é uma palavra só (não quebra linha como
   * "30 dias" quebra no espaço) — cortava por 2px com padding de 4px;
   * 2px de padding lateral é o suficiente pra caber inteiro, sem cortar.
   */
  /* Achado (QA de toque, dispositivo real): padding vertical de 7px
     media ~33px de área clicável — abaixo da faixa confortável de toque
     (~44px). `min-height` + flex garante o alvo de toque sem depender
     de line-height/fonte pra centralizar; o texto continua do mesmo
     tamanho visual, só a área que responde ao toque cresce. */
  .pp__atalho {
    flex: 1 1 0; min-width: 0; min-height: 44px; padding: 0 2px;
    display: flex; align-items: center; justify-content: center;
    font-size: 12.5px; text-align: center; background: var(--surface-2);
  }
  /* Achado (pedido explícito, comparado com a referência visual): o
     calendário esticado de ponta a ponta da tela lia como "componente
     desktop mal encaixado no celular" — célula de 46-47px de lado numa
     grade que já não precisa de tanto espaço pra caber um dígito de
     1-2 números. `min(320px, 100%)` mira ~44px de célula (alvo de
     toque confortável) quando a tela tem espaço (375px+) e centraliza a
     grade em vez de esticar; em 320px o próprio limite físico da tela
     ainda decide (100% vence o min ali, ~39px — inevitável com 7
     colunas numa tela de 320px, mesmo cálculo de antes). */
  .pp__mes { width: min(320px, 100%); margin: 0 auto; }
  .pp__grades { flex-direction: column; }
  .pp__rodape { padding: var(--sp-3) 0 0; }
}

/* Fase 3.3: no mobile o rodapé (Cancelar/Aplicar) virou o `footer` FIXO
   do modal (ver ppAbrirPainel() em ui.js) em vez de ficar dentro do
   corpo rolável — sem isto, tinha que rolar o calendário inteiro pra
   alcançar os botões. `.modal__foot` já tem seu próprio padding/borda/
   fundo; sem este reset, dobrava tudo (duas bordas, dois espaçamentos). */
.modal__foot .pp__rodape { padding: 0; border-top: 0; background: transparent; }

/* Meu painel: estado de "sem acesso" compacto e centralizado — não um
   card cheio ocupando a tela inteira. Ver meu-painel.js. */
/* Fase 3.1: 15vh de margem empurrava o card pro meio da tela e deixava
   tudo acima em branco — "compacto" não é "flutuando no vazio". 48px é
   respiro suficiente sem fingir que há mais conteúdo vindo depois. */
.mp-negado {
  max-width: 380px; margin: 48px auto 0; text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
}
.mp-negado svg { width: 28px; height: 28px; color: var(--text-3); }
.mp-negado__titulo { font-weight: 650; font-size: 15px; }
.mp-negado__texto { font-size: 13px; color: var(--text-2); line-height: 1.6; }

/*
 * Fase 3.2 — linha de resumo compacta, usada em Lista de espera,
 * Avaliações, Fidelidade e Clientes ("Desempenho"/"Também no período"/
 * "Resumo do período"). Era texto corrido dentro de um `.inline` com
 * `gap:16px` e `font-size:12px` (`.tiny`) — lia como frase apertada,
 * não como estatística. Rótulo em cima, valor embaixo, respiro de
 * verdade entre cada uma — mesma ideia de `.kpi`, sem virar cartão.
 */
.resumo-linha {
  display: flex; flex-wrap: wrap; align-items: center; gap: 24px;
  padding: 14px 18px; margin-bottom: var(--sp-3);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
}
.resumo-linha__titulo {
  text-transform: uppercase; letter-spacing: .04em; font-size: 11px; font-weight: 700;
  color: var(--text-2); flex: 0 0 auto;
}
.resumo-linha__stat { display: flex; flex-direction: column; gap: 3px; }
.resumo-linha__label { font-size: 12px; color: var(--text-3); white-space: nowrap; }
.resumo-linha__valor { font-size: 13.5px; font-weight: 650; color: var(--text); }
@media (max-width: 480px) {
  .resumo-linha { flex-direction: column; align-items: flex-start; gap: 14px; padding: 14px 16px; }
}

/* ------------------------------------------------------------- KPI */
/*
 * Duas faixas, sempre: quatro números que respondem "como foi o período"
 * e o resto numa faixa menor. `.kpis--destaque` e `.kpis--compacto` já
 * existiam no dashboard; aqui viram o padrão do sistema.
 */
.kpi__label svg { width: 14px; height: 14px; opacity: .65; flex: 0 0 14px; }
/*
 * Migração v76: ícone circular grande à ESQUERDA, em linha com o corpo
 * (flex real) — não mais um marcador pequeno no canto absoluto. Valores
 * (52px, radial-gradient 12%→3%, brilho interno, borda 46%) extraídos
 * ao vivo da referência (.kpi-icon, Dashboard e Clientes). V76 não
 * varia a cor do ícone por "tom" — é sempre dourado, em qualquer
 * cartão — por isso os modificadores --brand/--green/--red/--amber/
 * --blue/--violet (ainda aceitos por quem já chama kpiCard({tone})) não
 * mudam mais a cor: o parâmetro continua funcionando sem quebrar quem
 * já usa, só para de pintar variações que a referência não tem.
 *
 * Isto substitui DOIS blocos antigos que se sobrepunham (um cortava o
 * ícone no canto com cor por tom, outro — de uma rodada posterior —
 * já tinha neutralizado a cor mas mantido a posição absoluta errada) —
 * consolidados numa regra só, pedido explícito desta migração.
 */
/*
 * Achado real (validação WhatsApp/Atendente IA): existe pelo menos um
 * uso local de `.kpi` fora do kpiCard() compartilhado (kpiIA() em
 * whatsapp.js) que nunca teve ícone — só label+value, sem `.kpi__corpo`.
 * `display:flex` incondicional jogava os dois lado a lado (era bloco
 * empilhado). Escopado a `:has(.kpi__ico)` afeta só quem realmente tem
 * ícone (kpiCard() sempre embrulha certo — ver ui.js); quem não tem
 * ícone continua exatamente como sempre foi, sem precisar tocar em
 * cada arquivo que usa `.kpi` cru.
 */
.kpi:has(.kpi__ico) { display: flex; align-items: flex-start; gap: 14px; position: relative; }
.kpi__corpo { min-width: 0; flex: 1 1 auto; }
.kpi__ico {
  flex: 0 0 auto; width: 52px; height: 52px; border-radius: 50%;
  display: grid; place-items: center;
  background: radial-gradient(circle, color-mix(in srgb, var(--brand) 12%, transparent), color-mix(in srgb, var(--brand) 3%, transparent));
  box-shadow: inset 0 0 20px color-mix(in srgb, var(--brand) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--brand) 46%, transparent);
  color: var(--brand-text, var(--brand));
}
.kpi__ico svg { width: 25px; height: 25px; }
@media (max-width: 640px) {
  .kpi__ico { width: 40px; height: 40px; }
  .kpi__ico svg { width: 19px; height: 19px; }
}
/* Rodapé do cartão: subtexto à esquerda, variação à direita. */
.kpi__rodape { display: flex; align-items: baseline; gap: var(--sp-1); margin-top: 4px; min-width: 0; }
.kpi__rodape .kpi__hint {
  margin-top: 0; flex: 1 1 auto; min-width: 0;
  overflow: visible; text-overflow: clip; white-space: normal; overflow-wrap: anywhere;
}
.kpi__rodape > .badge { max-width: 100%; white-space: normal; overflow-wrap: anywhere; }

/*
 * Cards "Lembrete de agendamento"/"Aniversário do cliente" (Marketing →
 * Painel). Achado real do bug visual: icon() (ui/ui.js) monta um <svg
 * viewBox="0 0 24 24"> sem width/height nenhum — o tamanho sempre veio
 * de fora, da classe do contexto que usa o ícone (este projeto nunca
 * teve uma regra global tipo `svg { width... }`; cada lugar tem a
 * própria, ver .kpi__ico/.tab/.nav__item acima). Estes dois cards
 * jogavam o ícone solto dentro de um `.inline` sem NENHUMA classe de
 * tamanho — o SVG caía no tamanho intrínseco do navegador (~300px) e
 * tomava o card inteiro. width/height/max-width/max-height/flex-shrink
 * explícitos nos dois níveis (caixa e svg) pra nunca mais regredir.
 */
.au-card .card__body { padding: 20px; }
.au-card__head { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 2px; }
.au-card__ico {
  width: 44px; height: 44px; max-width: 44px; max-height: 44px; flex: 0 0 44px; flex-shrink: 0;
  border-radius: var(--r-sm);
  display: grid; place-items: center;
  background: var(--surface-3); color: var(--text-3);
}
.au-card__ico svg { width: 22px; height: 22px; max-width: 22px; max-height: 22px; flex-shrink: 0; }
.au-card__title { font-weight: 600; flex: 1 1 auto; min-width: 0; }
@media (max-width: 640px) {
  .au-card .card__body { padding: 18px; }
  .au-card__ico { width: 40px; height: 40px; max-width: 40px; max-height: 40px; flex: 0 0 40px; }
  .au-card__ico svg { width: 20px; height: 20px; max-width: 20px; max-height: 20px; }
}

/* Cartão clicável leva para o detalhe. Precisa parecer clicável. */
.kpi.is-clickable { cursor: pointer; transition: border-color .12s, transform .12s; }
.kpi.is-clickable:hover { border-color: var(--border-strong); transform: translateY(-1px); }

/* --------------------------------------------------------- ESTADO VAZIO */
/*
 * Antes: 44px de padding em cima e embaixo, ícone de 42px, e uma tela de
 * agendamentos sem resultado virava meia página em branco com "Nenhum
 * registro" no meio.
 *
 * Agora o padrão é compacto e cabe dentro do card junto com os filtros,
 * que é onde o usuário está olhando. `.empty--lg` fica para o caso raro em
 * que a tela inteira está vazia (primeiro acesso).
 *
 * Fase 3.1: ainda mais enxuto — medido de verdade num card real (não só
 * calculado): com padding de 18px o card ao redor (mais os 16px de
 * .card__body) fechava perto de 195px, acima da faixa pedida (100-170px).
 * 14px de padding + ícone de 24px mede ~155-165px com o card ao redor
 * para um texto de 1-2 linhas — dentro da faixa, conferido no navegador.
 */
.empty { text-align: center; padding: 14px var(--sp-4); color: var(--text-3); }
.empty svg { width: 24px; height: 24px; margin: 0 auto 6px; opacity: .45; }
.empty__title { font-size: 14.5px; font-weight: 650; color: var(--text-2); margin-bottom: 4px; }
.empty__text { font-size: 13px; max-width: 42ch; margin: 0 auto; line-height: 1.5; }
.empty__acoes {
  display: flex; gap: var(--sp-1); justify-content: center;
  flex-wrap: wrap; margin-top: var(--sp-3);
}
.empty--lg { padding: 56px var(--sp-4); }
.empty--lg svg { width: 44px; height: 44px; }
/*
 * `compact`: pra painel secundário que já tem card__head próprio em cima
 * (Distribuição das notas, Saldos por cliente...) — o `.empty` padrão
 * (14px + ícone de 24px) ainda soma ~155-165px DEPOIS do header do card,
 * o que empilhado com outro painel do lado vira dois blocos grandes e
 * vazios. Aqui o ícone cai pra 18px e o padding pela metade — cabe em
 * ~90-100px com o header, sem cortar título/texto de 1-2 linhas.
 */
.empty--compact { padding: 8px var(--sp-4) 6px; }
.empty--compact svg { width: 18px; height: 18px; margin-bottom: 4px; }
.empty--compact .empty__title { font-size: 13px; margin-bottom: 2px; }
.empty--compact .empty__text { font-size: 12px; }
.empty--lg .empty__title { font-size: 17px; }

/*
 * Redesign V3, Fase 2 (correção de checkpoint) — `errorState()` reaproveita
 * toda a estrutura de `.empty` (mesmo HTML, mesmo componente), mas "não
 * consegui carregar" precisa se distinguir de "não há nada aqui" num
 * relance, sem precisar ler o texto. Só o ícone e o título ganham o tom de
 * perigo; o corpo (`.empty__text`) continua no cinza neutro de sempre —
 * pintar o card inteiro de vermelho por causa de uma falha de rede seria
 * o tipo de saturação que o design system evita em outro lugar qualquer.
 */
.empty--error svg { opacity: .85; color: var(--red); }
.empty--error .empty__title { color: var(--red); }

/*
 * Redesign V3, Fase 6 (recompra) — mesmo aviso desta seção 1544 se
 * repetiu aqui: o ícone de "recompra vencida" (Retenção) e o de
 * "período de recompra configurado" (Serviços) ficaram sem um `svg`
 * escopado, e esticaram pra preencher o cartão/linha inteira.
 */
.rt__cartao svg { width: 13px; height: 13px; flex: 0 0 13px; vertical-align: -2px; }
.rt__tabela svg { width: 13px; height: 13px; flex: 0 0 13px; vertical-align: -2px; }
.svc-list__fim .badge svg { width: 12px; height: 12px; flex: 0 0 12px; vertical-align: -1px; }

/* --------------------------------------------------------------- ALERTA */
/* Aviso dentro da página: sem ícone gigante, sem cor berrante. */
.alert {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 11px 13px; border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--surface-2);
  font-size: 13px; line-height: 1.5;
}
.alert svg { width: 17px; height: 17px; flex: 0 0 17px; margin-top: 1px; }
.alert b { font-weight: 650; }
.alert__corpo { flex: 1 1 auto; min-width: 0; }
.alert--info  { border-color: color-mix(in srgb, var(--blue) 34%, transparent);  background: color-mix(in srgb, var(--blue) 9%, var(--surface)); }
.alert--info svg { color: var(--blue); }
.alert--warn  { border-color: color-mix(in srgb, var(--amber) 34%, transparent); background: color-mix(in srgb, var(--amber) 9%, var(--surface)); }
.alert--warn svg { color: var(--amber); }

/* Bloqueados (#/bloqueados): ícone da regra em vigor e aviso de horário
   futuro na linha do cliente — sem regra própria, o svg sem width/height
   cai no tamanho padrão do navegador (either colapsa a 0 dentro do flex,
   ou estoura pro tamanho intrínseco, dependendo do contexto). */
.blq-regra__ico { flex: 0 0 auto; }
.blq-regra__ico svg { width: 18px; height: 18px; flex: 0 0 18px; }
.blq-futuros { display: flex; align-items: center; gap: 4px; }
.blq-futuros svg { width: 13px; height: 13px; flex: 0 0 13px; }
.alert--error { border-color: color-mix(in srgb, var(--red) 34%, transparent);   background: color-mix(in srgb, var(--red) 9%, var(--surface)); }
.alert--error svg { color: var(--red); }
.alert--ok    { border-color: color-mix(in srgb, var(--green) 34%, transparent); background: color-mix(in srgb, var(--green) 9%, var(--surface)); }
.alert--ok svg { color: var(--green); }

/* ------------------------------------------------------------ TOOLBAR */
/* Faixa de ações acima de uma tabela, dentro de um card. */
.toolbar {
  display: flex; align-items: center; gap: var(--sp-1); flex-wrap: wrap;
  padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--border);
}
.toolbar__titulo { font-size: 13.5px; font-weight: 650; }

/* --------------------------------------------------------------- FOCO */
/*
 * Acessibilidade: navegar por teclado sem anel de foco é navegar às
 * cegas. `:focus-visible` não aparece no clique de mouse, então não
 * atrapalha quem usa ponteiro.
 */
:where(button, a, [tabindex], .btn, .tab, .proftab, .seg-chip, .nav__item, .nav__cabeca):focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}
.input:focus-visible, .select:focus-visible, .textarea:focus-visible { outline: none; }

/* ------------------------------------------------------------- LARGURA */
/*
 * Em 1920px o conteúdo parava em 1500px e sobrava vazio dos dois lados;
 * telas de tabela, que só precisam de largura, ficavam espremidas por
 * nada. A régua sobe com a tela, e o texto corrido continua limitado por
 * `max-width` no próprio bloco.
 */
@media (min-width: 1700px) { .page { max-width: 1720px; } }

/* ---------------------------------------------------------- SKELETON */
.sk-linha { height: 13px; border-radius: 5px; }
.sk-bloco { height: 96px; border-radius: var(--r-lg); }
@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; }
  .btn:active { transform: none; }
  .kpi.is-clickable:hover { transform: none; }
}

/* ------------------------------------------------- ROLAGEM QUE NÃO VAZA */
/*
 * Bug real, medido: em 790px de largura o Financeiro empurrava 138px de
 * rolagem horizontal no DOCUMENTO — a página inteira andava para o lado,
 * cabeçalho e sidebar junto.
 *
 * A causa não é a barra de abas: ela já tem `overflow-x: auto` e deveria
 * rolar sozinha. É que item de flex tem `min-width: auto` por padrão, ou
 * seja, ele se recusa a ficar menor que o conteúdo — e aí não há o que
 * rolar, o conteúdo simplesmente vaza.
 *
 * `min-width: 0` é o que permite o item encolher e a rolagem acontecer
 * DENTRO dele. Vale para toda faixa rolável do sistema: abas, chips e
 * tabelas largas.
 */
.page, #outlet > .view { min-width: 0; }
.tabs, .proftabs, .seg-chips, .table-wrap, .filterbar { min-width: 0; max-width: 100%; }
/* A tabela larga rola no envelope dela, e o envelope não estica a página */
.card > .table-wrap, .card__body > .table-wrap { max-width: 100%; }
/*
 * E a mesma causa, um nível acima: item de FLEX e de GRID também nasce com
 * `min-width: auto`. O gráfico do Financeiro está num card com
 * `flex: 2 1 380px` dentro de `.row` — o card se recusava a ficar menor
 * que as 31 colunas de barra, ia para 914px numa janela de 790px, e
 * arrastava o documento inteiro junto.
 *
 * `min-width: 0` nos filhos de `.row` e `.grid` é o que faz "flex: 1 1
 * 380px" significar de verdade "pode encolher". Sem isso, todo card que
 * contenha tabela, gráfico ou texto longo vira um estouro esperando
 * acontecer — e foi assim em toda tela estreita.
 */
.row > *, .grid > *, .kpis > * { min-width: 0; }

/* --------------------------------------------- OS DOIS ÚLTIMOS ESTOUROS */
/*
 * Em 375px sobravam dois, os dois pelo mesmo motivo: linha que não quebra
 * nem rola.
 *
 * `.segmented` (Metas: "% da meta / Faturamento / Atendimentos /
 * Produtos") pede 367px num viewport de 375 menos o padding. Rola, como
 * as abas — encolher a fonte tornaria os quatro rótulos ilegíveis, e
 * quebrar em duas linhas descaracterizaria o controle.
 */
.segmented {
  max-width: 100%; min-width: 0;
  overflow-x: auto; scrollbar-width: none;
}
.segmented::-webkit-scrollbar { display: none; }
.segmented button { flex: 0 0 auto; }

/*
 * `.inline` dentro do cabeçalho é sempre a barra de ferramentas da tela
 * (busca + filtro + ação). Em Unidades ela pedia 440px e empurrava a
 * página. No celular ela quebra; no desktop nada muda.
 */
@media (max-width: 640px) {
  .page-head .inline { flex-wrap: wrap; width: 100%; }
  .page-head .inline > .btn { flex: 1 1 auto; }
  .page-head .inline > .input, .page-head .inline > .select { flex: 1 1 160px; min-width: 0; }
}

/* =====================================================================
   SIDEBAR — refinamento
   ---------------------------------------------------------------------
   A estrutura ficou como estava: árvore de três níveis, uma categoria
   principal aberta por vez, poda por permissão e por recurso do plano,
   cadeado no que o plano não inclui. Isso já estava certo.

   O que muda é o acabamento.
   ===================================================================== */

/*
 * O item ativo era um retângulo sólido na cor da marca. Funciona, e é o
 * jeito de 2015: com a marca azul do tema escuro vira um bloco pesado no
 * meio de uma lista discreta, e puxa mais atenção que o conteúdo da
 * página.
 *
 * Trocado por fundo tênue da própria marca, texto na cor da marca e uma
 * barra à esquerda. Lê igual de longe, pesa muito menos, e continua
 * respeitando a cor que o tenant escolheu.
 */
/* Mistura com --surface, não com `transparent`: o resultado é uma cor
   sólida, que é o que o resto do projeto já usa (.svc-row.is-on) e o que
   compõe mais barato — camada com alpha sobre lista rolável é trabalho
   extra de composição a cada frame de scroll. */
.nav__item.is-active {
  background: rgba(212, 162, 96, .08);
  color: var(--nav-active-ink);
  font-weight: 700;
}
.nav__item.is-active svg { opacity: 1; color: var(--nav-active-ink); }

/* Categoria principal: um respiro entre os sete grupos. Sem isso eles
   correm juntos e a árvore vira uma lista só. */
.nav__pasta--n0 { margin-bottom: 3px; }
.nav__pasta--n0 + .nav__pasta--n0 { margin-top: 1px; }

/* A pasta que contém a página aberta fica marcada mesmo recolhida — já
   existia. Aqui ela ganha a cor da marca, não só o texto mais claro:
   recolhida, é o único sinal de onde a pessoa está. */
.nav__pasta--n0:has(.nav__item.is-active) > .nav__cabeca { color: var(--nav-active-ink); }
.nav__pasta--n0:has(.nav__item.is-active) > .nav__cabeca svg:first-of-type { color: var(--nav-active-ink); opacity: 1; }

/* Cadeado de recurso fora do plano: some no hover para não parecer botão */
.nav__item[data-locked] { opacity: .62; }
.nav__item[data-locked]:hover { opacity: .8; }

/*
 * Acessibilidade: no celular o item tinha 35px de altura. A recomendação
 * é 44px de área de toque — abaixo disso, dedo grande erra o alvo e abre
 * a tela errada, que num menu de 40 itens acontece o tempo todo.
 */
@media (max-width: 900px) {
  .nav__item, .nav__cabeca { padding-top: 11px; padding-bottom: 11px; }
  .nav__filhos .nav__item, .nav__filhos .nav__cabeca { padding-top: 10px; padding-bottom: 10px; }
  .sidebar { width: min(300px, 86vw); }
}

/* A rolagem do menu não arrasta a página atrás dele no celular. */
.sidebar__nav { overscroll-behavior: contain; }

/* -------------------------------------------------- LISTA PAGINADA */
/*
 * Rodapé de "mostrar mais". Fica claro que há mais coisa embaixo sem
 * fingir que a lista acabou — e diz quantos de quantos, que é a
 * informação que evita a pessoa achar que o filtro comeu registros.
 */
.lista__mais {
  display: flex; align-items: center; justify-content: center;
  gap: var(--sp-2); flex-wrap: wrap;
  padding: var(--sp-3) 0 var(--sp-1);
}

/* ================================================================
   MOVIMENTO REDUZIDO
   ----------------------------------------------------------------
   Bug real, medido no celular: com `prefers-reduced-motion: reduce`
   ligado — que é uma opção de acessibilidade do sistema, e vem ligada
   em alguns modos de economia de bateria — a animação `slideup` fica
   congelada em `currentTime: 0`.

   E `slideup` começa em `translateY(100%)`. Ou seja: o modal parava
   747px ABAIXO da tela, com os botões Cancelar e Salvar fora da
   viewport. Conferido em Clientes, Serviços, Produtos, Unidades e
   Cupons — os cinco iguais.

   Na prática, quem usa essa opção não conseguia cadastrar nada pelo
   celular. O painel inteiro depende de modal para criar registro.

   A causa de fundo é o padrão: usar animação para POSICIONAR. Enquanto
   a posição final depender do fim da animação, qualquer coisa que
   interrompa a animação deixa o elemento no lugar errado — aba em
   segundo plano, navegador economizando, ou esta opção.

   Aqui as animações de entrada saem inteiras. O elemento nasce no
   lugar certo, que é o que a diretriz pede de qualquer forma.
   ================================================================ */
@media (prefers-reduced-motion: reduce) {
  .modal, .modal__overlay, .toast, .cor-pop {
    animation: none !important;
    transform: none;
  }
  /* o modal no desktop é centrado por transform — esse precisa ficar */
  .modal { transform: translate(-50%, -50%); }
  .backdrop, .sidebar { transition: none !important; }
  .progress__bar, .switch__track, .switch__track::after { transition: none !important; }
  * { scroll-behavior: auto !important; }
}
@media (prefers-reduced-motion: reduce) and (max-width: 640px) {
  /* no celular ele é uma folha colada embaixo: sem transform nenhum */
  .modal { transform: none; }
}

/* =====================================================================
   DENSIDADE DOS CARTÕES DE LISTAGEM
   ---------------------------------------------------------------------
   Medido em 1440px: cartão de profissional com 420px de altura, de
   cliente com 358–374, de serviço com 316. Quatro por linha, e a tela de
   Profissionais inteira tem 640px — ou seja, quatro blocos enormes e mais
   nada. Rolar a lista de clientes custava 5.829px.

   O conteúdo está certo; o que está errado é o espaço entre ele. Cada
   linha de meta-informação ocupava a largura toda do cartão para dizer
   "3 serviços", e sobrava vazio à direita de cada uma.

   Aqui a meta vai para DUAS colunas, os respiros encolhem e a tipografia
   fica mais justa. Nenhuma informação sai do cartão.
   ===================================================================== */

/* --------------------------------------------------- PROFISSIONAIS */
.prof-card .card__body { padding: 13px 14px; }
.prof-card__meta {
  /* duas colunas: "sem telefone" e "3 serviços" não precisam de 340px
     cada uma. Telefone e unidade continuam podendo ocupar a linha toda
     quando o texto for longo, porque a coluna é `auto-fit`. */
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 4px 12px; margin-top: 10px; padding-top: 9px;
}
.prof-card__meta .inline { font-size: 11.5px; }
.prof-card__next { margin-top: 9px; padding: 6px 8px; font-size: 11.5px; }
/* "Sem meta definida para este mês" ocupava uma linha inteira de 15px
   para dizer que não há nada. Fica junto do resto. */
.prof-card .card__foot { padding: 9px 12px; }
.prof-card .avatar--lg { width: 46px; height: 46px; font-size: 16px; }

/* -------------------------------------------------------- CLIENTES */
.cli-card .card__body { padding: 13px 14px; }
.cli-card__meta {
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 4px 12px; margin-top: 9px;
}
.cli-card__meta .inline { font-size: 11.5px; }
.cli-card__nums { margin-top: 10px; }
.cli-card .card__foot { padding: 9px 12px; }

/* ---------------------------------------------------------- COMUM */
/*
 * Cartão de listagem clicável precisa parecer clicável e responder ao
 * toque. Antes só mudava a borda; agora sobe um fio de nada — o
 * suficiente para o olho registrar, longe de animação chamativa.
 */
.prof-card, .cli-card, .svc-card {
  transition: border-color .14s, box-shadow .14s, transform .14s;
}
.prof-card:hover, .cli-card:hover, .svc-card:hover { transform: translateY(-1px); }
.prof-card:active, .cli-card:active, .svc-card:active { transform: none; }
@media (prefers-reduced-motion: reduce) {
  .prof-card:hover, .cli-card:hover, .svc-card:hover { transform: none; }
}

/*
 * Grade de listagem: cartão de pessoa não precisa de 380px de largura.
 * Com 260 cabem quatro em 1180px e cinco em 1440 — a mesma informação,
 * menos rolagem, e nenhuma linha órfã porque `auto-fill` completa.
 */
.grid--cards {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(258px, 1fr));
}
/* Item de grid, por padrão, nunca encolhe abaixo do min-content do próprio
   conteúdo (min-width:auto implícito) — exatamente a mesma ambiguidade de
   flex-item que já apareceu em .ags__grupo. Sem isto, um rodapé de botões
   que não cabe força a COLUNA inteira (e o cartão) a crescer além do
   viewport, em vez de encolher/quebrar por dentro. */
.grid--cards > * { min-width: 0; }
@media (max-width: 640px) { .grid--cards { grid-template-columns: 1fr; gap: 10px; } }
/*
 * Achado real (varredura 320px, #/profissionais): mesmo com 1 coluna de
 * largura total, o cartão inteiro (prof-card/cli-card/svc-card) estourava
 * a página. Causa: o rodapé do cartão (.card__foot.inline) tem 2-3 botões
 * + .spacer numa linha sem quebra — "Ver ficha" + "Editar" + o ícone de
 * "mais ações" não cabem espremidos em ~290px, e um item flex sem
 * flex-wrap não encolhe abaixo do próprio conteúdo (min-width:auto por
 * padrão) — isso força a COLUNA DO GRID inteira a crescer para caber,
 * arrastando o cartão todo pra fora do viewport. Permitir quebra aqui é
 * inofensivo: na pior hipótese os botões vão para duas linhas, nunca para
 * fora da tela.
 */
@media (max-width: 480px) {
  .grid--cards .card__foot { flex-wrap: wrap; row-gap: 6px; }
}
.prof-card__meta-mes { margin-top: 9px; }
.prof-card__meta-mes .progress { height: 5px; }
/*
 * Os três números do cliente (visitas, gasto, ticket) tinham 11px de
 * respiro em cima e embaixo, mais duas bordas. Numa listagem de 60
 * cartões isso são 60 × ~14px de altura só de moldura.
 */
.cli-card__nums { margin-top: 10px; padding: 8px 0; gap: 6px; }
.cli-card__nums .b { font-size: 14px; }
.cli-card__status { margin-top: 8px; }
/*
 * O selo de próximo atendimento e o de retorno ficam na mesma linha do
 * rodapé de status — antes cada um abria a própria faixa.
 */
.cli-card__status { display: flex; gap: 6px; flex-wrap: wrap; }

/* ------------------------------------------------------------ SERVIÇOS */
/* O card vertical de antes (.svc-card, grade de 3 colunas) e o rótulo de
   categoria em linha única (.svc-grupo) saíram daqui no redesign da
   listagem — viraram o card horizontal .svc-list, em css/servicos.css.
   (nome "svc-list", não "svc-row": esse já era usado, sem relação, pelas
   linhas de "quem executa" em profissionais.css/servico.js/profissional.js) */

/* ------------------------------------------------------ MENU DE RELATÓRIOS */
.rp-menu { padding: 6px; }
.rp-menu__grupo {
  font-size: 10.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--text-3); padding: 10px 8px 4px;
}
.rp-menu__grupo:first-child { padding-top: 2px; }
.rp-menu__item {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 7px 8px; border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--text-2);
  font: inherit; font-size: 13px; font-weight: 550; text-align: left;
  cursor: pointer; transition: background .12s, color .12s;
}
.rp-menu__item svg { width: 15px; height: 15px; flex: 0 0 15px; opacity: .7; }
.rp-menu__item:hover { background: var(--surface-3); color: var(--text); }
.rp-menu__item.is-active {
  background: color-mix(in srgb, var(--brand) 15%, var(--surface));
  color: var(--brand-text, var(--brand)); font-weight: 650;
}
.rp-menu__item.is-active svg { opacity: 1; }

/* ----------------------------------------------------------- PAGINAÇÃO */
.paginacao {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  padding: var(--sp-2) var(--sp-3);
  border-top: 1px solid var(--border);
  font-size: 13px;
}
.paginacao__conta { color: var(--text-2); font-variant-numeric: tabular-nums; }
.paginacao__por { display: flex; align-items: center; gap: 6px; }
.paginacao__por .select { width: auto; height: 30px; padding: 0 26px 0 8px; font-size: 12.5px; }
.paginacao__nav { display: flex; align-items: center; gap: 3px; }
.paginacao__pag { padding: 0 8px; font-variant-numeric: tabular-nums; font-weight: 600; }
/* o "«" e o "»" são dois chevrons colados; o segundo encosta no primeiro */
.paginacao__nav .btn svg + svg { margin-left: -9px; }
/*
 * Fase 3.3: `.paginacao__por` já some de vez abaixo de 640px (regra
 * logo abaixo) — mas entre 641 e 900px (tablet em pé, por exemplo)
 * ele continua visível e tocável, com 12,5px de fonte. Mesma correção
 * de zoom do Safari/iOS que o resto do arquivo já aplica.
 */
@media (max-width: 900px) {
  .paginacao__por .select { font-size: 16px; height: 36px; }
}
/*
 * Achado de auditoria: o piso de toque de 38px para .btn--sm só existia
 * dentro do @media(max-width:640px) abaixo, mas o corte real de layout
 * mobile do painel (sidebar vira gaveta) é 900px — na faixa 641-900px
 * (tablet em pé, janela reduzida) o botão pequeno ficava em 32px mesmo
 * sendo tocável ali. Mesmo raciocínio já aplicado a .paginacao__por
 * .select acima.
 */
@media (max-width: 900px) {
  .btn--sm { height: 38px; padding: 0 13px; }
  .btn--icon.btn--sm { width: 38px; }
}
@media (max-width: 640px) {
  .paginacao { justify-content: center; padding: var(--sp-2); }
  .paginacao__conta { flex: 1 1 100%; text-align: center; }
  .paginacao__por { display: none; }
}

/* ------------------------------------------------- SEÇÃO DE FORMULÁRIO */
/*
 * O navegador põe borda, padding e margem próprios em <fieldset>, e um
 * <legend> flutuando no meio da borda. Nada disso combina com o resto;
 * aqui ele vira um bloco com um título discreto em cima.
 */
.form-secao {
  border: 0; padding: 0; margin: 0 0 var(--sp-4);
  min-width: 0;   /* fieldset ignora min-width:auto de flex/grid sem isto */
}
.form-secao:last-of-type { margin-bottom: 0; }
.form-secao__titulo {
  display: block; padding: 0; float: none; width: 100%;
  font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--text-3);
  padding-bottom: var(--sp-1); margin-bottom: var(--sp-2);
  border-bottom: 1px solid var(--border);
}
.form-secao__nota {
  font-size: 12px; color: var(--text-2); line-height: 1.45;
  margin: -4px 0 var(--sp-2);
}
/* dentro de uma seção, a última linha de campos não precisa de margem */
.form-secao > .row:last-child, .form-secao > .field:last-child { margin-bottom: 0; }

/* --------------------------------------------------- FILTROS EM GAVETA */
/*
 * No desktop a barra de filtros fica onde sempre esteve e o botão não
 * existe. Abaixo de 640px inverte: o botão aparece e a barra some da
 * página — os campos continuam vivos, só passam a morar na gaveta.
 */
.filtros-mobile__abrir { display: none; }
@media (max-width: 640px) {
  .filtros-mobile__abrir { display: inline-flex; width: 100%; justify-content: center; }
  /* a barra só some quando o botão está na tela; se a gaveta a levou
     para dentro do modal, ela volta a aparecer por causa da classe */
  /* Descendente, não filho direto: em Bloqueios a barra mora dentro de
     #blkHost, e o seletor com > deixava ela visível junto com a gaveta. */
  .tem-gaveta .ags__filtros:not(.filtros-mobile__campos),
  .tem-gaveta .aud__filtros:not(.filtros-mobile__campos),
  .tem-gaveta .blk__filtros:not(.filtros-mobile__campos),
  .tem-gaveta .filterbar:not(.filtros-mobile__campos) { display: none; }
  /* dentro da gaveta, um campo por linha e com respiro de dedo */
  .filtros-mobile__campos {
    display: flex; flex-direction: column; gap: 12px; margin: 0;
  }
  .filtros-mobile__campos > * { width: 100%; max-width: none; }
  .filtros-mobile__campos .input,
  .filtros-mobile__campos .select { width: 100%; height: 42px; }
  .filtros-mobile__campos .blk__campo { display: flex; flex-direction: column; gap: 4px; }
  /* o "limpar" da barra não repete dentro da gaveta: o rodapé já tem um */
  .filtros-mobile__campos #gLimpar { display: none; }
}

/* ------------------------------------------------------ CHECKOUT DO PDV */
/*
 * A linha que decide a ação no balcão. O Total é conferência; "falta
 * receber" é o que diz se pode liberar o cliente — quando existe, é ele
 * que precisa ser lido de longe.
 */
.pdv__row--falta {
  font-size: 19px; font-weight: 700; color: var(--red);
  padding-top: 8px; margin-top: 4px;
  border-top: 1px dashed color-mix(in srgb, var(--red) 40%, transparent);
}

/* =====================================================================
   CELULAR — não é o desktop espremido
   ---------------------------------------------------------------------
   Medido em 375px nas doze telas principais. Três problemas, os três
   sistêmicos:

   1. O conteúdo começava fundo demais. Profissionais gastava 515px antes
      do primeiro cartão, Serviços 450 — mais de meia tela de cabeçalho e
      ferramentas antes de qualquer coisa útil.

   2. Alvos de toque abaixo de 38px: 23 em Serviços, 25 em Relatórios, 18
      na Lista de espera. O dedo tem cerca de 9mm; abaixo disso erra.

   3. Texto abaixo de 11px: 22 em Configurações, 8 em Relatórios.
   ===================================================================== */
@media (max-width: 640px) {
  /* ------------------------------------------------------ 1. O TOPO */
  .page { padding-top: 12px; }
  .page-head { margin-bottom: var(--sp-2); gap: 6px; }
  /* Era 19px — abaixo da escala pedida pro título de página no mobile
     (24-26px). 24, o piso da faixa, porque a régua de conteúdo é a
     mesma de sempre (duas linhas de descrição, ver comentário abaixo). */
  .page-head h1 { font-size: 24px; line-height: 1.25; }
  /*
   * A descrição fica em duas linhas. Ela existe para quem chega pela
   * primeira vez; ocupar cinco linhas do celular todo dia é caro demais
   * pelo que entrega, e o texto completo continua no atributo title.
   */
  .page-head__desc {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden; font-size: 12px; line-height: 1.4;
  }
  /*
   * Rollout do achado do Dashboard (commit 1f544c2) pro resto do painel:
   * auditoria + verificação por card confirmaram que a DESCRIÇÃO destas
   * 5 telas só reafirma o que a própria tela (abas/filtros/tabela) já
   * mostra — diferente do título, que continua útil pra identificar a
   * página, e por isso NÃO é escondido aqui (diferente do "Olá, fulano"
   * do Dashboard, que não era um título de verdade). Escopado por classe
   * própria de cada tela — pageHeader() é compartilhado por ~50 telas e
   * continua intocado; nenhuma outra tela muda.
   */
  .page--financeiro .page-head__desc,
  .page--relatorio-gerencial .page-head__desc,
  .page--auditoria .page-head__desc,
  .page--cobranca-plataforma .page-head__desc,
  .page--empresas-plataforma .page-head__desc {
    display: none;
  }

  /*
   * Rollout do achado do Dashboard (commit 1f544c2, #visoes) pro resto
   * do painel: barras de abas com poucos itens FIXOS (nunca um-por-
   * profissional/serviço/categoria) vazavam a largura no celular,
   * precisando arrastar pra alcançar a última — mesmo bug, mesma
   * correção, escopada por id próprio de cada tela (nenhuma delas é a
   * .tabs/.proftabs compartilhada por ~20 outras telas, que precisam de
   * rolagem de verdade por terem MUITAS abas).
   *
   * `.proftab` (comissao-profissional/meta) já esconde o texto das abas
   * inativas neste mesmo breakpoint (ver `.proftab span{display:none}`
   * acima) — só falta o flex:1 1 0 pra dividir a largura; fonte/padding
   * ficam como já estavam. `.tab` (insights/lista-espera/preparo/
   * pacotes) não tem esse modo ícone-só, por isso repete a mesma receita
   * completa (fonte menor, padding mais justo) já testada no Dashboard.
   */
  #cpTabs, #gTabs { overflow-x: visible; }
  #cpTabs .proftab, #gTabs .proftab { flex: 1 1 0; justify-content: center; }

  #inTabs, #prepAreas { overflow-x: visible; }
  #pkTabs { overflow-x: auto; }
  #inTabs .tab, #prepAreas .tab, #pkTabs .tab {
    flex: 1 1 0; justify-content: center; padding: 8px 4px;
    font-size: 11.5px; gap: 4px; white-space: nowrap;
  }
  #inTabs .tab svg, #pkTabs .tab svg { width: 14px; height: 14px; flex: 0 0 14px; }

  /* 4 abas, uma com rótulo bem mais longo ("Regras da fila") — precisa
     de fonte/espaçamento mais justos que os outros 3 bares acima pra
     não estourar. `text-overflow:ellipsis` não tem efeito num filho
     flex direto (o ícone e o texto são itens separados do mesmo flex
     container) — por isso o rótulo tem seu próprio <span>, e é nele
     que a reticência (rede de segurança em 320px) é aplicada; `min-width:0`
     é o que permite esse span encolher abaixo do tamanho do texto. */
  #weTabs { overflow-x: visible; }
  #weTabs .tab {
    flex: 1 1 0; justify-content: center; padding: 7px 1px;
    font-size: 10px; gap: 2px;
  }
  #weTabs .tab svg { width: 13px; height: 13px; flex: 0 0 13px; }
  #weTabs .tab__label {
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  /* Faixa de indicadores mais rasa: o número continua legível, o cartão
     deixa de gastar 100px cada. */
  .kpis--destaque > .kpi { min-height: 0; padding: 11px 13px; }
  .kpis--destaque .kpi__value { font-size: 22px; }
  .section-title, .dash__sub { margin: var(--sp-3) 0 6px; }

  /* --------------------------------------------- 2. ÁREA DE TOQUE */
  /*
   * 38px é o piso. Não mexe na fonte nem na largura — só na altura e no
   * respiro, que é o que o dedo precisa. .btn--sm já ganha essa altura a
   * partir de 900px (ver @media acima, perto de .paginacao__por).
   */
  .tab, .proftab { padding-top: 11px; padding-bottom: 11px; }
  /* Achado de auditoria: este modo ícone-só de .proftab morava em
     profissionais.css com breakpoint 720px, diferente do breakpoint
     640px que .tabs/.proftabs usa no resto do arquivo (a mesma "peça
     visual" com dois cortes de tela diferentes). Movido pra cá. Só
     .proftab, não .tab: o rótulo de .proftab é gerado dentro de um
     <span> (ver profissionais.css), o de .tab não — extender pra .tab
     exigiria mudar o markup de 8+ telas sem verificação visual, fora do
     escopo desta correção pontual. */
  .proftab { padding: 9px 10px; font-size: 13px; }
  .proftab span { display: none; }
  .proftab.is-active span { display: inline; }
  .proftab svg { width: 18px; height: 18px; }
  .seg-chip { padding: 9px 13px; }
  .segmented button { padding: 9px 13px; }
  .rp-menu__item { padding: 11px 10px; }
  .cfg__item { min-height: 46px; }
  /* caixa de seleção com área clicável de verdade */
  .check input { width: 20px; height: 20px; }

  /* -------------------------------------------- 3. TAMANHO MÍNIMO */
  /*
   * Nada abaixo de 11px. Onde o projeto pediu 9 ou 10 — legenda de
   * gráfico, dica de rodapé — o texto sobe; é isso ou não ser lido.
   *
   * Fase 3.1: .tiny/.kpi__hint/.field__hint saíram daqui — o valor de
   * desktop (12.5px) já está ACIMA deste piso de 11,5px, então esta
   * regra só existia para ENCOLHER o texto no celular, ao contrário do
   * que qualquer piso deveria fazer.
   */
  .cfg__nota { font-size: 11.5px; line-height: 1.4; }
  [style*="font-size:9px"], [style*="font-size: 9px"],
  [style*="font-size:10px"], [style*="font-size: 10px"] { font-size: 11px !important; }
}
@media (max-width: 640px) {
  /*
   * Os três últimos textos abaixo de 11px, achados por medição: o selo de
   * "pelos primeiros passos" em Configurações (10px, 22 ocorrências) e o
   * título de gaveta do menu de Relatórios (10,5px).
   */
  .cfg__tag { font-size: 11px; }
  .rp-menu__grupo { font-size: 11px; }

  /*
   * O resumo da equipe empilhava quatro pílulas de largura inteira: 169px
   * de tela para dizer quatro números curtos. Duas colunas cabem, e o
   * primeiro cartão de profissional sobe meia tela.
   */
  .prof__resumo { gap: 8px; }
  .prof__resumo-item { flex: 1 1 calc(50% - 4px); border-radius: var(--r); padding: 8px 12px; }
  .prof__resumo-num { font-size: 15px; }
  .prof__resumo-lbl { font-size: 11.5px; }

  /*
   * Ferramentas do cabeçalho: a busca ocupa a linha, o resto divide a
   * seguinte. Antes cada controle pegava uma linha inteira e o cabeçalho
   * de Profissionais chegava a 231px antes de qualquer conteúdo.
   */
  .page-head__actions > .searchbox,
  .page-head .inline > .searchbox { flex: 1 1 100%; }
  .page-head__actions > .select,
  .page-head .inline > .select { flex: 1 1 calc(50% - 4px); min-width: 0; }
  .page-head__actions > .segmented,
  .page-head .inline > .segmented { flex: 0 0 auto; }
}
/*
 * Tentei fazer os dois botões do cabeçalho dividirem a linha no celular,
 * com min-width de 130px. Medido depois: PIOROU — o mínimo forçava
 * quebras extras e o topo de Profissionais subiu de 442 para 488px, o de
 * Comandas de 337 para 383. A regra saiu.
 *
 * Fica registrado porque a ideia é boa e a tentação de refazê-la é real:
 * o que não funciona é impor largura mínima numa linha que já tem busca,
 * quatro selects e um alternador disputando 375px.
 */

/*
 * A régua. Herda a cor do bloco do ícone do mesmo cartão, então não
 * precisa declarar cor por variante — e continua legível quando a marca
 * do tenant muda.
 */
.kpi__barra {
  height: 4px; border-radius: 99px; margin-top: 9px;
  background: var(--surface-3); overflow: hidden;
}
.kpi__barra > span {
  display: block; height: 100%; border-radius: 99px;
  background: var(--icon-accent); opacity: .85;
  transition: width .5s cubic-bezier(.4, 0, .2, 1);
}
/* a régua entra logo abaixo do número, então o rodapé encosta menos */
.kpi__barra + .kpi__rodape { margin-top: 6px; }
@media (prefers-reduced-motion: reduce) {
  .kpi__barra > span { transition: none; }
}

/*
 * `grande: true` (kpiCard()) existe desde antes desta migração pra dar
 * ícone circular à esquerda a cartões específicos (Retenção/Avaliações/
 * Fidelidade) — hoje é isso que TODO `.kpi` já faz por padrão (ver bloco
 * consolidado acima), então o modificador fica só como no-op inofensivo
 * para quem ainda chama `grande: true` — não precisa de regra própria.
 */

/* --------------------------------------------------- FILA DO DASHBOARD */
.kpi__bolinha {
  display: inline-block; width: 8px; height: 8px;
  border-radius: 50%; margin-right: 6px; flex: 0 0 8px;
}
/*
 * Estado sem ninguém fica apagado, não escondido: o zero de cancelamentos
 * é informação boa, e sumir com a coluna faria a fila mudar de forma ao
 * longo do dia — justamente a faixa que a pessoa aprende a ler de relance.
 */
.kpi--zero { opacity: .5; }
.kpi--zero .kpi__value { font-weight: 600; }

/* ===================================================================
   TAXAS DE MAQUININHA
   -------------------------------------------------------------------
   O cartão precisa responder uma pergunta só: quanto desta forma
   chega na casa. Por isso o percentual é o maior número do cartão e
   o líquido em R$ 100 vem logo abaixo — 3,49% não é grandeza sobre a
   qual alguém decide preço; "sobram R$ 96,51" é.
   =================================================================== */
.fp__ico {
  width: 34px; height: 34px; border-radius: var(--r-md);
  display: grid; place-items: center; flex: 0 0 34px;
  background: var(--surface-2); color: var(--text-2);
}
.fp__ico svg { width: 17px; height: 17px; }
.fp__nome {
  font-weight: 650; font-size: 14px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fp__taxa {
  margin-top: 10px; padding-top: 10px;
  border-top: 1px solid var(--border);
}
.fp__pct {
  font-size: 22px; font-weight: 700; letter-spacing: -.02em;
  line-height: 1.15; color: var(--amber);
}
/* sem taxa não é alerta: é o melhor caso, e amarelo diria o contrário */
.fp__pct--zero { color: var(--green); font-size: 18px; }

/* Forma desativada continua legível — ela ainda explica venda antiga. */
.fp__card.is-off { opacity: .62; }

.fp__previa {
  font-size: 12.5px; color: var(--text-2);
  background: var(--surface-2); border-radius: var(--r-md);
  padding: 9px 11px;
}
.fp__previa--erro { color: var(--red); font-weight: 600; }

/* =====================================================================
   PLANO E COBRANÇA  +  CHECKOUT
   ---------------------------------------------------------------------
   Duas telas, um vocabulário só. O que elas mostram é o que o banco
   registrou: plano contratado, valor congelado e cobranças emitidas.
   Não existe gateway de pagamento ligado, então nada aqui desenha
   botão de pagar — e as classes abaixo nem preveem esse botão.
   ===================================================================== */

/*
 * Laranja de estado.
 *
 * A escala de situação pedia seis cores e o sistema tinha cinco: entre o
 * amarelo de "pagamento pendente" (ainda no prazo) e o vermelho de
 * "suspenso" (acesso cortado) faltava o degrau de "inadimplente" — que é
 * atraso de verdade, mas com a casa ainda operando dentro da tolerância.
 * Pintar os dois de amarelo apagaria justamente a diferença que decide
 * se a pessoa precisa correr hoje.
 */
/*
 * V81: este par ficou de fora da rebalanceada da paleta (o laranja/creme
 * antigos vinham da base fria e destoavam do bege quente), e no claro o
 * texto media ~3,1:1 sobre o próprio fundo de badge — reprovava o mínimo
 * de 4,5:1. Reequilibrado na mesma família de --amber/--red, mantendo o
 * degrau semântico entre os dois; continua laranja, não vira dourado.
 */
:root { --orange: #A34A14; --orange-bg: #F7E3D2; }
[data-theme='dark'] { --orange: #F5A45C; --orange-bg: #331F0D; }
.badge--orange { background: var(--orange-bg); color: var(--orange); }

/* Ficha da assinatura: rótulo em cima, valor embaixo, quantas couberem. */
.cob__dados {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(178px, 1fr));
}
.cob__rot { font-size: 11.5px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-3); }
.cob__val { font-size: 14px; margin-top: 3px; overflow-wrap: anywhere; }
.cob__valor-grande { font-size: 22px; font-weight: 700; letter-spacing: -.02em; }

/*
 * Faturas em cartão, nunca em tabela.
 *
 * Extrato de cobrança tem seis campos por linha; num celular de 375px
 * isso vira rolagem horizontal dentro de rolagem vertical, e a pessoa
 * perde a coluna do valor logo no primeiro arrasto. Em cartão, cada
 * fatura cabe inteira na largura da tela em qualquer aparelho, e no
 * desktop a grade aproveita o espaço em duas ou três colunas.
 */
.cob__faturas {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
}
.cob__fatura {
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2); padding: 12px 14px;
}
.cob__fatura__topo { display: flex; align-items: center; gap: 8px; }
.cob__fatura__valor {
  margin-left: auto; font-size: 16px; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.cob__fatura__meta { font-size: 12px; color: var(--text-2); margin-top: 6px; line-height: 1.5; }
.cob__fatura__falha { font-size: 12px; color: var(--orange); margin-top: 4px; }

/* -------------------------------------------------------- CHECKOUT */
/*
 * Cartão de plano lado a lado não cabe em 375px, e comprimir três
 * colunas até caber deixa o preço menor que o rótulo. `auto-fill` com
 * piso de 258px empilha sozinho no celular e volta a comparar lado a
 * lado assim que houver largura.
 */
.co__grade {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(258px, 1fr));
}
.co__card {
  display: flex; flex-direction: column; gap: 9px;
  border: 1px solid var(--border); border-radius: var(--r);
  background: var(--surface); padding: 16px;
}
/* O plano contratado ganha contorno, não fundo: fundo colorido em um
   cartão de três faria parecer o recomendado, e recomendado é outra
   coisa. */
.co__card.is-atual { border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand); }
.co__card.is-alvo  { border-color: var(--blue); box-shadow: 0 0 0 1px var(--blue); }
.co__nome { font-size: 17px; font-weight: 700; }
.co__preco { font-size: 26px; font-weight: 700; letter-spacing: -.025em; line-height: 1.1; }
.co__preco small { font-size: 13px; font-weight: 600; color: var(--text-2); letter-spacing: 0; }
.co__limites {
  font-size: 12.5px; color: var(--text-2);
  border-top: 1px solid var(--border); padding-top: 9px;
}
.co__recs { display: flex; flex-direction: column; gap: 5px; }
.co__rec { display: flex; align-items: flex-start; gap: 7px; font-size: 13px; }
.co__rec svg { width: 15px; height: 15px; flex: none; color: var(--green); margin-top: 2px; }
/* o botão desce para a base para que cartões de alturas diferentes
   alinhem a ação — é nela que o olho volta ao comparar */
.co__acao { margin-top: auto; padding-top: 4px; }

/* Impedimento de troca: número atual contra o teto, lado a lado. */
.co__imped {
  border: 1px solid color-mix(in srgb, var(--orange) 34%, transparent);
  background: color-mix(in srgb, var(--orange) 9%, var(--surface));
  border-radius: var(--r-md); padding: 11px 13px; margin-bottom: 10px;
}
.co__imped__num { font-size: 13px; font-variant-numeric: tabular-nums; margin-top: 3px; }
.co__imped__ajuste { font-size: 13px; font-weight: 650; margin-top: 5px; }

/* ================================================================
   PAGAMENTOS (0161-0164) — como a casa recebe
   ---------------------------------------------------------------- */
.pg-formas {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 10px;
}
.pg-forma {
  display: flex; align-items: center; gap: 10px; min-width: 0;
  padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2);
}
.pg-forma svg { width: 18px; height: 18px; color: var(--text-3); flex: 0 0 auto; }
.pg-forma b { font-size: 14px; }

.pg-prov {
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2); padding: 14px;
}
.pg-prov + .pg-prov { margin-top: 10px; }
.pg-prov__topo {
  display: flex; align-items: flex-start; gap: 10px; flex-wrap: wrap;
}
.pg-prov__id { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }
.pg-prov__id b { font-size: 15px; }
.pg-prov__acoes { margin-left: auto; display: flex; gap: 6px; flex-wrap: wrap; }
.pg-prov__nota { margin-top: 8px; line-height: 1.5; }
.pg-prov__info {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border);
}
.pg-prov__info > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pg-prov__info b { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* A tabela de recebidos tem oito colunas: em 375px ela rola sozinha,
   dentro do próprio container, e nunca leva o corpo da página junto. */
.tabela-rolagem { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.tabela-rolagem > .tbl { min-width: 640px; }

@media (max-width: 560px) {
  .pg-prov__acoes { margin-left: 0; width: 100%; }
  .pg-prov__acoes .btn { flex: 1 1 auto; }
}

/* o comando de configuração no aviso da tela de Pagamentos */
.pg-prov__acoes .btn { white-space: nowrap; }

/* --------------------------------------------------- INTEGRAÇÕES ------ */
/* 300px de coluna mínima dá 1 no mobile, 2 no tablet (768px de área útil)
   e 3 no desktop (conteúdo ~1100-1150px depois da sidebar) sem precisar de
   media query — a mesma técnica que .cfg__grade já usa nesta tela. */
.ig__grade { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; }
@media (max-width: 640px) { .ig__grade { grid-template-columns: 1fr; } }
.ig__card .card__body { display: flex; flex-direction: column; gap: 10px; height: 100%; }
.ig__cabeca { display: flex; align-items: center; gap: 10px; }
.ig__ico {
  width: 36px; height: 36px; border-radius: var(--r-sm); flex: 0 0 36px;
  display: grid; place-items: center; background: var(--surface-3); color: var(--brand-text, var(--brand));
}
.ig__ico svg { width: 18px; height: 18px; }
.ig__nome { font-size: 15px; font-weight: 650; }
.ig__badges { display: flex; gap: 6px; flex-wrap: wrap; }
.ig__cat { color: var(--text-3); }
.ig__desc { font-size: 13px; color: var(--text-2); line-height: 1.5; flex: 1 1 auto; }
.ig__rodape { margin-top: auto; padding-top: 4px; }
/* Os dois estados de uma integração, lado a lado. Separados de propósito: ter o
 * identificador público não significa ter a API de servidor, e um selo único
 * diria "configurado" com metade faltando — meia verdade que só aparece quando
 * a campanha não mede. */
.ig__status { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 18px;
  padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-2); }
.ig__status-item { display: inline-flex; align-items: center; gap: 7px; min-width: 0; }
@media (max-width: 560px) {
  .ig__status { flex-direction: column; align-items: stretch; gap: 8px; }
  .ig__status-item { justify-content: space-between; }
}

/* =====================================================================
   Componentes V76 (".v23-*"/".v27-*") — extraídos ao vivo do HTML de
   referência (estrutura, classes e valores computados), não uma
   reinterpretação. Correção (esta rodada): substituem os componentes
   genéricos equivalentes (.filterbar/.select/.kpi/.card) nas páginas
   reconstruídas para bater exatamente com a V76 — não são "mais uma
   variante", são o próprio componente da referência.
   ===================================================================== */
.v23-toolbar {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  min-height: 62px; margin: 0 0 14px; padding: 10px 0;
  border-bottom: 1px solid rgba(212, 162, 96, .16);
}
.v23-search {
  height: 42px; min-width: 220px; max-width: 335px; flex: 1 1 245px;
  border: 1px solid var(--border-strong); border-radius: 10px; background: var(--surface-2);
  display: flex; align-items: center; gap: 9px; padding: 0 13px; color: var(--text-3);
}
.v23-search:focus-within { border-color: rgba(212, 162, 96, .45); }
.v23-search svg, .v23-select svg { width: 17px; height: 17px; stroke: currentColor; stroke-width: 1.7; fill: none; flex-shrink: 0; }
.v23-search input { width: 100%; min-width: 0; outline: 0; border: 0; background: transparent; color: var(--text); font-size: 13px; }
.v23-search input::placeholder { color: var(--text-3); }

.v23-select-wrap { position: relative; flex: 0 1 auto; min-width: 150px; }
.v23-select {
  height: 42px; min-width: 150px; width: 100%; padding: 0 12px; border-radius: 10px;
  border: 1px solid var(--border-strong); background: var(--surface-2);
  display: flex; align-items: center; justify-content: space-between; gap: 15px;
  font-size: 12.5px; font-weight: 750; cursor: pointer; color: var(--text);
}
.v23-select:hover, .v23-select[aria-expanded="true"] { border-color: rgba(212, 162, 96, .47); background: color-mix(in srgb, var(--icon-accent) 10%, var(--surface-2)); color: var(--icon-accent); }
.v23-select-menu {
  display: none; position: absolute; top: calc(100% + 6px); left: 0; min-width: 100%; width: max-content;
  max-width: 290px; max-height: 250px; overflow: auto; border: 1px solid rgba(212, 162, 96, .22);
  border-radius: 11px; padding: 6px; background: var(--surface-2); box-shadow: var(--sh-3); z-index: 100;
}
.v23-select-menu.open { display: grid; gap: 2px; }
.v23-select-option {
  min-height: 38px; text-align: left; padding: 7px 11px; border: 0; border-radius: 7px;
  background: transparent; color: var(--text-2); font-size: 12.5px; cursor: pointer; font: inherit;
}
.v23-select-option:hover, .v23-select-option.active { background: rgba(212, 162, 96, .12); color: var(--icon-accent); }

.v23-toolbar-actions { display: flex; gap: 8px; align-items: center; margin-left: auto; }
.v23-btn {
  min-height: 40px; display: inline-flex; gap: 7px; align-items: center; justify-content: center;
  padding: 0 14px; border-radius: 9px; border: 1px solid rgba(212, 162, 96, .3);
  background: var(--surface-2); color: var(--text); font-size: 12.5px; font-weight: 800;
  cursor: pointer; white-space: nowrap;
}
.v23-btn:hover { border-color: var(--icon-accent); background: color-mix(in srgb, var(--icon-accent) 12%, var(--surface-2)); }
.v23-btn.gold { background: linear-gradient(110deg, var(--gold-2), var(--brand)); border-color: var(--brand); color: var(--brand-fg); }
.v23-btn.gold:hover { filter: brightness(1.07); }
.v23-btn.ghost { border-color: var(--border); background: var(--surface); }

.v23-kpis { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 11px; margin: 0 0 16px; }
.v23-kpi {
  min-height: 112px; padding: 17px 18px; border: 1px solid rgba(212, 162, 96, .2); border-radius: 15px;
  background: linear-gradient(135deg, var(--card), var(--surface-2));
  display: flex; flex-direction: column; gap: 5px; min-width: 0;
}
.v23-kpi > span { color: var(--text-2); font-size: 12px; font-weight: 650; }
.v23-kpi strong { font-size: 26px; font-weight: 850; letter-spacing: -.03em; line-height: 1.2; overflow-wrap: anywhere; color: var(--text); }
.v23-kpi small { color: var(--text-3); font-size: 11px; }
.v23-kpi.v27-rich-kpi {
  position: relative; min-width: 0; min-height: 124px; padding: 20px 16px 17px 78px !important;
  display: flex; flex-direction: column; justify-content: center; align-items: flex-start; gap: 4px;
  border: 1px solid rgba(212, 162, 96, .31); border-radius: 15px;
  background:
    repeating-linear-gradient(135deg, var(--card-texture) 0 1px, transparent 1px 12px),
    linear-gradient(145deg, var(--card), var(--surface-2)) !important;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .025);
}
.v23-kpi.v27-rich-kpi > span:not(.v27-kpi-symbol):not(.v27-kpi-rule) { color: var(--text-2); font-size: 12px !important; font-weight: 700; line-height: 1.35; }
.v23-kpi.v27-rich-kpi strong { font-size: 26px !important; color: var(--text); line-height: 1.12; letter-spacing: -.035em; font-weight: 850; overflow-wrap: normal; white-space: normal; }
.v23-kpi.v27-rich-kpi small { font-size: 11px; line-height: 1.35; color: var(--text-3); }
.v27-kpi-symbol {
  position: absolute !important; left: 17px; top: 24px; width: 46px; height: 46px;
  display: grid !important; place-items: center; border-radius: 13px;
  border: 1px solid rgba(212, 162, 96, .33); background: rgba(212, 162, 96, .075); color: var(--icon-accent) !important;
}
.v27-icon { display: block; width: 22px; height: 22px; flex-shrink: 0; }
.v27-kpi-rule {
  position: absolute; bottom: 0; left: 77px; right: 18px; height: 2px; border-radius: 3px;
  background: linear-gradient(90deg, rgba(212, 162, 96, .6), transparent); opacity: .58; pointer-events: none;
}
.v27-rich-kpi.v27-unavailable .v27-kpi-rule { opacity: .2; }
@media (max-width: 1250px) { .v23-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); } .v23-toolbar-actions { margin-left: 0; } }

/* Blocos "insights" (v27) — a própria V76 os rotula "prévia"/demonstração
   quando não há dado real; aqui usam dado real (reaproveitado dos MESMOS
   KPIs já carregados, sem consulta nova) sempre que possível. */
.v27-insights { display: grid; grid-template-columns: 1.1fr 1fr; gap: 12px; margin: 0 0 15px; align-items: stretch; }
.v27-insights-single { grid-template-columns: 1fr; }
.v27-insight-card {
  min-width: 0; overflow: hidden; border: 1px solid rgba(212, 162, 96, .26); border-radius: 15px;
  background: repeating-linear-gradient(135deg, var(--card-texture) 0 1px, transparent 1px 14px), var(--card);
  display: flex; flex-direction: column; min-height: 215px;
}
.v27-insight-head { padding: 15px 17px; display: flex; align-items: center; gap: 11px; border-bottom: 1px solid var(--border); }
.v27-insight-symbol {
  display: grid; place-items: center; flex: 0 0 35px; width: 35px; height: 35px; color: var(--icon-accent);
  border-radius: 10px; border: 1px solid rgba(212, 162, 96, .25); background: rgba(212, 162, 96, .07);
}
.v27-insight-symbol .v27-icon { width: 18px; height: 18px; }
.v27-insight-head h3 { font-size: 14px; color: var(--text); line-height: 1.25; font-weight: 800; margin: 0 0 3px; }
.v27-insight-head p { font-size: 11px; color: var(--text-3); line-height: 1.45; margin: 0; }
.v27-insight-content { padding: 17px; display: grid; gap: 13px; flex: 1; }
.v27-meter { display: grid; gap: 5px; min-width: 0; }
.v27-meter-top { display: flex; gap: 8px; justify-content: space-between; align-items: baseline; font-size: 12px; color: var(--text-2); }
.v27-meter-top strong { font-size: 13px; color: var(--text); }
.v27-meter-track { height: 7px; border-radius: 10px; overflow: hidden; background: var(--surface-3); }
.v27-meter-track > span { display: block; height: 100%; border-radius: 10px; background: linear-gradient(90deg, var(--brand-dark), var(--gold-2)); min-width: 0; }
.v27-meter > small { color: var(--text-3); font-size: 10px; }
.v27-insight-foot { margin-top: auto; padding: 9px 17px; border-top: 1px solid var(--border); font-size: 10px; color: var(--text-3); letter-spacing: .01em; }
.v27-info-list { display: grid; padding: 4px 17px 5px; flex: 1; }
.v27-info-row { display: flex; gap: 10px; align-items: center; min-width: 0; padding: 12px 0; border-bottom: 1px solid var(--border); }
.v27-info-row:last-child { border-bottom: 0; }
.v27-row-mark {
  display: grid; place-items: center; width: 30px; height: 30px; flex: 0 0 30px; border-radius: 9px;
  border: 1px solid rgba(212, 162, 96, .16); color: var(--icon-accent); background: rgba(212, 162, 96, .045);
}
.v27-row-icon { width: 16px; height: 16px; }
.v27-info-row > div { min-width: 0; flex: 1; }
.v27-info-row strong { display: block; color: var(--text); font-size: 12px; font-weight: 780; line-height: 1.3; }
.v27-info-row small { display: block; color: var(--text-3); font-size: 10.5px; line-height: 1.4; margin-top: 3px; }
.v27-row-value { font-size: 12px; color: var(--icon-accent); white-space: nowrap; font-weight: 850; }

.v23-panel { border: 1px solid rgba(212, 162, 96, .18); border-radius: 15px; background: var(--surface); overflow: hidden; margin-bottom: 15px; }
.v23-panel-head { min-height: 51px; padding: 12px 16px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border); }
.v23-panel-head h3 { font-size: 14px; font-weight: 820; margin: 0; line-height: 1.3; }
.v23-panel-body { padding: 0; }
.v23-tabs { display: flex; gap: 9px; padding: 12px 16px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.v23-tabs button {
  font-size: 12px; font-weight: 800; background: transparent; color: var(--text-2);
  border: 1px solid var(--border); padding: 8px 13px; border-radius: 9px; cursor: pointer; font-family: inherit;
}
.v23-tabs button.active, .v23-tabs button:hover { background: rgba(212, 162, 96, .11); border-color: rgba(212, 162, 96, .4); color: var(--icon-accent); }
.v23-tabs button span { font-size: 10px; color: var(--text-3); margin-left: 4px; }

.v23-table-scroll { overflow-x: auto; }
.v23-table { width: 100%; border-collapse: collapse; min-width: 820px; text-align: left; }
.v23-table th { padding: 13px 16px; font-size: 10px; font-weight: 850; text-transform: uppercase; letter-spacing: .075em; color: var(--text-3); white-space: nowrap; }
.v23-table td { padding: 15px 16px; border-top: 1px solid var(--border); font-size: 12.5px; white-space: nowrap; vertical-align: middle; }
.v23-table td b { color: var(--text); font-size: 13px; display: block; }
.v23-table td small { color: var(--text-3); font-size: 11px; display: block; margin-top: 3px; }
.v23-table tbody tr:hover { background: rgba(212, 162, 96, .025); }
.v23-table td:first-child b { color: var(--icon-accent); }
.v23-pill {
  display: inline-flex; align-items: center; gap: 6px; border-radius: 99px; padding: 5px 9px;
  font-size: 10.5px; font-weight: 800; border: 1px solid rgba(212, 162, 96, .25);
  background: rgba(212, 162, 96, .08); color: var(--icon-accent); white-space: nowrap;
}
/* Tinta derivada do próprio token de estado: o verde/vermelho fixos daqui
   eram os valores do tema escuro, e no claro ficavam lavados. Mesma
   opacidade de antes, agora acompanhando a paleta nos dois temas. */
.v23-pill.green { border-color: color-mix(in srgb, var(--green) 30%, transparent); background: color-mix(in srgb, var(--green) 9%, transparent); color: var(--green); }
.v23-pill.red { border-color: color-mix(in srgb, var(--red) 30%, transparent); background: color-mix(in srgb, var(--red) 9%, transparent); color: var(--red); }
.v23-mini-action {
  border: 1px solid var(--border-strong); background: var(--surface-2); color: var(--text);
  padding: 6px 9px; border-radius: 7px; cursor: pointer; font-size: 11px; font-weight: 750;
}
.v23-mini-action:hover { border-color: rgba(212, 162, 96, .45); color: var(--icon-accent); }
.v23-person-cards { padding: 14px; display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 10px; }

/* Cabeçalho enxuto só no celular (V76: .ak-client-hero-mobile) — no
   desktop o topbar global já mostra o título da página. */
.ak-client-hero-mobile { display: none; }
.ak-client-hero-mobile h2 { font-size: 20px; margin: 0 0 4px; }
.ak-client-hero-mobile p { font-size: 12.5px; color: var(--text-2); margin: 0 0 12px; }

/* A barra de Clientes gruda no topo ao rolar, em QUALQUER largura (V76:
   #page-clients .v23-toolbar { position:sticky !important }, uma regra
   global, fora de media query — o !important aqui não é estético: sem
   ele, `.ak-mobile-compact{position:static!important}` do motor mobile
   (abaixo) venceria por ser declarado depois, e o popover "⋮" — que é
   position:absolute dentro desta barra — perderia sua referência de
   posicionamento e apareceria fora do lugar). */
.cli-page .v23-toolbar {
  position: sticky !important; top: 0; z-index: 26;
  backdrop-filter: blur(16px);
  background: var(--topbar-bg);
  box-shadow: 0 12px 28px rgba(0, 0, 0, .28);
}

/* =====================================================================
   Motor de barra compacta no mobile (V76: script "ak-v67-mobile-toolbar-
   engine" + CSS "ak-v68-mobile-final-polish"). Ponto de quebra real: 780px
   — não o 640px genérico do resto do projeto. Mantém visíveis só busca +
   período + 1 controle principal; o resto (2º select + as ações) entra
   num popover "⋮" (.ak-mobile-more/.ak-mobile-panel), sem apagar nenhum
   controle nem duplicar handlers — os mesmos nós reais só mudam de pai.
   Classes/valores portados literalmente; a lógica de mover os nós mora em
   mobileCompactToolbar() (ui.js), reaproveitável pelas próximas páginas
   que também usam .v23-toolbar/.v29-toolbar/.v36-toolbar na V76.
   ===================================================================== */
@media (max-width: 780px) {
  .ak-client-hero-mobile { display: block; }

  .ak-mobile-compact {
    display: grid !important;
    grid-template-columns: minmax(0, 105px) minmax(0, 1fr) 42px !important;
    gap: 9px !important; align-items: center !important;
    position: static !important; top: auto !important;
    min-height: 0 !important; width: 100%; max-width: none !important;
    margin: 0 0 14px !important; padding: 10px 0 !important;
  }
  .ak-mobile-compact.ak-mob-no-search { grid-template-columns: minmax(0, 105px) minmax(0, 1fr) 42px !important; }
  .ak-mobile-compact > .ak-mob-search {
    grid-column: 1 / -1; width: 100%; min-width: 0; max-width: none;
    height: 42px; min-height: 42px; margin: 0;
  }
  .ak-mobile-compact > .ak-mob-date {
    grid-column: 1; width: 100%; min-width: 0; max-width: none;
    height: 42px; min-height: 42px; margin: 0; padding: 0 10px;
  }
  /* periodPicker() é mais rico que o "Hoje" fixo da V76 (datas reais, não
     só um atalho), então o rótulo pode ser bem mais longo que os 105px
     desta coluna — troca pelo curto já calculado (rotuloPeriodoCurto())
     em vez de cortar o texto no meio com reticências. */
  .ak-mobile-compact > .ak-mob-date [data-rotulo] { font-size: 0; }
  .ak-mobile-compact > .ak-mob-date [data-rotulo]::after { content: attr(data-mobile-label); font-size: 12.5px; }
  .ak-mobile-compact > .ak-mob-main {
    grid-column: 2; width: 100%; min-width: 0; max-width: none;
    height: 42px; min-height: 42px; margin: 0;
  }
  .ak-mobile-compact > .ak-mob-only-primary { grid-column: 1 / 3; }
  .ak-mobile-compact.ak-mob-no-more > .ak-mob-only-primary { grid-column: 1 / -1; }
  .ak-mobile-compact.ak-mob-no-more > .ak-mob-date { grid-column: 1; }
  .ak-mobile-compact.ak-mob-no-more > .ak-mob-main { grid-column: 2 / 4; }
  .ak-mobile-compact.ak-mob-no-more.ak-mob-one-control > .ak-mob-main,
  .ak-mobile-compact.ak-mob-no-more.ak-mob-one-control > .ak-mob-date { grid-column: 1 / -1; }
  .ak-mobile-compact > .ak-mob-main:is(.v23-select-wrap),
  .ak-mobile-compact > .ak-mob-date:is(.v23-select-wrap) { width: 100%; height: 42px; display: flex; align-items: stretch; }
  .ak-mobile-compact > .ak-mob-main:is(.v23-select-wrap) > .v23-select,
  .ak-mobile-compact > .ak-mob-date:is(.v23-select-wrap) > .v23-select { width: 100%; height: 42px; min-width: 0; padding: 0 10px; }
  .ak-mobile-compact > .ak-mob-main .v23-select span,
  .ak-mobile-compact > .ak-mob-date .v23-select span { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .ak-mobile-compact > .ak-mob-main.v23-btn,
  .ak-mobile-compact > .ak-mob-date.v23-btn { width: 100%; height: 42px; justify-content: center; }

  .ak-mobile-compact > .ak-mobile-more {
    display: grid; grid-column: 3; width: 42px; height: 42px; min-width: 42px;
    margin: 0; padding: 0; place-items: center;
    background: var(--surface-2); color: var(--icon-accent); border: 1px solid rgba(212, 162, 96, .44);
    border-radius: 11px; cursor: pointer;
  }
  .ak-mobile-compact > .ak-mobile-more svg { width: 22px; height: 22px; fill: currentColor; }
  .ak-mobile-compact > .ak-mobile-more[aria-expanded="true"] { background: rgba(212, 162, 96, .14); box-shadow: inset 0 -2px 0 var(--icon-accent); }
  .ak-mobile-compact > .ak-mobile-panel[hidden], .ak-mobile-compact > .ak-mobile-more[hidden] { display: none !important; }

  .ak-mobile-panel {
    display: grid; position: absolute; z-index: 200;
    top: calc(100% + 5px); right: 0;
    width: min(320px, calc(100vw - 28px)); max-width: calc(100vw - 28px);
    max-height: min(70dvh, 520px); overflow-y: auto;
    grid-template-columns: minmax(0, 1fr); gap: 8px;
    padding: 12px; background: var(--surface);
    border: 1px solid rgba(212, 162, 96, .35); border-radius: 14px;
    box-shadow: 0 18px 54px rgba(0, 0, 0, .62);
  }
  .ak-mobile-panel-title { color: var(--text-3); font-size: 10px; letter-spacing: .08em; text-transform: uppercase; font-weight: 800; padding: 0 2px 2px; }
  .ak-mobile-panel > .ak-mob-extra {
    display: flex; min-width: 0; max-width: none; width: 100%; min-height: 42px; height: auto;
    margin: 0; padding: 0; flex-wrap: wrap; gap: 8px;
  }
  .ak-mobile-panel > .v23-select-wrap { display: block; position: relative; }
  .ak-mobile-panel > .v23-select-wrap > .v23-select { width: 100%; min-width: 0; min-height: 42px; }
  .ak-mobile-panel .v23-select-menu.open {
    position: static; top: auto; left: auto; right: auto; width: 100%; max-width: none; min-width: 0;
    max-height: min(33dvh, 230px); margin: 6px 0 0; overflow-y: auto; box-shadow: none;
  }
  .ak-mobile-panel > .v23-toolbar-actions {
    display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; width: 100%; margin: 0; min-width: 0;
  }
  .ak-mobile-panel > .v23-toolbar-actions > .v23-btn {
    width: 100%; min-width: 0; max-width: none; height: 42px; min-height: 42px;
    margin: 0; padding: 0 12px; text-align: left; justify-content: flex-start; white-space: normal; font-size: 12px;
  }
  .ak-mobile-panel > .v23-toolbar-actions > .v23-btn.gold { justify-content: center; text-align: center; }
  .ak-mobile-compact > .v23-toolbar-actions:empty { display: none; }

  .v23-kpis { grid-template-columns: 1fr !important; gap: 9px !important; }
  .cli-page .v23-kpi.v27-rich-kpi {
    position: relative; overflow: hidden; min-height: 118px !important; padding: 16px 58px 16px 72px !important;
    border-radius: 16px !important; border: 1px solid rgba(212, 162, 96, .34) !important;
    background:
      repeating-linear-gradient(135deg, var(--card-texture) 0 1px, transparent 1px 14px),
      radial-gradient(circle at 100% 50%, rgba(212, 162, 96, .08), transparent 34%), var(--card) !important;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .03), 0 10px 28px rgba(0, 0, 0, .18);
  }
  .cli-page .v23-kpi.v27-rich-kpi .v27-kpi-symbol {
    left: 16px !important; top: 18px !important; width: 42px !important; height: 42px !important; border-radius: 13px !important;
    background: linear-gradient(180deg, rgba(212, 162, 96, .08), rgba(212, 162, 96, .045)) !important;
    border-color: rgba(212, 162, 96, .38) !important; box-shadow: 0 6px 16px rgba(0, 0, 0, .14);
  }
  .cli-page .v23-kpi.v27-rich-kpi > span:not(.v27-kpi-symbol):not(.v27-kpi-rule) { display: block; color: var(--text) !important; font-size: 14px !important; font-weight: 850 !important; line-height: 1.25; }
  .cli-page .v23-kpi.v27-rich-kpi strong { display: block; margin-top: 7px; font-size: 29px !important; line-height: .96; font-weight: 900; color: var(--text) !important; letter-spacing: -.045em; }
  .cli-page .v23-kpi.v27-rich-kpi small { display: block; margin-top: 8px; font-size: 11.8px !important; line-height: 1.4; color: var(--text-2) !important; max-width: 100%; }
  .cli-page .v23-kpi.v27-rich-kpi .v27-kpi-rule { left: 72px; right: 14px; opacity: .26; }
  .cli-page .v23-kpi.v27-rich-kpi::after {
    content: '›'; position: absolute; right: 14px; top: 50%; transform: translateY(-50%);
    display: grid; place-items: center; width: 34px; height: 34px; border-radius: 999px;
    border: 1px solid rgba(212, 162, 96, .16); background: rgba(212, 162, 96, .08); color: var(--icon-accent);
    font-size: 28px; line-height: 1;
  }

  .v27-insights { grid-template-columns: 1fr !important; gap: 12px !important; }
  .cli-page .v27-insights .v27-insight-card:nth-child(2) { display: none !important; }
  .cli-page .v27-insight-card {
    min-height: 0; border-radius: 16px;
    background:
      repeating-linear-gradient(135deg, var(--card-texture) 0 1px, transparent 1px 14px),
      radial-gradient(circle at 100% 50%, rgba(212, 162, 96, .08), transparent 34%), var(--card);
  }
  .cli-page .v27-insight-head { padding: 16px 16px 12px; }
  .cli-page .v27-insight-head h3 { font-size: 15px; }
  .cli-page .v27-insight-head p { font-size: 12px; line-height: 1.5; }
  .cli-page .v27-insight-symbol { width: 40px; height: 40px; border-radius: 12px; }
  .cli-page .v27-insight-symbol .v27-icon { width: 18px; height: 18px; }
  .cli-page .v27-insight-content { padding: 0 16px 16px; }
  .cli-page .v27-meter { gap: 8px; }
  .cli-page .v27-meter-top { font-size: 13px; color: var(--text); }
  .cli-page .v27-meter-top strong { font-size: 15px; }
  .cli-page .v27-meter-track { height: 10px; background: var(--surface-3); }
  .cli-page .v27-insight-foot { padding: 10px 16px; font-size: 11px; }
}
@media (max-width: 360px) {
  .ak-mobile-compact { grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr) 40px !important; gap: 6px !important; }
  .ak-mobile-compact > .ak-mobile-more { width: 40px !important; min-width: 40px !important; }
}

/* =====================================================================
   Popover de profissional (V76: ".popover"/".prof-popover"/".prof-
   option") — componente compartilhado entre páginas que filtram por
   profissional na V76 (Dashboard, Ranking...), não exclusivo de uma só;
   por isso global, sem escopo de página. Ver professionalFilter() em
   ui.js — cria/remove este popover a cada abertura, igual ao periodPicker.
   ===================================================================== */
.popover {
  position: fixed; z-index: 200; display: none;
  background: var(--surface-2); border: 1px solid var(--border-strong); border-radius: 14px; box-shadow: var(--sh-3);
}
.popover.open { display: block; }
.prof-popover { width: 250px; padding: 6px; }
.prof-option {
  width: 100%; height: 38px; padding: 0 11px; border: 0; border-radius: 7px; background: transparent;
  color: var(--text-2); text-align: left; font-size: 12.5px; font-weight: 700; cursor: pointer; font-family: inherit;
}
.prof-option:hover, .prof-option.active { background: rgba(212, 162, 96, .10); color: var(--icon-accent); }
