/* ═══════════════════════════════════════════════════════════════════
   FRONT-END VITAL VIDA — padroes.css
   ═══════════════════════════════════════════════════════════════════

   Base CSS do projeto. Mobile-first.
   Cresce conforme novas telas vão sendo adicionadas.

   Ordem das seções:
     1. Tokens (:root)
     2. Reset
     3. Tipografia base
     4. Componentes — Topbar
     5. Componentes — Card
     6. Componentes — Form (inputs, labels)
     7. Componentes — Botões
     8. Layout — Login
     9. Layout — Home placeholder
    10. Responsivo (min-width media queries)
   ═══════════════════════════════════════════════════════════════════ */


/* ────────────────────────────────────────────────────────
   1. TOKENS — V2 (Jun/2026)
   Identidade: verde-clínica (o 💚 do bot) + dourado do logo.
   ──────────────────────────────────────────────────────── */

/* Fontes auto-hospedadas (s15): zero dependência do Google Fonts —
   carrega mais rápido e funciona mesmo se a CDN falhar.
   (s127) os @font-face da JetBrains Mono saíram com a fonte de dados —
   os .woff2 seguem em static/fonts sem consumidor (limpeza opcional). */
@font-face { font-family: 'Sora'; font-style: normal; font-weight: 600; font-display: swap; src: url('/app/static/fonts/sora-latin-600-normal.woff2') format('woff2'); }
@font-face { font-family: 'Sora'; font-style: normal; font-weight: 700; font-display: swap; src: url('/app/static/fonts/sora-latin-700-normal.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap; src: url('/app/static/fonts/inter-latin-400-normal.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap; src: url('/app/static/fonts/inter-latin-500-normal.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap; src: url('/app/static/fonts/inter-latin-600-normal.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 700; font-display: swap; src: url('/app/static/fonts/inter-latin-700-normal.woff2') format('woff2'); }
/* (s283 · 27/09 — auditoria de fontes, escolha dele: opção 5, Plus Jakarta Sans «como vem»)
   Só o painel novo (atendimento2) e o agendamento online usam; as outras telas seguem na Inter
   e não baixam estes arquivos. */
@font-face { font-family: 'Plus Jakarta Sans'; font-style: normal; font-weight: 400; font-display: swap; src: url('/app/static/fonts/plus-jakarta-sans-latin-400-normal.woff2') format('woff2'); }
@font-face { font-family: 'Plus Jakarta Sans'; font-style: normal; font-weight: 500; font-display: swap; src: url('/app/static/fonts/plus-jakarta-sans-latin-500-normal.woff2') format('woff2'); }
@font-face { font-family: 'Plus Jakarta Sans'; font-style: normal; font-weight: 600; font-display: swap; src: url('/app/static/fonts/plus-jakarta-sans-latin-600-normal.woff2') format('woff2'); }
@font-face { font-family: 'Plus Jakarta Sans'; font-style: normal; font-weight: 700; font-display: swap; src: url('/app/static/fonts/plus-jakarta-sans-latin-700-normal.woff2') format('woff2'); }

/* ⛔ (s124 — item 0) O [hidden] VENCE, SEMPRE E EM TODA A CASA.
   O `display` de uma classe do autor ganha do `[hidden]{display:none}`
   do navegador — então todo elemento com `display: flex/inline-flex/grid`
   continuava NA TELA com `hidden = true`, e a tela mentia calada. A casa
   remendou isso 3 vezes, uma classe por vez (.grafico-vazio s?, .insight-strip,
   .btn-mini s109p) e uma 4ª no atendimento.html (.nv-escolhido) — os quatro
   foram DELETADOS e esta linha os substitui (régua s86: existe X? não se cria Y).
   Medido antes: 11 de 13 elementos do ProDoctor respeitavam o atributo;
   os 2 que não (#pd-pac, #pd-zap-grava-cx) eram os itens 5 e 10 da fila
   dele. Fiscal pareado: prova de "está escondido" mede offsetParent/
   offsetHeight, NUNCA a propriedade `.hidden` — foi ela que deu 32/32 falso. */
[hidden] { display: none !important; }

/* (s124 — item 7) O <select> que virou vvCombo continua no DOM (é ele
   que a página lê e escuta) — só sai da TELA. De propósito NÃO usa
   `display`: é o `display` que as páginas ligam/desligam pra mostrar o
   filtro, e o campo novo copia essa deixa. */
.vv-select-fonte {
  position: absolute !important;
  /* ⚠️ `min-width`/`max-width` JUNTO: `.pd-campo .campo-pill{min-width:180px}`
     ganha de um `width:1px` e o select continuava ocupando 180px de
     layout, invisível — pego pela prova de tela em PIXEL, não pela
     leitura do CSS. */
  width: 1px !important; height: 1px !important;
  min-width: 1px !important; max-width: 1px !important;
  min-height: 1px !important; max-height: 1px !important;
  padding: 0 !important; margin: -1px !important; border: 0 !important;
  opacity: 0 !important; pointer-events: none !important;
  clip-path: inset(50%) !important; overflow: hidden !important;
}

/* (s124 — item 9) tokens da barra de rolagem. Globais de propósito:
   quem rola herda; quadro de curva maior sobrescreve `--rola-folga`. */
:root {
  --rola-largura: 14px;   /* era 11 — cabe o polegar E o recuo */
  --rola-recuo:    4px;   /* transparente dos dois lados do polegar */
  --rola-folga:   12px;   /* a calha começa depois da curva do quadro */
}

:root {
  /* Fundo & superfícies — claro neutro com leve frescor verde */
  --bg:           #f5f8f6;
  --surface:      #ffffff;
  --surface-2:    #edf3ef;
  --line:         #dfe8e2;
  --line-strong:  #c3d2c8;

  /* Texto (4 níveis) — verde-carvão */
  --ink:          #13201a;
  --ink-2:        #3f5147;
  --ink-3:        #64776c;
  --ink-faint:    #9baba1;

  /* Acento principal — verde-clínica */
  --accent:        #0e8a5f;
  --accent-strong: #0b6e4c;
  --accent-deep:   #0c2f23;   /* topbar, blocos de destaque */
  --accent-soft:   rgba(14, 138, 95, 0.10);
  --grad-accent:   linear-gradient(135deg, #11996a 0%, #0b6e4c 100%);

  /* Acento secundário — dourado do logo */
  --gold:         #c79a3c;
  --gold-soft:    rgba(199, 154, 60, 0.14);

  /* Semânticas — mais vivas */
  --ok:           #15803d;
  --ok-soft:      rgba(21, 128, 61, 0.10);
  --erro:         #c0392b;
  --erro-soft:    rgba(192, 57, 43, 0.10);
  --info:         #1d6fb8;
  --info-soft:    rgba(29, 111, 184, 0.10);
  --alerta:       #b45309;
  --alerta-soft:  rgba(180, 83, 9, 0.12);

  /* Tipografia — Sora (títulos) + Inter (texto e DADOS).
     ⛔⛔ (s127 — decisão do dono) A FONTE DE DADOS É INTER, POR COMPLETO.
     Verbatim: "não gosto da fonte e trocamos em alguns lugares (a que
     usas para dados) mas quero isso feito por completo". A s123 tirou a
     JetBrains Mono dos RÓTULOS; a s127 tirou dos DADOS também — o
     alinhamento de coluna que era o papel da mono passa pro
     `font-variant-numeric: tabular-nums` global (dígito de largura fixa
     na Inter). `--font-mono` fica como ALIAS de compat (s91: mover
     deixando alias, nunca duplicar); código novo usa `--font-dados`. */
  --font-display: 'Sora', 'Inter', -apple-system, system-ui, sans-serif;
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  --font-dados: 'Inter', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  --font-mono: var(--font-dados);

  /* ⛔ (s127 — o PADRÃO que o dono pediu: "criar o padrão e o fiscal
     disso para nao se repetir") ESCALA TIPOGRÁFICA ÚNICA — 12 degraus.
     A auditoria da s127 achou 491 font-size em px solto, em 22 valores
     diferentes (9→34px, com 10.8 e 11.8 no meio). Regra: font-size nas
     TELAS é sempre var(--fs-*); px só aqui. Papel de cada degrau:
       micro  selo/contagem      rotulo  rótulo de campo, eyebrow
       mini   meta/detalhe       corpo   valor de campo, célula, texto
       medio  nome em card       titulo  título de card
       sub    subtítulo          head    título de página
       display-sm/display/num/num-lg     números e heros de stat
     Fiscal: H7 do auditar_html.py. */
  --fs-micro:      10px;
  --fs-mini:       11px;
  --fs-rotulo:     12px;
  --fs-corpo:      13px;
  --fs-medio:      14px;
  --fs-titulo:     15px;
  --fs-sub:        16px;
  --fs-head:       18px;
  --fs-display-sm: 20px;
  --fs-display:    24px;
  --fs-num:        28px;
  --fs-num-lg:     34px;

  /* (s127) ALTURAS DE BOTÃO/CONTROLE — 4 degraus (eram 7 alturas
     declaradas na casa). Botão de AÇÃO com texto usa a escada; botão de
     ÍCONE quadrado dimensiona pelo contexto (fora do fiscal).
       micro 26 (jt-btn, mini de janela) · compacta 32 (tabela/painel)
       padrão 38 (pílulas de formulário, .pd-bt, .btn-ghost)
       cta 44 (.btn-primary) */
  --alt-bt-micro:    26px;
  --alt-bt-compacta: 32px;
  --alt-bt:          38px;
  --alt-bt-cta:      44px;

  /* Raios */
  --r-sm: 8px;
  --r:    12px;
  --r-lg: 16px;
  /* (s294) a tinta do PAPEL impresso (impressos do paciente, declaração, guia) — de propósito outra que a da tela */
  --papel-tinta: #111; --papel-texto: #333; --papel-fio: #bbb; --papel-fio-claro: #ccc;

  /* Gaps — grade de 8px */
  --gap-xs:  4px;
  --gap-sm:  8px;
  --gap:     16px;
  --gap-lg:  24px;
  --gap-xl:  32px;

  /* Sombras — camadas suaves com tinta verde-carvão */
  --shadow-soft:   0 1px 2px rgba(12,47,35,0.05), 0 6px 20px rgba(12,47,35,0.06);
  --shadow-strong: 0 2px 6px rgba(12,47,35,0.07), 0 18px 40px rgba(12,47,35,0.12);

  /* Anel de foco (teclado) */
  --focus-ring: 0 0 0 3px rgba(14,138,95,0.28);

  /* Easing (impeccable): desaceleração exponencial, nunca bounce */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);

  /* Paleta categórica de gráficos (validada: 6 checks dataviz, s15) */
  --chart-1: #0e8a5f;   /* verde-clínica */
  --chart-2: #a87b24;   /* dourado-escuro */
  --chart-3: #1d6fb8;   /* azul */
  --chart-4: #b45309;   /* laranja queimado */
  --chart-5: #8250c4;   /* roxo */
  --chart-grid: #e3ebe6;
}


/* ────────────────────────────────────────────────────────
   2. RESET
   ──────────────────────────────────────────────────────── */

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  /* (s127) dígito de largura fixa em TODA a casa: é o que segura o
     alinhamento de coluna agora que a fonte de dados é a Inter */
  font-variant-numeric: tabular-nums;
  /* Luz suave de marca no topo da página — dá profundidade sem pesar */
  background:
    radial-gradient(1100px 340px at 50% -140px, rgba(14,138,95,0.07), transparent 70%),
    var(--bg);
  background-attachment: fixed;
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-medio);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  min-height: 100vh;

  /* Fade-in suave depois que os fetches criticos carregam.
     JS adiciona a classe 'pronto' quando o conteudo da pagina esta pronto.
     Failsafe: <script inline> em cada pagina libera apos 1500ms se algo falhar. */
  opacity: 0;
  transition: opacity 220ms ease-out;
}

body.pronto {
  opacity: 1;
}

img {
  max-width: 100%;
  height: auto;
  display: block;
}

button {
  font-family: inherit;
  font-size: inherit;
  cursor: pointer;
  border: none;
  background: none;
}

input, select, textarea {
  font-family: inherit;
  font-size: inherit;
  color: inherit;
}

a {
  color: var(--accent);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

code, pre {
  font-family: var(--font-dados);
  font-size: 0.9em;
  background: var(--surface-2);
  padding: 1px 6px;
  border-radius: var(--r-sm);
}


/* ────────────────────────────────────────────────────────
   3. TIPOGRAFIA BASE
   ──────────────────────────────────────────────────────── */

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
}

h1 { font-size: var(--fs-num); letter-spacing: -0.02em; }
h2 { font-size: var(--fs-display-sm); }
h3 { font-size: var(--fs-sub); }
h4 { font-size: var(--fs-medio); }

p {
  color: var(--ink-2);
}


/* ────────────────────────────────────────────────────────
   4. TOPBAR
   ──────────────────────────────────────────────────────── */

.topbar {
  background: linear-gradient(180deg, #0e3a2b 0%, var(--accent-deep) 100%);
  border-bottom: 1px solid rgba(255,255,255,0.08);
  position: sticky;
  top: 0;
  z-index: 10;
}

/* Filete verde de marca — brilho tecnológico discreto */
@keyframes topbar-varredura {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}
.topbar::after {
  content: '';
  display: block;
  height: 2px;
  background: linear-gradient(90deg,
    rgba(17,153,106,0.10) 0%, #11996a 35%,
    #5fd9a8 50%, #11996a 65%, rgba(17,153,106,0.10) 100%);
  background-size: 200% 100%;
  animation: topbar-varredura 7s linear infinite;
}

.topbar-inner {
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 var(--gap);
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--gap-sm);
}

.brand-icon {
  /* chip branco atrás da logo: cores originais visíveis no topbar escuro */
  width: 30px;
  height: 30px;
  padding: 4px;
  box-sizing: border-box;
  background: #ffffff;
  border-radius: 9px;
  box-shadow: 0 1px 4px rgba(0,0,0,0.25);
}

.brand-name {
  font-family: var(--font-display);
  font-size: var(--fs-sub);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: #ffffff;
}

.brand-name span {
  color: #5fd9a8;   /* verde-menta da família da marca */
  font-weight: 600;
}

.topbar-right {
  display: flex;
  align-items: center;
  gap: var(--gap);
}

/* Marca em chip branco + status (V2) */
.brand-chip {
  width: 34px; height: 34px;
  background: #ffffff;
  border-radius: 9px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 1px 4px rgba(0,0,0,0.25);
  flex: 0 0 34px;
}
.brand-chip .brand-icon {
  width: 24px; height: 24px;
  filter: none !important;
  background: transparent;
  padding: 0;
  box-shadow: none;
  border-radius: 0;
}
.ia-pill {
  display: inline-flex; align-items: center; gap: 6px;
  margin-left: 10px;
  font-size: var(--fs-mini); font-weight: 600; letter-spacing: .04em;
  color: #d9f3e7;
  background: rgba(255,255,255,.10);
  border: 1px solid rgba(255,255,255,.18);
  border-radius: 999px;
  padding: 4px 11px;
  text-transform: uppercase;
}
.ia-pill i {
  width: 7px; height: 7px; border-radius: 50%;
  background: #2ee6a8;
  box-shadow: 0 0 8px rgba(46,230,168,.9);
  animation: v2-pulso 1.6s ease-in-out infinite;
}
@media (max-width: 520px) { .ia-pill { display: none; } }

.topbar .btn-ghost {
  color: rgba(255,255,255,0.85);
  border-color: rgba(255,255,255,0.25);
}

.topbar .btn-ghost:hover {
  background: rgba(255,255,255,0.10);
  color: #ffffff;
}


/* ────────────────────────────────────────────────────────
   5. CARD
   ──────────────────────────────────────────────────────── */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-soft);
  padding: var(--gap);
}

/* ⛔⛔ (s123 — decisão do dono) A MONO É PRA DADO, NÃO PRA RÓTULO.
   Verbatim, olhando os títulos do ProDoctor: *"não sou muito fã das
   fontes utilizadas ali nos titulos da box Paciente, consultas marcadas
   (…) nao quero mais essa fonte antiga (…) virar padrão de todo
   projeto"*. E a substituta já existia na casa: o título de janela do
   CRM (`.jt-nome`) é Inter, caixa normal — foi ele que o agradou.

   Varredura das 27 telas, classe por classe: das 28 que usavam
   `--font-mono`, 8 eram RÓTULO (saem), 16 são DADO — número, hora,
   data, CPF, coluna de tabela — e FICAM, porque é a mono que alinha
   coluna. 4 estavam mortas sem nenhum consumidor (medido) e saíram.

   A RÉGUA: mono = dado. Rótulo e título = Inter, caixa normal.        */
.card-eyebrow {
  font-size: var(--fs-corpo);
  font-weight: 700;
  color: var(--ink);
  margin-bottom: var(--gap-xs);
}

.card-title {
  font-size: var(--fs-titulo);
  font-weight: 600;
  margin-bottom: var(--gap-sm);
}

.card-text {
  font-size: var(--fs-corpo);
  color: var(--ink-2);
  line-height: 1.5;
}


/* ────────────────────────────────────────────────────────
   6. FORM
   ──────────────────────────────────────────────────────── */

.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.field-label {
  font-size: var(--fs-rotulo);
  font-weight: 600;
  color: var(--ink-2);
}

.field-input {
  background: var(--bg);
  border: 1px solid var(--line-strong);
  border-radius: var(--r);
  padding: 0 14px;
  height: 44px;
  font-size: var(--fs-sub);          /* 16px evita zoom automático no iOS */
  color: var(--ink);
  transition: border-color 150ms, box-shadow 150ms;
}

.field-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.field-input::placeholder {
  color: var(--ink-3);
}


/* ────────────────────────────────────────────────────────
   7. BOTÕES
   ──────────────────────────────────────────────────────── */

.btn-primary {
  background: var(--grad-accent);
  color: #ffffff;
  border-radius: var(--r);
  font-weight: 600;
  font-size: var(--fs-medio);
  min-height: var(--alt-bt-cta);
  min-width: 44px;
  padding: 0 20px;
  box-shadow: 0 1px 2px rgba(11,110,76,0.25);
  transition: filter 150ms, transform 150ms, box-shadow 150ms;
}

.btn-primary:hover {
  filter: brightness(1.07);
  transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(11,110,76,0.32);
}

.btn-primary:active {
  transform: scale(0.98);
}

.btn-primary:focus-visible,
.btn-ghost:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.btn-ghost {
  background: transparent;
  color: var(--ink-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--r);
  font-weight: 500;
  font-size: var(--fs-corpo);
  min-height: var(--alt-bt)   /* (s127) 36→38: alinhado à pílula de formulário */;
  padding: 0 14px;
  transition: background 150ms, color 150ms;
}

.btn-ghost:hover {
  background: var(--surface-2);
  color: var(--ink);
}


/* ────────────────────────────────────────────────────────
   8. LAYOUT — LOGIN
   ──────────────────────────────────────────────────────── */

.login-body {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: var(--gap);
}

.login-shell {
  width: 100%;
  max-width: 440px;
}

.login-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-strong);
  padding: 32px 28px 20px;
}

.login-header {
  text-align: center;
  margin-bottom: 28px;
}

.login-title {
  font-size: var(--fs-display);
  font-weight: 600;
  letter-spacing: -0.02em;
  margin-bottom: var(--gap-xs);
}

.login-subtitle {
  font-size: var(--fs-corpo);
  font-weight: 500;
  color: var(--ink-3);
}

.login-form {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
}

.login-submit {
  margin-top: var(--gap-sm);
  width: 100%;
}

.login-erro {
  background: var(--erro-soft);
  color: var(--erro);
  font-size: var(--fs-corpo);
  padding: 10px 14px;
  border-radius: var(--r);
  border: 1px solid rgba(192,57,43,0.38);
}

.login-footer {
  border-top: 1px solid var(--line);
  margin-top: 24px;
  padding-top: 16px;
  display: flex;
  justify-content: center;
}

.login-mark {
  width: 44px;
  height: 44px;
  opacity: 0.6;
}


/* ────────────────────────────────────────────────────────
   9. LAYOUT — HOME UNIVERSAL
   ──────────────────────────────────────────────────────── */

.page-shell {
  max-width: 1280px;
  margin: 0 auto;
  padding: var(--gap-lg) var(--gap);
}

/* ── Saudação ───────────────────────────────────────── */

.saudacao {
  margin-bottom: var(--gap-lg);
}

.saudacao-titulo {
  font-size: var(--fs-num);
  font-weight: 600;
  letter-spacing: -0.02em;
  margin-bottom: var(--gap-xs);
}

.saudacao-subtitulo {
  color: var(--ink-3);
  font-size: var(--fs-titulo);
}

/* ── Busca universal ─────────────────────────────────── */

.busca-shell {
  margin-bottom: var(--gap-xl);
}

.busca-caixa {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-soft);
  display: flex;
  align-items: center;
  padding: 0 14px;
  transition: border-color 150ms, box-shadow 150ms;
}

.busca-caixa:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft), var(--shadow-soft);
}

.busca-icone {
  width: 18px;
  height: 18px;
  color: var(--ink-3);
  flex-shrink: 0;
}

.busca-input {
  flex: 1;
  background: transparent;
  border: none;
  outline: none;
  height: 52px;
  padding: 0 12px;
  font-size: var(--fs-sub);
  color: var(--ink);
}

.busca-input::placeholder {
  color: var(--ink-3);
}

.busca-dica {
  font-family: var(--font-dados);
  font-size: var(--fs-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-top: var(--gap-sm);
  text-align: center;
}

/* ── 4 cards de números ──────────────────────────────── */

.numeros-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--gap);
  margin-bottom: var(--gap-xl);
}

.numero-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-soft);
  padding: var(--gap);
  display: block;
  text-decoration: none;
  color: inherit;
  transition: transform 150ms, box-shadow 150ms, border-color 150ms;
  position: relative;
}

.numero-card:hover {
  text-decoration: none;
  transform: translateY(-1px);
  box-shadow: var(--shadow-strong);
  border-color: var(--line-strong);
}

.numero-card.numero-card-alerta {
  border-color: rgba(192,57,43,0.45);
  background: linear-gradient(0deg, rgba(192,57,43,0.04), rgba(192,57,43,0.04)), var(--surface);
}

/* Icone no canto superior direito do card */
.numero-card-icone {
  position: absolute;
  top: var(--gap);
  right: var(--gap);
  width: 32px;
  height: 32px;
  border-radius: var(--r-sm);
  background: var(--accent-soft);
  color: var(--accent);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.numero-card-icone svg {
  width: 18px;
  height: 18px;
}

.numero-card-icone-erro {
  background: var(--erro-soft);
  color: var(--erro);
}

.numero-eyebrow {
  font-size: var(--fs-rotulo);
  font-weight: 600;
  color: var(--ink-3);
  margin-bottom: 6px;
  padding-right: 40px;   /* espaço pro ícone do canto */
}

/* Numero + sufixo "hoje" na mesma linha */
.numero-valor-linha {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 6px;
}

.numero-valor {
  font-family: var(--font-sans);
  font-size: var(--fs-num-lg);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ink);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

.numero-valor-sufixo {
  font-size: var(--fs-corpo);
  color: var(--ink-3);
  font-weight: 400;
}

.numero-comparativo {
  font-family: var(--font-dados);
  font-size: var(--fs-mini);
  color: var(--ink-3);
}

.numero-card-alerta .numero-comparativo {
  color: var(--erro);
  font-weight: 500;
}

/* ── Grade de gráficos ───────────────────────────────── */

.graficos-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--gap);
  margin-bottom: var(--gap-xl);
}

.grafico-card {
  padding: var(--gap-lg);
}

.grafico-wrap {
  position: relative;
  height: 280px;
  margin-top: var(--gap);
}

.grafico-vazio {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  color: var(--ink-3);
  font-size: var(--fs-corpo);
  padding: var(--gap);
}


/* ── Ferramentas ─────────────────────────────────────── */

.ferramentas {
  margin-bottom: var(--gap-xl);
}

.ferramentas-titulo {
  font-size: var(--fs-head);
  font-weight: 600;
  margin-bottom: var(--gap);
  color: var(--ink-2);
}

.ferramentas-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--gap);
}

.ferramenta-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-soft);
  padding: var(--gap-lg);
  text-decoration: none;
  color: inherit;
  display: flex;              /* card vira coluna: o .ferramenta-stats */
  flex-direction: column;     /* gruda embaixo via margin-top:auto, e  */
  transition: transform 150ms, box-shadow 150ms, border-color 150ms;
}                             /* o grid já estica todos pra mesma altura */

.ferramenta-card:hover {
  text-decoration: none;
  transform: translateY(-1px);
  box-shadow: var(--shadow-strong);
  border-color: var(--accent);
}

.ferramenta-card-vazia {
  border-style: dashed;
  border-color: var(--line-strong);
  background: transparent;
  box-shadow: none;
  opacity: 0.7;
  cursor: default;
}

.ferramenta-card-vazia:hover {
  transform: none;
  box-shadow: none;
  border-color: var(--line-strong);
}

.ferramenta-icone {
  width: 32px;
  height: 32px;
  color: var(--accent);
  margin-bottom: var(--gap);
}

.ferramenta-icone svg {
  width: 100%;
  height: 100%;
}

.ferramenta-titulo {
  font-size: var(--fs-sub);
  font-weight: 600;
  margin-bottom: var(--gap-xs);
  color: var(--ink);
}

.ferramenta-desc {
  font-size: var(--fs-corpo);
  color: var(--ink-2);
  line-height: 1.5;
}


.ferramenta-stats {
  font-family: var(--font-dados);
  font-size: var(--fs-mini);
  color: var(--ink-3);
  margin-top: auto;            /* gruda no rodapé do card */
  padding-top: var(--gap);
  border-top: 1px solid var(--line);
}
/* o conteúdo acima dos stats precisa de respiro fixo */
.ferramenta-desc { margin-bottom: var(--gap); }

/* ── Sub-telas (cards menores, na página do painel) ──── */

.subtelas-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--gap-sm);
}

.subtela-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-soft);
  padding: var(--gap);
  text-decoration: none;
  color: inherit;
  display: block;
  transition: transform 150ms, box-shadow 150ms, border-color 150ms;
}

.subtela-card:hover {
  text-decoration: none;
  transform: translateY(-1px);
  box-shadow: var(--shadow-strong);
  border-color: var(--line-strong);
}

.subtela-card-icone {
  width: 36px;
  height: 36px;
  border-radius: var(--r-sm);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: var(--gap-sm);
}

.subtela-card-icone svg {
  width: 20px;
  height: 20px;
}

.subtela-card-icone-accent {
  background: var(--accent-soft);
  color: var(--accent);
}

.subtela-card-icone-info {
  background: var(--info-soft);
  color: var(--info);
}

.subtela-card-icone-erro {
  background: var(--erro-soft);
  color: var(--erro);
}

.subtela-card-titulo {
  font-size: var(--fs-titulo);
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 4px;
}

.subtela-card-desc {
  font-size: var(--fs-rotulo);
  color: var(--ink-2);
  line-height: 1.4;
}


/* ────────────────────────────────────────────────────────
   10. RESPONSIVO — desktop e tablet
   ──────────────────────────────────────────────────────── */

@media (min-width: 600px) {

  .numeros-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .ferramentas-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .subtelas-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 768px) {

  body { font-size: var(--fs-medio); }

  .topbar-inner {
    height: 64px;
  }

  .brand-icon {
    width: 28px;
    height: 28px;
  }

  .login-card {
    padding: 40px 36px 24px;
  }

  .login-title {
    font-size: var(--fs-num);
  }

  .saudacao-titulo {
    font-size: 36px;
  }

  .graficos-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {

  .numeros-grid {
    grid-template-columns: repeat(5, 1fr);
  }

  .saudacao-titulo {
    font-size: 40px;
  }

  .graficos-grid {
    grid-template-columns: repeat(3, 1fr);
  }

  .ferramentas-grid {
    grid-template-columns: repeat(3, 1fr);
  }

  .subtelas-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}


/* ════════════════════════════════════════════════════════
   12. CARD GRANDE DE HISTÓRICO (na home do painel)
   ════════════════════════════════════════════════════════ */

.historico-section {
  margin-bottom: var(--gap-xl);
}

.historico-card {
  display: block;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-soft);
  padding: var(--gap-lg);
  text-decoration: none;
  color: inherit;
  transition: transform 150ms, box-shadow 150ms, border-color 150ms;
}

.historico-card:hover {
  text-decoration: none;
  transform: translateY(-1px);
  box-shadow: var(--shadow-strong);
  border-color: var(--accent);
}

.historico-header {
  display: flex;
  align-items: flex-start;
  gap: var(--gap);
  margin-bottom: var(--gap-sm);
}

.historico-icone {
  width: 44px;
  height: 44px;
  border-radius: var(--r-sm);
  background: var(--accent-soft);
  color: var(--accent);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.historico-icone svg {
  width: 22px;
  height: 22px;
}

.historico-titulo-bloco {
  flex: 1;
  min-width: 0;
}

.historico-titulo {
  font-size: var(--fs-head);
  font-weight: 600;
  color: var(--ink);
  margin-top: 2px;
}

.historico-desc {
  font-size: var(--fs-corpo);
  color: var(--ink-2);
  line-height: 1.5;
  margin-bottom: var(--gap);
}

.historico-preview {
  background: var(--surface-2);
  border-radius: var(--r-sm);
  padding: var(--gap-sm);
  margin-bottom: var(--gap-sm);
  min-height: 60px;
}

.historico-preview-loading,
.historico-preview-vazio {
  color: var(--ink-3);
  font-size: var(--fs-rotulo);
  text-align: center;
  padding: var(--gap-sm);
}

.historico-preview-item {
  display: flex;
  align-items: center;
  gap: var(--gap-sm);
  padding: 6px 4px;
  border-bottom: 1px solid var(--line);
}

.historico-preview-item:last-child {
  border-bottom: none;
}

.historico-preview-icone {
  width: 26px;
  height: 26px;
  border-radius: var(--r-sm);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  background: var(--accent-soft);
  color: var(--accent);
}

.historico-preview-icone svg {
  width: 14px;
  height: 14px;
}

.historico-preview-icone-erro          { background: var(--erro-soft); color: var(--erro); }
.historico-preview-icone-transferencia { background: var(--info-soft); color: var(--info); }
.historico-preview-icone-desmarcacao   { background: var(--info-soft); color: var(--info); }

.historico-preview-conteudo {
  flex: 1;
  min-width: 0;
}

.historico-preview-desc {
  font-size: var(--fs-corpo);
  color: var(--ink-2);
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.historico-preview-quando {
  font-family: var(--font-dados);
  font-size: var(--fs-micro);
  color: var(--ink-3);
  margin-top: 2px;
}

.historico-cta {
  color: var(--accent);
  font-size: var(--fs-corpo);
  font-weight: 500;
  text-align: right;
}

/* ════════════════════════════════════════════════════════
   13. TIMELINE (sub-tela de histórico)
   ════════════════════════════════════════════════════════ */

.timeline {
  display: flex;
  flex-direction: column;
  gap: var(--gap-sm);
}

.timeline-item {
  display: flex;
  gap: var(--gap);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-soft);
  padding: var(--gap);
}

.timeline-item-erro {
  border-color: rgba(192,57,43,0.40);
  background: linear-gradient(0deg, rgba(192,57,43,0.03), rgba(192,57,43,0.03)), var(--surface);
}

.timeline-item-reagendamento {
  border-color: rgba(14,138,95,0.40);
}

.timeline-icone {
  width: 36px;
  height: 36px;
  border-radius: var(--r-sm);
  background: var(--accent-soft);
  color: var(--accent);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.timeline-icone svg {
  width: 18px;
  height: 18px;
}

.timeline-icone-erro          { background: var(--erro-soft); color: var(--erro); }
.timeline-icone-transferencia { background: var(--info-soft); color: var(--info); }
.timeline-icone-desmarcacao   { background: var(--info-soft); color: var(--info); }

.timeline-conteudo {
  flex: 1;
  min-width: 0;
}

.timeline-titulo {
  font-size: var(--fs-medio);
  color: var(--ink);
  margin-bottom: 4px;
  line-height: 1.4;
}

.timeline-detalhes {
  font-size: var(--fs-corpo);
  color: var(--ink-2);
  line-height: 1.5;
  margin-bottom: 6px;
}

.timeline-meta {
  font-family: var(--font-dados);
  font-size: var(--fs-micro);
  letter-spacing: 0.04em;
  color: var(--ink-3);
  text-transform: uppercase;
}

/* ════════════════════════════════════════════════════════
   11. SUB-TELAS DO PAINEL (Agendamentos, Desmarcações, etc.)
   ════════════════════════════════════════════════════════ */

/* ── Header da sub-tela (breadcrumb + título) ─────────── */

.subtela-header {
  margin-bottom: var(--gap-lg);
}

.breadcrumb {
  margin-bottom: var(--gap-sm);
}

/* .breadcrumb-link e .subtela-titulo: specs movidas pra seção 16
   (Tela padrão) — aqui ficam só os aliases lá definidos. */

.subtela-contagem {
  font-family: var(--font-dados);
  font-size: var(--fs-corpo);
  font-weight: 500;
  color: var(--ink-3);
}

/* ── Barra de filtros ─────────────────────────────────── */

.filtros-bar {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-soft);
  padding: var(--gap);
  margin-bottom: var(--gap);
  display: flex;
  flex-direction: column;
  gap: var(--gap-sm);
}

.filtros-grupo {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.filtros-label {
  font-size: var(--fs-rotulo);
  font-weight: 600;
  color: var(--ink-3);
}

.filtros-pillgroup {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.filtro-pill {
  background: transparent;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  padding: 6px 14px;
  font-size: var(--fs-rotulo);
  color: var(--ink-2);
  cursor: pointer;
  transition: background 150ms, border-color 150ms, color 150ms;
  min-height: 32px;
}

.filtro-pill:hover {
  background: var(--surface-2);
}

.filtro-pill.ativo {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--bg);
}

/* ⛔ (s123 — decisão do dono) TODO CAMPO DE ESCOLHA É PÍLULA.
   Verbatim: *"acho que eles devem respeitar o formato do pill mais
   arredondado, varredura inteira no sistema/painel para manter novo
   padrão"*. Uma spec só: altura 38, raio 999, seta desenhada (a nativa
   muda de cara em cada sistema operacional). Serve `<select>` e o campo
   de texto do vv-combo — é o que faz os dois parecerem a mesma peça.  */
.campo-pill,
.filtros-select {
  background: var(--bg);
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  min-height: var(--alt-bt);
  padding: 0 32px 0 12px;
  font-size: var(--fs-corpo);
  color: var(--ink);
  appearance: none;
  background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237a7570' stroke-width='2'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 14px;
  cursor: pointer;
}

.campo-pill:focus,
.filtros-select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.campo-pill { color: var(--ink); font-size: var(--fs-medio); padding: 0 34px 0 16px;
  transition: border-color 150ms, box-shadow 150ms; }
.campo-pill::placeholder { color: var(--ink-faint); }

/* ⛔ (s124) A SETINHA ⌄ PROMETE LISTA — campo de TEXTO puro não tem uma.
   A pílula virou o padrão da casa na s123 e passou a vestir também
   campos onde não há nada pra escolher (Nome, Nascimento, Telefone do
   cadastro; o Recado da recepção): o ⌄ ali diz "clique que abre" e não
   abre nada. Quem TEM lista é `[role="combobox"]`, posto pelo próprio
   `vvCombo` — então a seta passa a sair só nesses, sem tocar em tela
   nenhuma. Campo de texto fica com a pílula e sem a promessa. */
/* (s124) o campo que NASCEU de um <select> sempre abre lista — a seta é
   a mesma do `.campo-pill`, então onde ela já vinha nada muda. */
/* ═══════════════════════════════════════════════════════════════════════
   (s161 · A5a — decisão do dono) O COMBO DA CASA, CHEIO E COM O ×.
   Estas regras SÃO as do `.m3-caixa-combo` do M3 Cadastros — que por sua
   vez são as `.combo` / `.combo.cheio` / `.limpa` do arquivo do
   protótipo, medidas em 240/240. Mudaram de casa, não de valor.
   A SETA continua sendo a `.vv-campo-lista` (s124): quando o campo enche,
   ela sai e o × entra no lugar dela.
   ⚠️ `!important` é OBRIGATÓRIO aqui: o `vvComboDeSelect` copia o estilo
   COMPUTADO pro style INLINE do campo (cor, fundo, borda, peso), e inline
   ganha de classe. Sem ele o verde nunca apareceria nos ~54 combos que
   nascem de <select>. */
.vv-combo-caixa { position: relative; display: flex; min-width: 0; }
.vv-combo-caixa > input { width: 100%; min-width: 0; max-width: 100%; }
.vv-combo-caixa > input.cheio {
  border-color: var(--accent) !important;
  color: var(--accent-strong) !important;
  font-weight: 600 !important;
  background-color: var(--accent-soft) !important;
  background-image: none !important;      /* a seta da s124 sai */
}
.vv-combo-caixa .limpa {
  width: 16px; height: 16px; border-radius: 50%;
  display: none; align-items: center; justify-content: center; flex: none;
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  background: none; border: 0; padding: 0; cursor: pointer; color: var(--ink-3);
}
.vv-combo-caixa .limpa:hover { background: rgba(11, 110, 76, .15); }
/* ⛔ (s174 · G2 — ele: "os x dos dropdowns padrão da casa só aparecer ao
   passar o mouse em cima da box") O × VIVE NO HOVER. `:focus-within` vai
   junto: sem ele quem chega pelo teclado ficaria sem o gesto. */
.vv-combo-caixa.cheio .limpa { display: none; }
.vv-combo-caixa.cheio:hover .limpa,
.vv-combo-caixa.cheio:focus-within .limpa {
  display: flex;
  color: var(--accent-strong);
  background: var(--accent-soft);         /* no arquivo o × mora DENTRO do combo cheio */
}
/* a seta do ARQUIVO (a `.vv-campo-lista` da s124 sai no vestir — duas
   setas no mesmo campo é o que a régua dela proíbe). Some quando enche. */
.vv-combo-caixa .seta {
  position: absolute; right: 9px; top: 50%; transform: translateY(-50%);
  color: var(--ink-3); pointer-events: none; display: flex;
}
.vv-combo-caixa.cheio .seta { display: none; }
/* ⛔⛔ (s185 — a régua dele, medida rodando) O CAMPO CHEIO NÃO FICA MUDO.
   Medição da s185: dos 60 campos que nascem preenchidos, 27 não mostravam
   NADA à direita — a seta some quando enche (linha acima) e o × estava
   escondido pelo catálogo. Na classe TRAVADA é a seta que fica, sempre:
   ela é o que diz "aqui se escolhe de uma lista". E o × não existe ali,
   porque vazio não é estado possível. */
.vv-combo-caixa.vv-travado .limpa { display: none !important; }
.vv-combo-caixa.vv-travado .seta,
.vv-combo-caixa.vv-travado.cheio .seta { display: flex !important; }
.vv-combo-caixa.vv-travado > input { cursor: pointer; caret-color: transparent; }
/* ⛔ (s185 — foto dele: "ficou com 2 x ali, péssimo") O × DO NAVEGADOR MORRE.
   Todo campo de busca da casa é `type=search`, e o Chrome desenha o próprio
   botão de limpar: azul, fora da paleta, e visível sem hover. Ele já estava
   na busca do topo do painel — some, e fica só o × da casa. */
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none;
  appearance: none;
  display: none;
}
/* (s161b) caixa sem altura = campo escondido pela vista: a seta e o ×,
   que são absolutos, sairiam soltos na tela. Quem decide é a ALTURA
   medida, não o motivo de estar escondido. */
/* (s161e) caixa de campo escondido SAI DO FLUXO — a s161b só apagava a
   seta, e o wrapper seguia ocupando lugar no flex do dock (692 px de
   barra invisível em dois filtros que a vista esconde). */
.vv-combo-caixa.vazia { display: none !important; }
.vv-combo-caixa.vazia .seta,
.vv-combo-caixa.vazia .limpa { display: none !important; }

/* (s161f) a trava da s161e caiu no mesmo dia — o dono quer digitar no
   filtro igual digita na ficha. A classe some junto. */
.vv-combo-caixa > input { padding-right: 30px; }
/* (s162 · o1a) caixa de campo de TEXTO: não tem seta, então o vão do
   lado direito só existe quando o × está lá. Sem isto, todo campo de
   texto do cadastro perderia 30px de largura útil por nada — e texto
   cortado é o que a régua T1 proíbe. */
.vv-combo-caixa.so-texto > input { padding-right: 11px; }
.vv-combo-caixa.so-texto.cheio > input { padding-right: 30px; }

.vv-campo-lista {
  background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237a7570' stroke-width='2'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e") !important;
  background-repeat: no-repeat !important;
  background-position: right 10px center !important;
  background-size: 14px !important;
  padding-right: 30px !important;
}

input.campo-pill:not([role="combobox"]) {
  background-image: none;
  padding-right: 16px;
  cursor: text;
}

/* ⛔ (s123) O CAMPO E A LISTA SÃO UM PAR — decisão dele, na 2ª volta:
   *"fica como estava antes só que a largura e o formato igual, com
   paridade"*. A lista continua SOLTA (a versão colada foi recusada:
   confundia a zona de digitar com a de escolher), mas passa a ter a
   largura EXATA do campo, o mesmo raio, e a borda dos dois acende
   junto. O `[aria-expanded]` é posto pelo próprio `vvCombo` — então
   todo campo de catálogo da casa herda isto sem tocar em nenhuma tela. */
[role="combobox"][aria-expanded="true"].campo-pill {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* ⛔⛔ (s130 — fotos do dono: "pill não está respeitando o padrão,
   vazamento aos lados") DROPDOWN-PILL DA CASA — fonte única.
   Era o 3º e o 4º dropdown-de-filtro artesanal (medicos.html e
   dia.html, cada um com seu CSS e um menu MAIS LARGO que a pílula).
   O botão veste a MESMA pele do .campo-pill (altura 38, raio 999,
   seta desenhada) e o menu é o PAR dele — régua s123: a lista tem a
   largura EXATA do campo e o raio das listas da casa (19px). Quem
   pareia as larguras é vvDdParear() no vv-ui.js: mede o menu, dá a
   mesma largura aos dois, e o menu NUNCA vaza dos lados.
   Filtro novo de tela = .vv-dd + vvDdLigar(); dropdown artesanal é
   regressão (fiscal H10 do auditar_html).                              */
.vv-dd { position: relative; display: inline-flex; flex: none; }
.vv-dd-bt {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: var(--alt-bt); padding: 0 34px 0 16px;
  border: 1px solid var(--line-strong); border-radius: 999px;
  background-color: var(--bg);
  background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237a7570' stroke-width='2'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
  background-repeat: no-repeat; background-position: right 12px center;
  background-size: 14px;
  font-family: var(--font-sans); font-size: var(--fs-corpo); font-weight: 600;
  color: var(--ink-2); cursor: pointer; white-space: nowrap;
  transition: border-color 150ms, box-shadow 150ms;
}
.vv-dd-bt:hover { background-color: var(--surface-2); }
.vv-dd.aberto .vv-dd-bt {
  border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}
.vv-dd-menu {
  position: absolute; left: 0; top: calc(100% + 4px); width: 100%;
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: 19px; box-shadow: var(--shadow-strong);
  padding: 6px; z-index: 90; display: none; flex-direction: column; gap: 1px;
}
.vv-dd.aberto .vv-dd-menu { display: flex; }
.vv-dd-menu button {
  display: flex; align-items: center; gap: 8px; width: 100%; border: none;
  background: none; text-align: left; cursor: pointer; padding: 8px 12px;
  border-radius: var(--r-sm); font-family: var(--font-sans);
  font-size: var(--fs-corpo); color: var(--ink-2); white-space: nowrap;
}
.vv-dd-menu button:hover { background: var(--accent-soft); color: var(--ink); }
.vv-dd-menu button.ativo { color: var(--accent-strong); font-weight: 600; }
.vv-dd-menu button .qt {
  margin-left: auto; color: var(--ink-faint); font-size: var(--fs-rotulo);
  font-variant-numeric: tabular-nums;
}

.filtros-reset {
  background: transparent;
  border: none;
  color: var(--accent);
  font-size: var(--fs-rotulo);
  font-weight: 500;
  cursor: pointer;
  align-self: flex-start;
  min-height: 32px;
  padding: 0 6px;
}

.filtros-reset:hover {
  text-decoration: underline;
}

/* ── Lista — Mobile (cards verticais) ─────────────────── */

.lista-items {
  display: flex;
  flex-direction: column;
  gap: var(--gap-sm);
}

.lista-item {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-soft);
  padding: var(--gap);
  cursor: pointer;
  transition: border-color 150ms, transform 150ms;
}

.lista-item:hover {
  border-color: var(--line-strong);
  transform: translateY(-1px);
}

.lista-item-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--gap-sm);
  margin-bottom: 6px;
  flex-wrap: wrap;
}

.lista-item-titulo {
  font-size: var(--fs-titulo);
  font-weight: 600;
  color: var(--ink);
}

.lista-item-quando {
  font-family: var(--font-dados);
  font-size: var(--fs-mini);
  color: var(--ink-3);
}

.lista-item-meta {
  font-size: var(--fs-corpo);
  color: var(--ink-2);
  line-height: 1.5;
}

.lista-item-meta strong {
  font-weight: 500;
  color: var(--ink);
}

.lista-item-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: var(--gap-sm);
}

/* ── Tags semânticas ──────────────────────────────────── */

.tag {
  font-family: var(--font-dados);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 4px 8px;
  border-radius: var(--r-sm);
  display: inline-flex;
  align-items: center;
}

.tag-ok       { background: var(--ok-soft);     color: var(--ok); }
.tag-erro     { background: var(--erro-soft);   color: var(--erro); }
.tag-info     { background: var(--info-soft);   color: var(--info); }
.tag-accent   { background: var(--accent-soft); color: var(--accent); }
.tag-neutra   { background: var(--surface-2);   color: var(--ink-3); }

/* ── Lista vazia ─────────────────────────────────────── */

.lista-vazia {
  background: var(--surface);
  border: 1px dashed var(--line-strong);
  border-radius: var(--r);
  padding: var(--gap-xl);
  text-align: center;
  color: var(--ink-3);
}

.lista-vazia-titulo {
  font-size: var(--fs-titulo);
  font-weight: 600;
  color: var(--ink-2);
  margin-bottom: var(--gap-xs);
}

.lista-vazia-desc {
  font-size: var(--fs-corpo);
  color: var(--ink-3);
}

/* ── Erros: grupo por tipo ────────────────────────────── */

.erro-grupo {
  background: linear-gradient(0deg, rgba(192,57,43,0.03), rgba(192,57,43,0.03)), var(--surface);
  border: 1px solid rgba(192,57,43,0.40);
  border-radius: var(--r);
  box-shadow: var(--shadow-soft);
  margin-bottom: var(--gap-sm);
}

.erro-grupo-header {
  padding: var(--gap);
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--gap);
}

.erro-grupo-info {
  flex: 1;
  min-width: 0;
}

.erro-grupo-tipo {
  font-family: var(--font-dados);
  font-size: var(--fs-rotulo);
  font-weight: 600;
  color: var(--erro);
  word-break: break-word;
  margin-bottom: 4px;
}

.erro-grupo-msg {
  font-size: var(--fs-corpo);
  color: var(--ink-2);
  line-height: 1.4;
}

.erro-grupo-stats {
  font-family: var(--font-dados);
  font-size: var(--fs-mini);
  color: var(--ink-3);
  text-align: right;
  flex-shrink: 0;
}

.erro-grupo-contagem {
  font-size: var(--fs-display-sm);
  font-weight: 600;
  color: var(--ink);
  font-family: var(--font-sans);
  line-height: 1;
  margin-bottom: 4px;
}

.erro-grupo-ocorrencias {
  border-top: 1px solid var(--line);
  padding: var(--gap-sm) var(--gap);
  display: none;
}

.erro-grupo.expandido .erro-grupo-ocorrencias {
  display: block;
}

.erro-ocorrencia {
  padding: var(--gap-sm) 0;
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-corpo);
}

.erro-ocorrencia:last-child {
  border-bottom: none;
}

.erro-ocorrencia-quando {
  font-family: var(--font-dados);
  font-size: var(--fs-mini);
  color: var(--ink-3);
  margin-bottom: 4px;
}

.erro-ocorrencia-contexto {
  color: var(--ink-2);
  word-break: break-word;
}

/* ── Tabela (desktop apenas) ──────────────────────────── */

.tabela-wrap {
  display: none;
}

/* ── Responsivo das sub-telas ─────────────────────────── */

@media (min-width: 600px) {
  .filtros-bar {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: flex-end;
  }
  .filtros-grupo {
    flex: 1;
    min-width: 140px;
  }

  /* Variante: cada grupo em sua própria linha (pra quando tem muitos botões num grupo).
     Usada na sub-tela de Histórico onde "Mostrar" tem 6 botões que não cabem na mesma linha. */
  .filtros-bar.filtros-bar-empilhada {
    flex-direction: column;
    align-items: stretch;
  }
  .filtros-bar.filtros-bar-empilhada .filtros-grupo {
    flex-basis: 100%;
    min-width: 0;
  }
}

@media (min-width: 900px) {
  /* Desktop: usa tabela em vez de cards */
  .lista-items {
    display: none;
  }

  /* Exceção: .lista-items-sempre mantém cards visíveis no desktop também */
  /* (usado em sub-telas onde card é mais legível que tabela — ex: reagendamentos antes→depois) */
  .lista-items.lista-items-sempre {
    display: flex;
  }

  .tabela-wrap {
    display: block;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r);
    box-shadow: var(--shadow-soft);
    overflow: hidden;
  }

  .tabela {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--fs-corpo);
  }

  .tabela thead {
    background: var(--surface-2);
  }

  .tabela th {
    text-align: left;
    padding: 12px 14px;
    font-family: var(--font-dados);
    font-size: var(--fs-micro);
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink-3);
    white-space: nowrap;
    border-bottom: 1px solid var(--line);
  }

  .tabela td {
    padding: 12px 14px;
    border-bottom: 1px solid var(--line);
    color: var(--ink-2);
    vertical-align: top;
  }

  .tabela tbody tr {
    cursor: pointer;
    transition: background 150ms;
  }

  .tabela tbody tr:hover {
    background: var(--surface-2);
  }

  .tabela tbody tr:last-child td {
    border-bottom: none;
  }

  .tabela-mono {
    font-family: var(--font-dados);
    color: var(--ink-2);
  }

  .tabela-paciente {
    color: var(--ink);
    font-weight: 500;
  }
}


/* ────────────────────────────────────────────────────────
   14. V2 — DESIGN SYSTEM (Jun/2026)
   Primitivas novas compartilhadas entre as telas.
   ──────────────────────────────────────────────────────── */

/* ── Animações ─────────────────────────────────────────── */
@keyframes v2-subir {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes v2-pop {
  0%   { transform: scale(0.96); opacity: 0; }
  100% { transform: scale(1);    opacity: 1; }
}
@keyframes v2-brilho {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}
@keyframes v2-pulso {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.45; }
}

.v2-entra      { animation: v2-subir 280ms ease-out both; }
.v2-entra-pop  { animation: v2-pop 220ms ease-out both; }

/* ── Skeleton (carregando) ─────────────────────────────── */
.skel {
  border-radius: var(--r-sm);
  background: linear-gradient(90deg, var(--surface-2) 25%, #e4ece7 50%, var(--surface-2) 75%);
  background-size: 200% 100%;
  animation: v2-brilho 1.2s linear infinite;
  color: transparent !important;
  pointer-events: none;
  min-height: 14px;
}

/* ── Chips (o que o bot captou, filtros) ───────────────── */
.v2-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: var(--fs-corpo);
  font-weight: 600;
  color: #fff;
  background: var(--grad-accent);
  border-radius: 999px;
  padding: 6px 14px 6px 10px;
  white-space: nowrap;
  box-shadow: 0 2px 6px rgba(11,110,76,0.30);
}
.v2-chip .chip-rotulo {
  font-size: var(--fs-micro);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: rgba(255,255,255,0.95);
  background: rgba(255,255,255,0.18);
  border-radius: 999px;
  padding: 2px 8px;
}

/* ── Badges semânticas ─────────────────────────────────── */
.v2-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-rotulo);
  font-weight: 600;
  border-radius: 999px;
  padding: 4px 12px;
  white-space: nowrap;
}
.v2-badge.ok     { color: #fff; background: linear-gradient(135deg, #16a34a, #15803d); }
.v2-badge.alerta { color: #fff; background: linear-gradient(135deg, #d97706, #b45309); }
.v2-badge.erro   { color: #fff; background: linear-gradient(135deg, #dc2626, #b91c1c); }
.v2-badge.info   { color: #fff; background: linear-gradient(135deg, #2563eb, #1d4ed8); }
.v2-badge.gold   { color: #3d2c08; background: linear-gradient(135deg, #e9c265, #c79a3c); }
.v2-badge.suave-ok     { color: var(--ok);     background: rgba(21,128,61,0.14); }
.v2-badge.suave-alerta { color: var(--alerta); background: rgba(180,83,9,0.16); }
.v2-badge.suave-erro   { color: var(--erro);   background: rgba(192,57,43,0.14); }

/* ── Medidor de certeza (alta/média/baixa) ─────────────── */
.v2-certeza { display: inline-flex; align-items: center; gap: 8px; }
.v2-certeza .barras { display: inline-flex; gap: 3px; align-items: flex-end; }
.v2-certeza .barras i {
  width: 5px; border-radius: 2px;
  background: var(--line-strong);
  transition: background 200ms;
}
.v2-certeza .barras i:nth-child(1) { height: 7px; }
.v2-certeza .barras i:nth-child(2) { height: 11px; }
.v2-certeza .barras i:nth-child(3) { height: 15px; }
.v2-certeza.alta  .barras i { background: var(--ok); }
.v2-certeza.media .barras i:nth-child(-n+2) { background: var(--alerta); }
.v2-certeza.baixa .barras i:nth-child(1) { background: var(--erro); }
.v2-certeza .rotulo { font-size: var(--fs-rotulo); font-weight: 600; }
.v2-certeza.alta  .rotulo { color: var(--ok); }
.v2-certeza.media .rotulo { color: var(--alerta); }
.v2-certeza.baixa .rotulo { color: var(--erro); }

/* ── Mock de conversa WhatsApp (kit completo) ──────────── */
.wa-phone {
  border-radius: 18px;
  overflow: hidden;
  box-shadow: 0 8px 28px rgba(19,32,26,0.18), 0 2px 6px rgba(19,32,26,0.10);
  border: 1px solid rgba(19,32,26,0.08);
  background: #efe7dd;
  display: flex;
  flex-direction: column;
}
.wa-header {
  background: #008069;
  color: #fff;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
}
.wa-avatar {
  width: 34px; height: 34px;
  border-radius: 50%;
  background: #0c2f23;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-sub);
  flex: 0 0 34px;
}
.wa-header .wa-nome { font-weight: 600; font-size: var(--fs-medio); line-height: 1.15; }
.wa-header .wa-status { font-size: var(--fs-mini); opacity: .85; }
.wa-body {
  flex: 1;
  padding: 14px 12px 16px;
  background:
    radial-gradient(circle at 20% 30%, rgba(0,0,0,0.018) 0 2px, transparent 2px),
    radial-gradient(circle at 70% 60%, rgba(0,0,0,0.018) 0 2px, transparent 2px),
    #efe7dd;
  background-size: 90px 90px, 110px 110px, auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.wa-dia {
  align-self: center;
  background: #fff;
  color: #54656f;
  font-size: var(--fs-mini);
  font-weight: 500;
  padding: 4px 12px;
  border-radius: 8px;
  box-shadow: 0 1px 1px rgba(0,0,0,0.08);
}
.wa-sys {
  align-self: center;
  text-align: center;
  font-size: var(--fs-rotulo);
  font-weight: 500;
  padding: 7px 14px;
  border-radius: 10px;
  box-shadow: 0 1px 1px rgba(0,0,0,0.08);
  max-width: 92%;
  line-height: 1.4;
  background: #fdf3cf;
  color: #5c4a12;
}
.wa-sys.verde    { background: #d5f5e5; color: #0b5c3f; }
.wa-sys.vermelho { background: #fde2de; color: #8a2317; }
.wa-sys.ambar    { background: #fdeccf; color: #7a4408; }
.wa-msg {
  position: relative;
  max-width: 82%;
  border-radius: 10px;
  padding: 7px 9px 8px;
  font-size: var(--fs-medio);
  line-height: 1.42;
  color: #111b21;
  box-shadow: 0 1px 1px rgba(0,0,0,0.10);
  white-space: pre-wrap;
  word-break: break-word;
  animation: v2-subir 260ms ease-out both;
}
.wa-msg .wa-meta {
  float: right;
  margin: 6px -2px -4px 8px;
  font-size: var(--fs-micro);
  color: #8696a0;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  user-select: none;
}
.wa-msg.bot {
  align-self: flex-start;
  background: #ffffff;
  border-top-left-radius: 2px;
}
.wa-msg.bot::before {
  content: '';
  position: absolute;
  left: -7px; top: 0;
  border: 7px solid transparent;
  border-top-color: #ffffff;
  border-right-color: #ffffff;
  border-left-width: 0;
}
.wa-msg.paciente {
  align-self: flex-end;
  background: #d9fdd3;
  border-top-right-radius: 2px;
}
.wa-msg.paciente::before {
  content: '';
  position: absolute;
  right: -7px; top: 0;
  border: 7px solid transparent;
  border-top-color: #d9fdd3;
  border-left-color: #d9fdd3;
  border-right-width: 0;
}
.wa-check { color: #53bdeb; font-size: var(--fs-mini); letter-spacing: -2px; }
.wa-digitando {
  align-self: flex-start;
  background: #ffffff;
  border-radius: 10px;
  border-top-left-radius: 2px;
  padding: 11px 14px;
  box-shadow: 0 1px 1px rgba(0,0,0,0.10);
  display: inline-flex;
  gap: 4px;
  animation: v2-subir 200ms ease-out both;
}
.wa-digitando i {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: #9aa7af;
  animation: v2-pulso 1s ease-in-out infinite;
}
.wa-digitando i:nth-child(2) { animation-delay: .18s; }
.wa-digitando i:nth-child(3) { animation-delay: .36s; }

/* compat: classes antigas simples ainda usáveis */
.wa-fundo {
  background: #efe7dd;
  border-radius: var(--r-lg);
  padding: 16px 14px;
}
.wa-bolha {
  background: #ffffff;
  border-radius: 10px;
  border-top-left-radius: 2px;
  box-shadow: 0 1px 1px rgba(0,0,0,0.12);
  padding: 9px 12px;
  max-width: 560px;
  font-size: var(--fs-medio);
  line-height: 1.45;
  color: #111b21;
  white-space: pre-wrap;
  word-break: break-word;
}
.wa-bolha + .wa-bolha { margin-top: 8px; }
.wa-hora {
  display: block;
  text-align: right;
  font-size: var(--fs-micro);
  color: #8696a0;
  margin-top: 3px;
}

/* ── Faixa informativa leiga ("o que esta tela faz") ───── */
.info-strip {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  background: var(--gold-soft);
  border: 1px solid rgba(199,154,60,0.38);
  border-radius: var(--r);
  padding: 12px 16px;
  font-size: var(--fs-corpo);
  color: var(--ink-2);
}
.info-strip svg { flex: 0 0 18px; margin-top: 1px; color: var(--gold); }

/* ── Controle segmentado (alternar modos) ──────────────── */
.v2-seg {
  display: inline-flex;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 3px;
  gap: 2px;
}
.v2-seg button {
  border: 0;
  background: transparent;
  border-radius: 999px;
  padding: 7px 16px;
  font: 500 13px var(--font-sans);
  color: var(--ink-3);
  transition: background 150ms, color 150ms, box-shadow 150ms;
}
.v2-seg button.ativo {
  background: var(--surface);
  color: var(--ink);
  box-shadow: 0 1px 3px rgba(19,32,26,0.12);
}
.v2-seg button:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* ── Acessibilidade: foco e movimento reduzido ─────────── */
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--focus-ring);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}


/* ────────────────────────────────────────────────────────
   15. V2 — MICRO-FEEDBACK (Jun/2026)
   Entradas escalonadas, flash de atualização, status ao vivo,
   estados vazios e carregamento.
   ──────────────────────────────────────────────────────── */

/* Entrada escalonada pra grades/listas/tabelas */
/* (impeccable/product: sem sequência orquestrada de carregamento —
   um fade único e rápido; o usuário entra na tarefa, não no show) */
.v2-stagger > * { animation: v2-subir .16s ease-out both; }

/* Flash verde quando um valor/linha acabou de atualizar */
@keyframes v2-blink {
  0%   { background-color: rgba(95,217,168,0.40); }
  100% { background-color: transparent; }
}
.v2-atualizou { animation: v2-blink 900ms ease-out; border-radius: 6px; }

/* Selo "ao vivo" (dashboards) */
.v2-live {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-mini); font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--accent-strong);
  background: var(--accent-soft);
  border-radius: 999px;
  padding: 4px 12px;
}
.v2-live i {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 7px rgba(14,138,95,.8);
  animation: v2-pulso 1.6s ease-in-out infinite;
}
/* variante pausada (âmbar, ponto parado) — única spec de "ao vivo" do painel */
.v2-live.pausado {
  color: var(--alerta);
  background: var(--alerta-soft);
}
.v2-live.pausado i {
  background: var(--alerta);
  box-shadow: none;
  animation: none;
}

/* Estado vazio amigável */
.v2-vazio-box {
  text-align: center;
  padding: 34px 18px;
  color: var(--ink-3);
  font-size: var(--fs-medio);
}
.v2-vazio-box svg { width: 34px; height: 34px; color: var(--line-strong); margin-bottom: 8px; }

/* Hub/ferramentas: seta que desliza no hover */
.ferramenta-card { position: relative; overflow: hidden; }
.ferramenta-card::after {
  content: '→';
  position: absolute;
  right: 18px; bottom: 14px;
  font-size: var(--fs-head);
  color: var(--accent);
  opacity: 0;
  transform: translateX(-8px);
  transition: opacity .2s, transform .2s;
}
.ferramenta-card:hover::after { opacity: 1; transform: translateX(0); }

/* Modais: entrada suave (páginas que usam .modal-overlay/.modal) */
.modal-overlay { animation: v2-fade .18s ease-out both; }
.modal { animation: v2-pop .22s ease-out both; }
@keyframes v2-fade { from { opacity: 0; } to { opacity: 1; } }

/* Linhas de tabela: hover sutil universal */
.tabela tbody tr, .regras-tabela tbody tr, .lote-tab tbody tr {
  transition: background 120ms;
}
.tabela tbody tr:hover { background: var(--bg); }


/* ────────────────────────────────────────────────────────
   16. TELA PADRÃO (Jun/2026)
   Spec ÚNICA de header de tela: voltar, título, subtítulo,
   nota explicativa e espaçamentos. As classes antigas
   (.breadcrumb-link, .subtela-titulo, .info-card) são
   ALIASES desta spec — páginas legadas herdam o visual novo
   sem precisar de mudança de markup.

   Markup canônico:
     <a class="voltar-global" href="...">
       <svg ...><path d="M15 18l-6-6 6-6"/></svg> Voltar
     </a>
     <div class="topo-tela">
       <h1 class="titulo-tela">Nome da tela</h1>
       [elemento opcional à direita]
     </div>
     <p class="subtitulo-tela">Uma linha do que a tela faz.</p>
     <div class="nota-card">…</div>   (opcional)
   ──────────────────────────────────────────────────────── */

/* ── Voltar (uma spec; .breadcrumb-link é alias) ───────── */
.voltar-global,
.breadcrumb-link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--font-sans);
  font-size: var(--fs-corpo);
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-3);
  text-decoration: none;
  margin-bottom: 14px;
  transition: color 150ms;
}
.voltar-global svg,
.breadcrumb-link svg {
  width: 14px;
  height: 14px;
  transition: transform 150ms;
}
.voltar-global:hover,
.breadcrumb-link:hover {
  color: var(--accent-strong);
  text-decoration: none;
}
.voltar-global:hover svg,
.breadcrumb-link:hover svg {
  transform: translateX(-2px);
}
.voltar-global:focus-visible,
.breadcrumb-link:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--r-sm);
}
/* wrapper legado <nav class="breadcrumb"> não soma margem extra */
.breadcrumb { margin-bottom: 0; }
.subtela-header { margin-bottom: var(--gap-lg); }

/* ── Linha do título (título + elemento à direita) ────── */
.topo-tela {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--gap);
  flex-wrap: wrap;
  margin-bottom: 6px;
}

/* ── Título de tela (uma spec; .subtela-titulo é alias) ── */
.titulo-tela,
.subtela-titulo {
  font-family: var(--font-display);
  font-size: var(--fs-display);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
  color: var(--ink);
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: var(--gap-sm);
  flex-wrap: wrap;
}
@media (min-width: 768px) {
  .titulo-tela,
  .subtela-titulo { font-size: var(--fs-num); }
}

/* ── Subtítulo (uma linha, leigo) ──────────────────────── */
.subtitulo-tela,
.subtitulo {
  color: var(--ink-2);
  font-size: var(--fs-medio);
  line-height: 1.5;
  margin: 0 0 18px 0;
}

/* ── Nota explicativa (.info-card legado é alias) ──────── */
.nota-card,
.info-card {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  background: var(--info-soft);
  border: 1px solid rgba(29,111,184,0.32);
  border-radius: var(--r);
  padding: 13px 16px;
  margin-bottom: 24px;
  font-size: var(--fs-corpo);
  color: var(--ink-2);
  line-height: 1.5;
}
.nota-card svg,
.info-card svg { flex: 0 0 18px; width: 18px; height: 18px; margin-top: 1px; color: var(--info); }
.nota-card strong,
.info-card strong,
.nota-card .info-card-corpo strong,
.info-card .info-card-corpo strong { color: var(--ink); }
.info-card-corpo { font-size: var(--fs-corpo); color: var(--ink-2); line-height: 1.5; }

/* ── Cabeçalho de seção dentro da tela ─────────────────── */
.secao-rotulo {
  font-size: var(--fs-corpo);
  font-weight: 700;
  color: var(--ink);
  margin: 28px 0 4px;
}
.secao-rotulo:first-of-type { margin-top: 0; }
.secao-rotulo-desc {
  font-size: var(--fs-corpo);
  color: var(--ink-3);
  margin: 0 0 14px;
  line-height: 1.5;
}

/* ── Resumo da tela (mini stat-cards sob o header) ─────── */
.tela-stats {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 20px;
}
.tela-stat {
  flex: 1 1 130px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 10px 14px;
  min-width: 0;
}
.tela-stat .num {
  font-family: var(--font-dados);
  font-size: var(--fs-display-sm);
  font-weight: 600;
  color: var(--ink);
  line-height: 1.15;
}
.tela-stat .lbl {
  font-size: var(--fs-mini);
  color: var(--ink-3);
  margin-top: 2px;
}
.tela-stat.ok .num     { color: var(--ok); }
.tela-stat.erro .num   { color: var(--erro); }
.tela-stat.alerta .num { color: var(--alerta); }
.tela-stat.acao {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  background: transparent;
  border: none;
  padding: 0;
}

/* ────────────────────────────────────────────────────────
   17. VV-COMBO (Jun/2026)
   Dropdown de catálogo (vv-combo.js). Substitui datalist e
   select nativos em listas longas (médicos, convênios,
   especialidades). O painel é anexado ao <body>.
   ──────────────────────────────────────────────────────── */
/* (s121 — régua "a caixa curva não rola", seção 27) o painel é a CAIXA:
   tem o canto curvo e CLIPA. Quem rola é o `.vv-combo-rolo`, e é ele
   que carrega o `rola-miolo`. */
.vv-combo-painel {
  position: absolute;
  z-index: 300;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  /* (s123) o MESMO raio do campo-pílula: é a paridade de forma que ele
     pediu. A largura exata vem do `posicionar()` do vv-combo.js. */
  border-radius: 19px;
  box-shadow: var(--shadow-strong);
  overflow: hidden;
  animation: v2-pop 140ms ease-out both;
}
.vv-combo-rolo { max-height: 280px; padding: 6px; }
.vv-combo-item {
  padding: 8px 12px;
  border-radius: var(--r-sm);
  font-size: var(--fs-medio);
  color: var(--ink-2);
  cursor: pointer;
  line-height: 1.35;
}
.vv-combo-item b {
  color: var(--accent-strong);
  font-weight: 700;
}
.vv-combo-item:hover,
.vv-combo-item.sel {
  background: var(--accent-soft);
  color: var(--ink);
}
.vv-combo-grupo {
  font-size: var(--fs-mini);
  font-weight: 700;
  color: var(--ink-3);
  padding: 8px 12px 4px;
}
.vv-combo-grupo:not(:first-child) {
  border-top: 1px solid var(--line);
  margin-top: 4px;
}
.vv-combo-vazio,
.vv-combo-mais {
  padding: 9px 12px;
  font-size: var(--fs-rotulo);
  color: var(--ink-3);
}
.vv-combo-mais {
  border-top: 1px solid var(--line);
  margin-top: 4px;
  font-family: var(--font-dados);
  font-size: var(--fs-mini);
  letter-spacing: 0.04em;
}


/* ────────────────────────────────────────────────────────
   18. VV-UI (Jun/2026)
   Toast e confirmação da marca (vv-ui.js). Substituem
   alert()/confirm() nativos e os toasts copiados por página.
   ──────────────────────────────────────────────────────── */
/* ⛔⛔ (s205c — ele: "tem pontos em que mais vale box de aviso, do que algo
   que some facilmente com essas pills infernais") A FAIXA É O AVISO QUE
   FICA. A pílula conta o que acabou de acontecer e some em 2,4s; a faixa
   é ESTADO — ela vive enquanto o problema existe, ao lado do problema.
   ⛔ Não é peça nova por capricho: a `.agp-bloqfaixa` (a única faixa VIVA
   do painel, s204b) passa a herdar daqui e fica só com o que é dela. Os
   valores abaixo são os DELA, para que nada mude de aparência. */
.vv-faixa { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 8px 12px; border-radius: 9px; background: var(--surface-2);
  border: 1px solid var(--line); font-size: var(--fs-corpo);
  color: var(--ink-2); }
.vv-faixa b { color: var(--ink); }
.vv-faixa span { color: var(--ink-3); }
.vv-faixa svg { flex: none; }
.vv-faixa.alerta { background: var(--alerta-soft); border-color: transparent;
  color: var(--alerta); }
.vv-faixa.alerta b { color: var(--alerta); }
.vv-faixa.erro { background: var(--erro-soft); border-color: transparent;
  color: var(--erro); }
.vv-faixa.erro b { color: var(--erro); }

/* ⛔ (s205c) O CAMPO EM ALERTA. Medido antes de escrever: o painel não
   tinha NENHUM estado de campo inválido — zero `aria-invalid`, zero
   classe de erro em campo. A única maneira de dizer "este campo está
   errado" era uma pílula que some. A marca vai no `.m3-campo`, que é a
   peça de campo do painel inteiro (Cadastros, Financeiro e agenda). */
.m3-campo.alerta > label { color: var(--alerta); }
/* ⚠️ O `!important` NÃO é força bruta: é PARIDADE. A box cheia
   (`.vv-combo-caixa > input.cheio`, logo acima) já usa `!important`
   porque o `vvCombo` escreve o verde no style INLINE do campo, e inline
   ganha de classe. Sem o mesmo peso, o alerta nunca apareceria num campo
   preenchido — que é exatamente o caso (o convênio está escolhido). */
/* ⛔ (s266v) O CAMPO DE GRADE COM FORMATO TORTO (a célula da tabela não tem
   `.m3-campo` pra levar o `.falta`): a mesma cor do vermelho da casa. Quem
   pinta é o `vv-ui.js`, e só nas páginas que pedem (`VV_CLASSE_TORTO`). */
input.vv-torto {
  border-color: var(--erro) !important;
  background-color: var(--erro-soft) !important; }
.m3-campo.alerta > input,
.m3-campo.alerta input.combo,
.m3-campo.alerta .vv-combo-caixa > input.cheio {
  border-color: var(--alerta) !important;
  color: var(--alerta) !important;
  background-color: var(--alerta-soft) !important; }

/* (s241) o toast novo — cartão da casa, ícone do tipo, entra de baixo com
   desaceleração e sai rápido. A pele mora aqui; quem monta é o vv-ui.js. */
.vv-toast {
  position: fixed;
  bottom: 22px;
  left: 50%;
  transform: translate(-50%, 14px) scale(.97);
  display: flex; align-items: center; gap: 10px;
  padding: 9px 14px 9px 10px;
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 12px;
  font-size: var(--fs-corpo, 13px);
  font-weight: 500;
  line-height: 20px;
  box-shadow: 0 12px 32px rgba(12,47,35,.16), 0 1px 2px rgba(12,47,35,.06);
  opacity: 0;
  transition: opacity .18s ease, transform .22s ease-in;
  pointer-events: none;
  z-index: 1000;
  max-width: calc(100vw - 32px);
}
.vv-toast.mostra { opacity: 1; transform: translate(-50%, 0) scale(1); transition: opacity .22s ease-out, transform .38s cubic-bezier(.22,1,.36,1); pointer-events: auto; }
.vv-toast .txt { white-space: nowrap; line-height: 20px; }
.vv-toast .ico { width: 22px; height: 22px; border-radius: 7px; display: grid; place-items: center; flex: none; background: var(--surface-2); color: var(--ink-2); }
.vv-toast .ico svg { display: block; }
.vv-toast.ok .ico { background: var(--accent-soft); color: var(--accent-strong); }
.vv-toast.erro .ico { background: rgba(192,57,43,.10); color: var(--erro); }
.vv-toast .acao { margin-left: 4px; border: 0; background: transparent; color: var(--accent-strong); font: 650 var(--fs-corpo, 13px)/20px inherit; font-family: inherit; padding: 3px 10px; border-radius: 8px; cursor: pointer; }
.vv-toast .acao:hover { background: var(--accent-soft); }
.vv-toast .x { border: 0; background: transparent; color: var(--ink-3); width: 24px; height: 24px; line-height: 0; border-radius: 7px; display: grid; place-items: center; cursor: pointer; margin: 0 -4px 0 0; }
.vv-toast .x:hover { background: var(--surface-2); color: var(--ink); }
@media (prefers-reduced-motion: reduce) { .vv-toast, .vv-toast.mostra { transition: opacity .15s; transform: translate(-50%, 0); } }
/* (s244z — ele) a cobrinha: um filete verde neon andando no contorno do toast, velocidade constante */
.vv-toast .cobra { position: absolute; inset: -1px; width: calc(100% + 2px); height: calc(100% + 2px); pointer-events: none; overflow: visible; border-radius: 12px; }
.vv-toast .cobra rect { x: .75px; y: .75px; width: calc(100% - 1.5px); height: calc(100% - 1.5px); rx: 12px; ry: 12px; fill: none;
  stroke: #39ff14; stroke-width: 1.5; stroke-linecap: round; stroke-dasharray: 14 86; stroke-dashoffset: 0;
  filter: drop-shadow(0 0 2.5px rgba(57,255,20,.75)); animation: vv-cobra 2.6s linear infinite; }
.vv-toast:hover .cobra rect { animation-play-state: paused; }
@keyframes vv-cobra { to { stroke-dashoffset: -100; } }
@media (prefers-reduced-motion: reduce) { .vv-toast .cobra { display: none; } }
/* (s265h — ele, opção 2 do protótipo) no painel NOVO o toast é o verde-escuro da
   barra lateral (--deep): no painel quase todo branco o cartão branco sumia em
   cima do campo de digitar. O tipo vai no ícone cheio; a cobrinha fica. A classe
   quem põe é o vv-ui.js (só no painel novo). */
.vv-toast.painel-novo { background: var(--deep, #0c2f23); color: #fff; border-color: var(--deep, #0c2f23);
  box-shadow: 0 12px 32px rgba(12,47,35,.28), 0 1px 2px rgba(12,47,35,.1); }
.vv-toast.painel-novo .ico { background: rgba(255,255,255,.14); color: #fff; border-radius: 50%; }
.vv-toast.painel-novo.ok .ico { background: var(--accent); color: #fff; }
.vv-toast.painel-novo.erro .ico { background: var(--erro); color: #fff; }
.vv-toast.painel-novo .acao { color: #7ee2b0; }
.vv-toast.painel-novo .acao:hover { background: rgba(255,255,255,.1); }
.vv-toast.painel-novo .x { color: rgba(255,255,255,.7); }
.vv-toast.painel-novo .x:hover { background: rgba(255,255,255,.1); color: #fff; }

.vv-conf-overlay {
  position: fixed;
  inset: 0;
  background: rgba(12, 47, 35, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  z-index: 900;
  animation: v2-fade .15s ease-out both;
}
.vv-conf {
  background: var(--surface);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-strong);
  padding: 22px;
  width: 100%;
  max-width: 420px;
  animation: v2-pop .18s ease-out both;
}
.vv-conf-titulo {
  font-family: var(--font-display);
  font-size: var(--fs-head);
  font-weight: 700;
  color: var(--ink);
  margin: 0 0 6px;
}
.vv-conf-texto {
  font-size: var(--fs-medio);
  color: var(--ink-2);
  line-height: 1.55;
  margin: 0 0 18px;
}
.vv-conf-aviso {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  background: var(--alerta-soft);
  border: 1px solid rgba(180,83,9,0.35);
  border-radius: var(--r-sm);
  padding: 10px 12px;
  font-size: var(--fs-corpo);
  color: var(--ink-2);
  line-height: 1.5;
  margin: 0 0 18px;
}
.vv-conf-aviso svg { flex: 0 0 16px; margin-top: 1px; color: var(--alerta); }
.vv-conf-acoes {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
}
.vv-conf .btn-confirmar-perigo {
  background: var(--erro);
  color: #fff;
  border: 0;
  padding: 10px 20px;
  border-radius: var(--r);
  font: 600 14px var(--font-sans);
  cursor: pointer;
}
.vv-conf .btn-confirmar-perigo:hover { filter: brightness(0.94); }


.btn-primary .pendente-dot {
  display: none;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: #ffd66e;
  box-shadow: 0 0 6px rgba(255,214,110,.9);
  margin-left: 8px;
}
.btn-primary.pendente .pendente-dot { display: inline-block; }


/* ────────────────────────────────────────────────────────
   19. MOBILE (Jun/2026)
   Utilitários do passe de portabilidade. Tabelas de edição
   (retornos, preços, idades) NÃO cabem espremidas em 380px —
   rolam na horizontal preservando os inputs utilizáveis.
   ──────────────────────────────────────────────────────── */
.tabela-rolavel {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.tabela-rolavel > table {
  width: 100%;
}
@media (max-width: 640px) {
  .tabela-rolavel > table {
    /* min-width por página via style no <table>; default seguro: */
    min-width: 560px;
  }
  /* dica visual de que rola */
  .tabela-rolavel {
    background:
      linear-gradient(90deg, var(--surface) 30%, transparent),
      linear-gradient(270deg, var(--surface) 30%, transparent) 100% 0,
      radial-gradient(farthest-side at 0 50%, rgba(19,32,26,.12), transparent),
      radial-gradient(farthest-side at 100% 50%, rgba(19,32,26,.12), transparent) 100% 0;
    background-repeat: no-repeat;
    background-size: 40px 100%, 40px 100%, 14px 100%, 14px 100%;
    background-attachment: local, local, scroll, scroll;
  }
}

/* ────────────────────────────────────────────────────────
   20. S15 — ELEVAÇÃO VISUAL (Jul/2026)
   Polimento de apresentação: login com fundo de marca,
   chips de variação nos cartões, faixa de insight, detalhes
   de acabamento (scrollbar, seleção, estados vazios).
   ──────────────────────────────────────────────────────── */

/* ── Login: fundo de marca (primeira tela que o visitante vê) ── */
.login-body {
  background:
    radial-gradient(900px 480px at 15% -10%, rgba(17,153,106,0.32), transparent 60%),
    radial-gradient(760px 420px at 92% 108%, rgba(199,154,60,0.18), transparent 55%),
    linear-gradient(160deg, #0e3a2b 0%, #0c2f23 55%, #0a291c 100%);
  background-color: #0c2f23;
}
.login-card {
  border: 1px solid rgba(255,255,255,0.55);
  box-shadow: 0 8px 24px rgba(4,20,14,0.35), 0 28px 80px rgba(4,20,14,0.45);
}
.login-rodape-nota {
  text-align: center;
  margin-top: 18px;
  font-size: var(--fs-rotulo);
  color: rgba(255,255,255,0.55);
}

/* ── Seleção de texto e scrollbar da marca ────────────── */
::selection { background: rgba(14,138,95,0.22); }

/* ── A ROLAGEM (s120 — pedido do dono: "tem algum jeito de demonstrar
   que tem scroll pra baixo sem ficar tão poluído? quebra e polui
   design desse jeito... não só aqui, no CRM inteiro daí")

   Duas peças, e a distinção importa porque a casa já reprovou uma
   scrollbar custom antes ("afordância reinventada — nativa de volta"):

   1. A BARRA CONTINUA NATIVA. Ninguém desenhou barra nova, ninguém
      escondeu rolagem atrás de JS: arrastar, clicar na calha, roda do
      mouse, teclado e a barra do sistema no mobile seguem iguais. O que
      sai é só a TINTA da calha — aquele corredor cinza de 15px que
      encostava no conteúdo e cortava a tela em duas. A afordância fica;
      o ruído sai.
   2. A DICA DE FIM (`.rola-dica`) é o que RESPONDE a pergunta dele —
      "tem mais coisa embaixo?". Sombra suave na borda que aparece só
      quando há mais conteúdo e some sozinha ao chegar no fim. Zero JS,
      zero listener de scroll: é o MESMO mecanismo que a `.tabela-rolavel`
      já usa na horizontal desde o passe de mobile (gradiente preso ao
      conteúdo com `background-attachment: local` + gradiente preso ao
      quadro com `scroll`; um cobre o outro enquanto dá pra rolar).
      Régua s86 — existe X na casa, não se cria Y.
   ────────────────────────────────────────────────────── */
/* ⛔⛔ (s124 — item 9, a 4ª vez que ele pede: "flechas pra cima e pra
   baixo cortadas, está muito colado na beirada")
   A CAUSA NÃO ERA A LISTA DE SELETORES — ERA ESTE BLOCO INTEIRO ESTAR
   MORTO. Quando `scrollbar-width` (a propriedade PADRÃO) está declarada,
   o Chrome DESCARTA todos os `::-webkit-scrollbar-*`. Como o `*` acima
   declarava `scrollbar-width: thin`, a casa desenhava a barra no vazio
   desde sempre: o que aparecia na tela dele era a barra NATIVA do
   Windows — com as setinhas ▲▼ nas pontas, que a curva do quadro corta.
   Medido no Chromium com barra clássica (xvfb): só-::-webkit = 13px ·
   só-padrão = 12px · OS DOIS (o CSS de ontem) = 12px, ou seja IGUAL a
   não ter escrito uma linha de ::-webkit. Por isso a s123 mediu
   `getComputedStyle` da folga, viu 12px e passou verde — a variável
   existia, a barra é que não a lia.
   Hoje o `scrollbar-width` fica atrás de um @supports que só o Firefox
   entra (ele não tem ::-webkit-scrollbar), e o Chrome volta a obedecer
   o bloco. As três coisas que ele pediu viram REGRA GLOBAL, não lista:
     · `-button` sumindo  → acabam as setinhas cortadas;
     · `-track { margin }` → a calha começa depois da curva;
     · borda transparente maior → o polegar descola da beirada.       */
@supports not selector(::-webkit-scrollbar) {
  * {                                                 /* Firefox só */
    scrollbar-width: thin;
    scrollbar-color: rgba(19,32,26,.22) transparent;
  }
}
::-webkit-scrollbar { width: var(--rola-largura); height: var(--rola-largura); }
/* as SETINHAS: a barra nativa põe ▲▼ nas pontas e a curva do quadro
   corta as duas. Some com elas em toda a casa — a rolagem é por
   arrasto/roda, ninguém clica nelas. */
::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
::-webkit-scrollbar-track,
::-webkit-scrollbar-corner { background: transparent; }
/* a calha RECUA nas pontas: o polegar nasce depois da curva e morre
   antes dela. Vale pra QUALQUER área que role (era lista de 4 nomes na
   s123, e a área da foto dele não estava na lista). Quadro de raio
   maior sobrescreve `--rola-folga`; quem não tem curva zera. */
::-webkit-scrollbar-track:vertical   { margin: var(--rola-folga) 0; }
::-webkit-scrollbar-track:horizontal { margin: 0 var(--rola-folga); }
/* a janela inteira não tem canto curvo — ali a calha vai de ponta a ponta */
html::-webkit-scrollbar-track, body::-webkit-scrollbar-track { margin: 0; }
::-webkit-scrollbar-thumb {
  /* a borda transparente + background-clip afina o POLEGAR sem afinar a
     ÁREA DE CLIQUE: pegar a barra continua fácil pra quem tem mão pesada.
     (s124) o recuo subiu de 3px pra `--rola-recuo` — era ele o "colado
     na beirada": com 11px de barra e 3px de borda sobravam 3px até o
     limite do quadro. */
  background: rgba(19,32,26,.18);
  background-clip: content-box;
  border: var(--rola-recuo) solid transparent;
  border-radius: 99px;
}
::-webkit-scrollbar-thumb:hover { background: rgba(19,32,26,.34); background-clip: content-box; }
::-webkit-scrollbar-thumb:active { background: rgba(19,32,26,.44); background-clip: content-box; }

/* A dica de fim. Vai no elemento QUE ROLA. `--rola-fundo` é a cor do
   fundo dele (o gradiente precisa "apagar" a sombra na ponta certa) —
   default `--surface`, sobrescrever quando o fundo for outro. */
/* ⚠️ lista de seletores, NÃO cópias da regra: quem rola no CRM entra
   AQUI e herda o mecanismo. Nove janelas usam `.jan-corpo-simples` e a
   décima vai nascer amanhã — se a dica morasse na marcação, a janela
   nova nasceria sem ela e ninguém perceberia (s62). */
/* ⛔ (s123 — o dono, com o print e a paciência no fim: "SÓ TEM QUE
   AJEITAR A [BARRA] DO SCROLL QUE ESTA FICANDO CORTADA, JA PEDI ALGUMAS
   VEZES") Quem rola é o MIOLO, um retângulo; quem tem a curva é o
   QUADRO, que clipa. A barra corre a altura inteira do miolo, então as
   PONTAS dela entram na curva e saem cortadas retas.
   `--rola-folga` recua a CALHA (não o conteúdo, não a barra): o polegar
   nasce depois da curva e morre antes dela. Quadro com raio maior
   sobrescreve a variável; quem não tem curva pode zerar.               */
.rola-dica,
.dock-lista,
.jan-corpo-simples,
.rola-miolo {
  --rola-fundo: var(--surface);
  background:
    linear-gradient(var(--rola-fundo) 32%, rgba(255,255,255,0)),
    linear-gradient(rgba(255,255,255,0), var(--rola-fundo) 68%) 0 100%,
    radial-gradient(farthest-side at 50% 0,   rgba(19,32,26,.13), rgba(19,32,26,0)),
    radial-gradient(farthest-side at 50% 100%, rgba(19,32,26,.13), rgba(19,32,26,0)) 0 100%;
  background-repeat: no-repeat;
  background-size: 100% 30px, 100% 30px, 100% 11px, 100% 11px;
  background-attachment: local, local, scroll, scroll;
}
/* Toque não tem hover e a barra vive escondida: lá a dica é a única
   pista de que há mais coisa. Reforça. */
@media (hover: none) {
  .rola-dica { background-size: 100% 34px, 100% 34px, 100% 14px, 100% 14px; }
}

/* ── Chip de variação (vs ontem) nos cartões de número ── */


/* ── Faixa de insight (raio-x do dia no painel) ───────── */
.insight-strip {
  display: flex;
  align-items: center;
  gap: 12px;
  background: linear-gradient(135deg, rgba(14,138,95,0.08), rgba(17,153,106,0.04));
  border: 1px solid rgba(14,138,95,0.22);
  border-radius: var(--r);
  padding: 12px 16px;
  margin-bottom: var(--gap-lg);
  font-size: var(--fs-medio);
  color: var(--ink-2);
}
.insight-strip b { color: var(--accent-strong); }
.insight-strip svg { flex: 0 0 20px; width: 20px; height: 20px; color: var(--accent); }

/* ── Ação secundária ao lado do título (ex.: apagar tudo) ── */
.titulo-acao-perigo {
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink-3);
  font-size: var(--fs-rotulo);
  font-weight: 500;
  padding: 6px 14px;
  min-height: 32px;
  transition: color 150ms, border-color 150ms, background 150ms;
}
.titulo-acao-perigo:hover {
  color: var(--erro);
  border-color: rgba(192,57,43,0.4);
  background: var(--erro-soft);
}

/* ── Estado vazio de gráfico com ícone ────────────────── */
.grafico-vazio {
  flex-direction: column;
  gap: 8px;
}
.grafico-vazio svg {
  width: 30px;
  height: 30px;
  color: var(--line-strong);
}

/* ── Tabelas: números tabulares nos dados ─────────────── */
.tabela td.tabela-mono, .tela-stat .num { font-variant-numeric: tabular-nums; }

/* ── Cartão clicável: leve realce de borda com a marca ── */
.numero-card:hover { border-color: rgba(14,138,95,0.35); }
.subtela-card:hover { border-color: rgba(14,138,95,0.35); }

/* ────────────────────────────────────────────────────────
   21. S15b — CASCO EXECUTIVO (moldura escura + navegação)
   Sidebar fixa à esquerda (desktop) formando um "L" com o
   topbar: o conteúdo claro fica emoldurado pela marca.
   Mobile (<1024px): sidebar some, topbar volta ao normal.
   ──────────────────────────────────────────────────────── */

.app-shell { display: flex; min-height: 100vh; align-items: stretch; }
.app-main  { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.app-main > .page-shell { width: 100%; }

.sidenav { display: none; }
.topbar-trilha { display: none; }

@media (min-width: 1024px) {
  .sidenav {
    display: flex;
    flex-direction: column;
    width: 228px;
    flex: 0 0 228px;
    background: #0c2f23;
    position: sticky;
    top: 0;
    height: 100vh;
    padding: 18px 12px 14px;
    overflow-y: auto;
    z-index: 11;
  }
  /* brand mora na sidebar — some do topbar (a pílula de IA fica) */
  .app-shell .topbar .brand-chip,
  .app-shell .topbar .brand-name { display: none; }
  .app-shell .topbar .ia-pill { margin-left: 0; }
  .topbar-trilha {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: var(--fs-rotulo);
    font-weight: 600;
    color: rgba(255,255,255,0.55);
    margin-right: auto;
    padding-left: 2px;
    white-space: nowrap;
  }
  .topbar-trilha b {
    color: rgba(255,255,255,0.92);
    font-weight: 600;
  }
  .topbar-trilha i {
    font-style: normal;
    color: rgba(255,255,255,0.3);
  }
}

.sidenav-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 10px 14px;
  margin-bottom: 6px;
}
.sidenav-brand img {
  width: 30px; height: 30px;
  padding: 4px;
  background: #fff;
  border-radius: 9px;
  box-shadow: 0 1px 4px rgba(0,0,0,0.25);
}
.sidenav-brand .nome {
  font-family: var(--font-display);
  font-size: var(--fs-sub);
  font-weight: 600;
  color: #fff;
  letter-spacing: -0.01em;
}
.sidenav-brand .nome span { color: #5fd9a8; }

.sidenav-grupo { margin-top: 18px; }

.sidenav a {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: 9px;
  color: rgba(255,255,255,0.74);
  font-size: var(--fs-medio);
  font-weight: 500;
  line-height: 1.2;
  text-decoration: none;
  margin-bottom: 2px;
  transition: background 130ms, color 130ms;
}
.sidenav a svg { width: 17px; height: 17px; flex: 0 0 17px; opacity: 0.9; }
.sidenav a:hover {
  background: rgba(255,255,255,0.07);
  color: #fff;
  text-decoration: none;
}
.sidenav a.ativo {
  background: rgba(46,230,168,0.13);
  color: #fff;
  box-shadow: inset 3px 0 0 #2ee6a8;
}


/* ────────────────────────────────────────────────────────
   22. S15b — GEOMETRIA (grade rígida, caixas definidas)
   Mesma linha, mesma coluna: KPI com altura única, ícones
   em chip de tamanho único, cabeçalho de página com ritmo
   fixo, nada extrapolando a caixa.
   ──────────────────────────────────────────────────────── */

/* Caixa bem desenhada: limite explícito em todo cartão */
.card, .numero-card, .ferramenta-card, .subtela-card, .historico-card,
.grafico-card, .le-stat, .tela-stat, .timeline-item, .lista-item,
.erro-grupo, .filtros-bar, .tabela-wrap, .nota-card, .info-card,
.info-strip {
  border-color: #d5e2da;
}

/* KPI: todos na mesma linha de base, mesma altura */
.numero-card { min-height: 132px; display: flex; flex-direction: column; }
.numero-comparativo { margin-top: auto; }
.le-stat { min-height: 84px; display: flex; flex-direction: column; justify-content: center; }
.tela-stat { min-height: 68px; display: flex; flex-direction: column; justify-content: center; }
.tela-stat.acao { min-height: 0; }

/* Ícones das ferramentas da home: chip geométrico único (44px) */
.ferramenta-icone {
  width: 44px;
  height: 44px;
  border-radius: var(--r);
  background: var(--accent-soft);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.ferramenta-icone svg { width: 22px; height: 22px; }

/* (impeccable: grade de cartões idênticos é tell — o cartão do Painel
   administrativo é o destaque da casa e ocupa 2 colunas no desktop) */
@media (min-width: 1024px) {
  .ferramentas-grid > .ferramenta-card:first-child { grid-column: span 2; }
  .ferramentas-grid > .ferramenta-card:first-child .ferramenta-desc { max-width: 52ch; }
}

/* Cards de ferramenta/subtela: mesma altura na grade (o grid estica,
   o rodapé de stats desce pra MESMA linha em todos) */
.ferramentas-grid, .subtelas-grid { align-items: stretch; }
.subtela-card { display: flex; flex-direction: column; }
.subtela-card-desc { margin-bottom: 0; }

/* Cabeçalho de página: ritmo vertical FIXO em toda tela */
.voltar-global, .breadcrumb-link { margin-bottom: 12px; }
.topo-tela { margin-bottom: 4px; min-height: 40px; }
.subtitulo-tela, .subtitulo { margin: 0 0 20px 0; }

/* Grade de conteúdo nunca vaza: filho de grid/flex pode encolher */
.numeros-grid > *, .graficos-grid > *, .ferramentas-grid > *,
.subtelas-grid > *, .le-stats > * { min-width: 0; }

/* Tabelas: números alinhados à direita quando marcados */
.tabela td.num, .tabela th.num { text-align: right; }

/* Botões na mesma linha do título: mesma altura, alinhados */
.topo-tela .btn-ghost, .topo-tela .titulo-acao-perigo { align-self: center; }

/* Com a sidebar visível, o "Voltar" do conteúdo é redundante no desktop
   (a navegação está sempre à esquerda). No celular ele volta. */
@media (min-width: 1024px) {
  .app-shell .voltar-global,
  .app-shell nav.breadcrumb,
  .app-shell .breadcrumb-link { display: none; }
  .app-shell .topo-tela { margin-top: 4px; }
}

/* ────────────────────────────────────────────────────────
   23. S15c — ASSINATURA VISUAL (o filete menta)
   Um motivo só, repetido com disciplina: o gradiente
   verde→menta da marca vira fio condutor — título, KPI,
   navegação, login. Direção de arte, não decoração.
   ──────────────────────────────────────────────────────── */

/* (impeccable: acento é ação/seleção/estado, não decoração — barra dos
   títulos removida; hierarquia vem de tamanho, peso e espaço) */
.titulo-tela, .subtela-titulo, .saudacao-titulo, h1, h2, h3 { text-wrap: balance; }
.subtitulo-tela, .subtitulo, .ferramenta-desc, .card-text { text-wrap: pretty; }
.subtitulo-tela, .subtitulo { max-width: 72ch; }

/* (impeccable: gradient-text banido; display font em dado banida)
   Números em Inter, peso e tamanho carregam a ênfase. */

/* (impeccable: eyebrow decorado em todo rótulo = gramática de IA — removido) */

/* Sidebar: brilho atrás da marca + ativo com respiração */
.sidenav-brand { position: relative; }
.sidenav-brand::after {
  content: '';
  position: absolute;
  top: -18px; left: -12px; right: -12px;
  height: 90px;
  background: radial-gradient(140px 70px at 30% 20%, rgba(46,230,168,0.14), transparent 70%);
  pointer-events: none;
}
.sidenav a.ativo {
  background: linear-gradient(90deg, rgba(46,230,168,0.17), rgba(46,230,168,0.04));
}
.sidenav a.ativo svg { opacity: 1; color: #5fd9a8; }

/* Cartões: hover com mais vida (levanta 2px, sombra funda) */
.numero-card:hover, .ferramenta-card:hover, .subtela-card:hover,
.historico-card:hover {
  transform: translateY(-2px);
}

/* Cabeçalho de tabela: fio de fechamento em menta suave */
.tabela thead th { border-bottom: 2px solid rgba(14,138,95,0.22); }

/* Login: filete da marca coroando o cartão */
.login-card {
  position: relative;
  overflow: hidden;
}
.login-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 4px;
  background: linear-gradient(90deg, #0b6e4c 0%, #2ee6a8 45%, #c79a3c 100%);
}

/* (impeccable: motion transmite estado, não decoração — teto de hover removido) */

/* Insight strip: relâmpago em chip, geometria igual aos ícones */
.insight-strip svg {
  flex: 0 0 34px;
  width: 34px; height: 34px;
  padding: 7px;
  border-radius: 9px;
  background: rgba(14,138,95,0.13);
}

/* ────────────────────────────────────────────────────────
   24. S15d — ACABAMENTO IMPECÁVEL (a folha de conteúdo)
   O conteúdo vira uma FOLHA clara com canto arredondado,
   assentada sobre a moldura escura — o olho entende na hora
   onde a navegação termina e o trabalho começa.
   ──────────────────────────────────────────────────────── */

@media (min-width: 1024px) {
  .app-shell { background: #0c2f23; }
  .app-main  { background: #0c2f23; }
  .app-shell main.page-shell {
    max-width: none;
    margin: 0;
    flex: 1;
    padding: 28px max(24px, calc((100% - 1328px) / 2)) 44px;
    background:
      radial-gradient(1100px 340px at 50% -140px, rgba(14,138,95,0.07), transparent 70%),
      var(--bg);
    border-top-left-radius: 18px;
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.35);
  }
  /* A folha de conteúdo tem canto arredondado — a linha neon do topbar
     cortava reta por cima e quebrava a moldura (feedback Marcio). No
     casco ela SOME; no celular (sem folha) o filete da marca continua. */
  .app-shell .topbar { border-bottom: none; background: #0c2f23; }
  .app-shell .topbar::after { display: none; }

  /* (s37b) Cabeçalho de tabela: o sticky foi REMOVIDO. O .tabela-wrap
     tem overflow:hidden (clipe do canto arredondado) — isso faz o
     sticky ancorar no WRAP, não na página: com top:64px o cabeçalho
     flutuava 64px por cima das 2 primeiras linhas em TODA lista (bug
     relatado pelo Marcio 19/jul; o "grudar ao rolar" nunca funcionou
     aqui). Cabeçalho estático = comportamento correto. */
  .app-shell .tabela thead th {
    background: var(--surface-2);
  }
}

/* Navegação: micro-deleite no hover (nudge suave) */
.sidenav a { transition: background 150ms var(--ease-out), color 150ms var(--ease-out), padding-left 180ms var(--ease-out); }
.sidenav a:hover { padding-left: 13px; }
.sidenav a.ativo:hover { padding-left: 10px; }

/* Estado pressionado: resposta tátil em tudo que clica */
.numero-card:active, .ferramenta-card:active, .subtela-card:active,
.historico-card:active, .filtro-pill:active, .btn-ghost:active {
  transform: scale(0.985);
}

/* Impressão: só o conteúdo — moldura, navegação e ações somem */
@media print {
  .sidenav, .topbar, .titulo-acao-perigo, .btn-atualizar,
  .voltar-global, .breadcrumb, .filtros-bar, .le-acoes { display: none !important; }
  .app-shell, .app-main, body { background: #fff !important; }
  .app-shell main.page-shell { padding: 0; border-radius: 0; box-shadow: none; }
  .card, .numero-card, .grafico-card, .tabela-wrap { box-shadow: none !important; }
  body { opacity: 1 !important; }
}


/* ────────────────────────────────────────────────────────
   25. S15f — COMPARTIMENTOS (feedback Marcio: quebra-cabeça)
   Toda caixa com TESTEIRA: o rótulo vira faixa de cabeçalho
   de borda a borda; ações moram no canto direito da testeira.
   ──────────────────────────────────────────────────────── */

.card > .card-eyebrow:first-child {
  margin: calc(-1 * var(--gap)) calc(-1 * var(--gap)) var(--gap);
  padding: 10px var(--gap);
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
  border-radius: calc(var(--r) - 1px) calc(var(--r) - 1px) 0 0;
}
.grafico-card > .card-eyebrow:first-child {
  margin: calc(-1 * var(--gap-lg)) calc(-1 * var(--gap-lg)) var(--gap);
  padding: 10px var(--gap-lg);
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
  border-radius: calc(var(--r) - 1px) calc(var(--r) - 1px) 0 0;
}

/* Testeira genérica pra caixas montadas à mão (treinar, simulador) */
.vv-testeira {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin: -20px -22px 14px;
  padding: 12px 22px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
  border-radius: calc(var(--r-lg) - 1px) calc(var(--r-lg) - 1px) 0 0;
}
.vv-testeira .vv-testeira-acoes {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.vv-testeira h2, .vv-testeira h3 { margin: 0; }


/* ────────────────────────────────────────────────────────
   26. (s121) O ⋯ DA CASA — menu de três pontos
   Verbatim do dono, olhando a Lista de Espera: "o adicionar
   paciente, o ver histórico e o baixar .csv se encaixam
   perfeitamente no padrão que temos os ... (três pontos, que
   tem no card da conversa)".

   ⛔ Régua s86 — existe X na casa? então não se cria Y. O ⋯
   nasceu no cabeçalho da janela do CRM (s114c/s114e) e ficou
   morando dentro do `atendimento.html`. Uma segunda tela
   precisar dele NÃO autoriza um segundo menu de três pontos:
   a peça DESCE pra cá, e as duas telas compõem daqui.

   ⚠️ O glifo ⋯ de fonte NÃO alinha com — ▢ ✕ (a s114e provou
   em duas voltas: cada família desenha um peso). O botão leva
   SVG com `currentColor` — cor e alinhamento passam a ser do
   desenho, não da linha de base da fonte.

   O abre/fecha (clique, clique fora, Esc, fecha ao escolher)
   mora no `vv-ui.js` como `vvMenuPontos(el)` — que as duas
   telas já carregam.
   ──────────────────────────────────────────────────────── */
.jt-mais { position: relative; flex: none; }
.jt-btn {
  width: 28px; height: var(--alt-bt-micro);
  display: grid; place-content: center;
  border: none; background: transparent; border-radius: 6px;
  color: var(--ink-3); cursor: pointer; font-size: var(--fs-corpo);
}
.jt-btn:hover { background: var(--surface-2); color: var(--ink); }
.jt-btn.fechar:hover { background: var(--erro-soft); color: var(--erro); }
.jt-btn.mais svg { display: block; }
.jt-menu {
  position: absolute; right: 0; top: 30px; z-index: 40;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 9px; box-shadow: 0 10px 26px rgba(0,0,0,.15);
  padding: 6px; width: 226px; display: none; flex-direction: column; gap: 1px;
}
.jt-mais.aberto .jt-menu { display: flex; }
.jt-menu .btn-mini {
  border: none; background: none; text-align: left; width: 100%;
  padding: 8px 10px; font-size: var(--fs-corpo);
}
.jt-menu .btn-mini:hover { background: var(--surface-2); }
.jt-menu .btn-mini.ativo { color: var(--accent-strong); font-weight: 600; }

/* ⛔ (s123 — correção do dono) O ↻ É BOTÃO NOVO DA MESMA FAMÍLIA, NÃO
   É O ⋯. Verbatim: *"os ... existem e são extremamente validos e
   legais, e esse refresh é um novo da mesma familia (…) como no
   prodoctor ainda nao tem nada, não tem o porque ter ele ali"*.
   Menu de três pontos com UM item é gaveta pra esconder botão, e dilui
   o ⋯, que na casa quer dizer "tem várias coisas aqui dentro".         */
.jt-btn.recarregar svg { display: block; transition: transform 450ms var(--ease-out); }
.jt-btn.recarregar:hover svg { transform: rotate(-90deg); }
.jt-btn.recarregar.girando svg { animation: jt-gira 700ms linear; }
@keyframes jt-gira { to { transform: rotate(-360deg); } }

/* O filete: separa o que age no CONTEÚDO (o ⋯, o ↻) do que age na
   JANELA (— ▢ ✕). Decisão dele, com o preview na mão: "COM FILETE",
   e nas três janelas que têm o caso.                                   */
/* ⛔ (s130 — foto do dono) O filete se CENTRALIZA sozinho (align-self)
   — antes nascia grudado no topo, porque o contêiner estica os filhos.
   E filete sem NADA antes dele é invisível por regra: primeiro filho
   do .jt-botoes = janela sem botão de conteúdo = sem filete.           */
.jt-sep {
  width: 1px; height: 16px; flex: none; align-self: center;
  background: var(--line-strong); margin: 0 5px;
}
.jt-sep:first-child { display: none; }
.jm-sep {
  padding: 7px 10px 2px; font-size: var(--fs-mini); letter-spacing: .6px;
  text-transform: uppercase; color: var(--ink-3); font-weight: 700;
}

/* O botão de dentro do menu. Base do CRM (s114c), agora fonte
   única — é ela que o ⋯ da Lista de Espera herda de graça. */
.btn-mini {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 6px 11px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--surface); color: var(--ink-2);
  font-family: inherit; font-size: var(--fs-rotulo); font-weight: 600;
  cursor: pointer; transition: background 150ms, border-color 150ms;
}
.btn-mini:hover { border-color: var(--line-strong); background: var(--surface-2); }
.btn-mini:disabled { opacity: .55; cursor: wait; }
/* (s112m) botão de AÇÃO que também é ESTADO: aceso = está valendo */
.btn-mini.ativo {
  background: var(--alerta-soft); color: var(--alerta);
  border-color: var(--alerta); font-weight: 700;
}
.btn-mini.concluir { background: var(--accent); border-color: var(--accent); color: #fff; }

/* (s123) o estado final do `vvBotaoFeito`: o botão VIROU o aviso.
   O texto muda junto com a cor ("Enviar" → "✓ Enviada"), então a cor
   nunca carrega a informação sozinha — a régua de daltonismo da s113f.
   Medido: azul #1d6fb8 × verde #15803d dá ΔE 79 em deuteranopia. */
.btn-primary.feito, .btn-mini.feito, .btn-ghost.feito {
  background: var(--ok); border-color: var(--ok); color: #fff;
  box-shadow: none; cursor: default; filter: none; transform: none;
}
.btn-primary.feito:hover, .btn-mini.feito:hover, .btn-ghost.feito:hover {
  background: var(--ok); filter: none; transform: none;
}
.btn-mini.concluir:hover { background: var(--accent-strong); }


/* ────────────────────────────────────────────────────────
   27. (s121) A CAIXA CURVA NÃO ROLA
   Verbatim do dono, no modal de candidatos da Lista de
   Espera: "ao abrir o paciente ali no candidato você consegue
   perceber que o mesmo fica meio que cortado (acredito por
   ser uma box meio rounded). Veja se isso acontece em outros
   lugares ali do CRM."

   CAUSA: o MESMO elemento tem `border-radius` E
   `overflow-y: auto`. Aí o conteúdo que rola é clipado pelo
   canto curvo, a barra fica dentro da curva, e o que estava
   fixo (título, rodapé) rola junto e some da tela.

   O PADRÃO, um só pros cinco pontos que a varredura achou:
   quem tem a curva é o QUADRO e ele CLIPA (`overflow:hidden`);
   quem rola é o MIOLO, lá dentro. Cabeçalho e rodapé ficam
   FORA do miolo — é isso que os mantém na tela.

   `.rola-miolo` já entra na lista de seletores da `.rola-dica`
   (seção da rolagem, s120): quem rola ganha a dica de fim de
   graça, sem ninguém lembrar de pedir.

   ⚠️ Nasce com FISCAL: `scripts/auditar_html.py` reprova
   elemento que rola COM canto curvo. Sem cheque, a régua
   volta na próxima tela (s64).
   ──────────────────────────────────────────────────────── */
.rola-quadro { overflow: hidden; }
.rola-miolo  { overflow-y: auto; min-height: 0; }

/* ────────────────────────────────────────────────────────
   28. (s128 — A GRANDE REFORMA) MODO EMBUTIDO É DA CASA
   Qualquer tela pode virar janela da mesa (`?embutido=1`).
   A régua veio das duas que já sabiam (ProDoctor e Lista de
   Espera, s120–s125): a página embutida é CONTEÚDO PURO —
   sem topbar, sem casco verde, sem canto curvo (o "buraco
   preto" da s125). Quem põe a classe é o vv-nav.js, a peça
   que as 24 telas já carregam; as regras vivem AQUI, uma vez.
   A tela que precisar de ajuste PRÓPRIO (ex.: LE esconde a
   info-strip) mantém as regras dela por cima — isto é o piso.
   ──────────────────────────────────────────────────────── */
body.embutido { margin: 0; padding: 0; background: transparent; }
body.embutido .topbar { display: none; }
body.embutido .app-shell, body.embutido .app-main { background: var(--bg); }
body.embutido .app-shell main.page-shell,
body.embutido .page-shell {
  border-radius: 0; box-shadow: none;
  padding: 14px 16px 20px; margin: 0; max-width: none;
}
body.embutido .cron-pill { display: none; }
body.embutido .voltar-global { display: none; }
/* o título grande da página vira redundância dentro de uma janela que
   já tem cabeçalho com o mesmo nome — encolhe, não some (contagens e
   ações que moram do lado dele continuam na tela) */
body.embutido .titulo-tela { font-size: var(--fs-head); }

/* ────────────────────────────────────────────────────────
   29. (s128) TOOLTIP DA CASA — `data-tip`
   O pedido do dono na pílula da API: "a informação pequena
   aparecer mais bonitinha" no hover das barrinhas (era o
   `title` nativo do navegador). Peça única: qualquer elemento
   com `data-tip="…"` ganha a pílula escura; quem posiciona é
   o vv-ui.js (vvTip), delegado no document.
   ──────────────────────────────────────────────────────── */
.vv-tip {
  position: fixed; z-index: 5000; pointer-events: none;
  background: var(--ink); color: #fff;
  font-size: var(--fs-mini); font-weight: 600;
  padding: 5px 9px; border-radius: 8px;
  box-shadow: 0 4px 14px rgba(19,32,26,.28);
  white-space: nowrap; opacity: 0; transform: translateY(2px);
  transition: opacity 120ms ease, transform 120ms ease;
}
.vv-tip.mostra { opacity: 1; transform: translateY(0); }


/* ════════════════════════════════════════════════════════════
   17. A RÉGUA DO MOVIMENTO (s260) — só no PAINEL NOVO e no
   AGENDAMENTO ONLINE
   ────────────────────────────────────────────────────────────
   Pedido do dono (24/set): "detalhes de efeitos, mais dinâmicos
   (…) hoje clico o botão salvar, não acontece nada com o botão".
   ⛔ LEI DA FRONTEIRA: este arquivo também é carregado pelo painel
   velho — então TUDO aqui mora atrás da chave `body.vv-mov`, que
   só o atendimento2.html e o agendar.html põem no <body> (mesma
   régua do `VV_PISO_LISTA`, ARMADILHAS s258). Quem não diz nada
   fica como sempre foi.
   ⛔ A régua: movimento só pra mostrar ESTADO (apertou, está
   esperando, gravou, deu erro, mudou, abriu, fechou). Dois tempos
   (130 ms resposta · 190 ms troca), uma curva, nada em loop que
   seja enfeite, nada que pisque. Quem pediu movimento reduzido no
   aparelho não vê nada disso (a regra global da seção de
   acessibilidade já zera tudo).
   Protocolo completo: docs/PROTOCOLO_DO_OLHAR.md.
   ⛔⛔ (s289 · a régua S da auditoria do movimento — escolha dele:
   aplicar) UM RELÓGIO SÓ. Havia 11 tempos de entrada e 8 curvas (duas
   com dois nomes pra mesma conta); 12 peças abriam suave e fechavam
   seco. Agora o tempo é do TIPO de gesto — ninguém escolhe número:
     resposta (cor, afundar, foco) ........ 130 (--t-rapido)
     o que flutua (lista, ⋯, popover, dica) entra 130 (3 px do lado do
       botão) · sai 120 ease-in (--t-sai; vvSome no vv-ui.js)
     o que cobre (confirmação, caixa, foto, receita) entra 190
       (--t-medio) · sai 120 ease-in
     popup que leva a outro: véu e caixa ficam, o de dentro troca
       (cx.passar() no vv-ui.js)
     o que ocupa lugar (bloco, faixa, aviso em fluxo) abre 190 pela
       ALTURA e fecha 180 (--t-fecha) na curva suave (--curva-suave),
       sólido: sai de trás do vizinho e o vizinho volta por cima.
       Pela altura = `height: 0 ↔ auto` com `interpolate-size` (abaixo),
       quem mede é o navegador — NUNCA a grade 0fr↔1fr (deixa vão entre
       a peça e o que está dentro) nem conta em JS (s263l)
     aviso que flutua ....... entra 190 (sobe 3 px) · sai 120 (desce 3)
     tela e janela .......... 240 (--t-tela), sobe 6 px OPACA desde o
       1º quadro; ao fechar, a que fica sobe por cima da que sai; só a
       de cima faz sombra; abas, cabeçalho e barras ficam PARADAS
     estado ................. ✓ risca 260 · pulso 500
   Curva de entrar: --curva (é a --ease-out do :root; um nome só).
   ⛔⛔ (s293 · 28/09 — escolha dele no protótipo «Ritmo do movimento»: C++) O RITMO C COM A MOLA MACIA.
   Ele sentiu os efeitos curtos demais: a curva de antes fazia 90% do caminho em 107 ms e o resto quase
   parado. TODO movimento fica 50% mais lento e usa a MOLA MACIA — começa macio, espalha o movimento
   pelo tempo todo (90% do caminho aos 70% do tempo) e nunca passa do ponto (a régua «nenhuma curva
   passa do ponto» continua). A mesma curva ENTRA e SAI (--curva, --curva-suave e --curva-sai apontam
   pra ela). Os números de cima são os de antes; os de agora (entra · sai):
     resposta (cor, foco, passar o mouse) ... 130 — não é movimento, fica (--t-rapido)
     flutua (lista, ⋯, popover, dica) ....... 195 (--t-flutua) · 180 (--t-sai)
     cobre (popup, foto, receita) ........... 285 (--t-medio) · 180 (--t-sai)
     ocupa lugar (bloco, faixa, aviso, linha) 285 (--t-medio) · 270 (--t-fecha)
     tela / janela .......................... 360 (--t-tela) · 360
     encaixe da janela (reacomoda na mesa) .. 300 (--t-encaixe)
     dentro do bloco (o texto e as pontas) .. ×1,5 do aprovado (--t-texto-*, --t-ponta-*)
   UM LUGAR SÓ: toda peça lê daqui — o CSS pelo var(), o JS pelo vvTempo/vvCurva (vv-ui.js). Mudar o
   ritmo é mudar este bloco e mais nada. Os tokens moram também no <html> da página nova (:has), porque
   a troca suave (::view-transition) é filha do <html>, não do <body>. Fica fora do relógio o que é
   ESTADO (✓, pulso, a linha que mudou, a espera de ¼ s) e o que tem régua própria nomeada (a marca
   do fundo, a barra lateral, o aviso da casa).
   Navegador sem linear() (antigo): a curva de antes.
   ════════════════════════════════════════════════════════════ */
:is(:root:has(> body.vv-mov), body.vv-mov) {
  --t-rapido: 130ms; --t-flutua: 195ms; --t-sai: 180ms; --t-medio: 285ms; --t-fecha: 270ms; --t-tela: 360ms;
  --t-encaixe: 300ms;   /* a janela que se reacomoda na mesa (lado a lado, ▢, a fila que recolhe): 200 ×1,5 (escolha dele, 29/09) */
  --t-texto-sai: 105ms; --t-texto-entra: 180ms; --t-texto-espera: 90ms;
  --t-ponta-entra: 45ms; --t-ponta-sai: 60ms; --t-ponta-sai-espera: 195ms;
  --curva-mola: linear(0.000 0%, 0.020 4.2%, 0.069 8.3%, 0.136 12.5%, 0.212 16.7%, 0.291 20.8%, 0.370 25%, 0.446 29.2%, 0.517 33.3%, 0.583 37.5%, 0.642 41.7%, 0.695 45.8%, 0.743 50%, 0.785 54.2%, 0.821 58.3%, 0.853 62.5%, 0.881 66.7%, 0.905 70.8%, 0.926 75%, 0.943 79.2%, 0.959 83.3%, 0.972 87.5%, 0.983 91.7%, 0.992 95.8%, 1.000 100%);
  --curva: var(--curva-mola); --curva-suave: var(--curva-mola); --curva-sai: var(--curva-mola);
}
@supports not (transition-timing-function: linear(0, 1)) {
  :is(:root:has(> body.vv-mov), body.vv-mov) { --curva: var(--ease-out); --curva-suave: cubic-bezier(.4, 0, .6, 1); --curva-sai: ease-in; }
}
body.vv-mov {
  interpolate-size: allow-keywords;   /* a altura anima até `auto` (herdado): o navegador mede */
}

/* ── P1 · todo botão responde: cor suave e afunda no clique ── */
body.vv-mov .m2-bt, body.vv-mov .tirar, body.vv-mov .jt-btn, body.vv-mov .pac-ed-bt,
body.vv-mov .m3-chip, body.vv-mov .pchip, body.vv-mov .vista-pill, body.vv-mov .btn-mini {
  transition: background-color var(--t-rapido) var(--curva), color var(--t-rapido) var(--curva),
              border-color var(--t-rapido) var(--curva), box-shadow var(--t-rapido) var(--curva),
              opacity var(--t-rapido) var(--curva), transform 90ms var(--curva);
}
body.vv-mov .m2-bt:active:not(:disabled), body.vv-mov .tirar:active, body.vv-mov .jt-btn:active,
body.vv-mov .pac-ed-bt:active, body.vv-mov .m3-chip:active, body.vv-mov .pchip:active {
  transform: scale(.97);
}
/* (s260i — ele: "os botões lá no atendimento também não estão com aquele efeito de apertar")
   medido apertando botão por botão: o Enviar, o anexo, o ⚡, as abas, os btn-mini, o ✕ da
   bolha e os da busca da conversa não afundavam. Mesma peça, mesma medida. */
body.vv-mov .jr-enviar, body.vv-mov .bt-ico, body.vv-mov .jr-raio, body.vv-mov .msg-x, body.vv-mov .jb-bt, body.vv-mov .eq-envio button {
  transition: background-color var(--t-rapido) var(--curva), color var(--t-rapido) var(--curva),
              border-color var(--t-rapido) var(--curva), transform 90ms var(--curva);
}
body.vv-mov .vista-pill:active, body.vv-mov .btn-mini:active:not(:disabled),
body.vv-mov .jr-enviar:active:not(:disabled), body.vv-mov .bt-ico:active, body.vv-mov .jr-raio:active,
body.vv-mov .jb-bt:active:not(:disabled), body.vv-mov .eq-envio button:active:not(:disabled) {
  transform: scale(.97);
}
body.vv-mov .bolha .msg-x:active { transform: scale(.9); }   /* 18 px: .97 não se vê */

/* ── P3 · foco: a borda e o anel entram juntos; o teclado ganha o anel da casa ── */
body.vv-mov .m3-campo input, body.vv-mov .m3-campo textarea, body.vv-mov .vv-combo-caixa > input {
  transition: border-color var(--t-rapido) var(--curva), box-shadow var(--t-rapido) var(--curva),
              background-color var(--t-medio) var(--curva);
}
body.vv-mov .m2-bt:focus-visible, body.vv-mov .tirar:focus-visible, body.vv-mov .jt-btn:focus-visible,
body.vv-mov .vista-pill:focus-visible, body.vv-mov .m3-chip:focus-visible, body.vv-mov .pchip:focus-visible {
  outline: none; box-shadow: var(--focus-ring);
}
body.vv-mov .m3-tg:focus-visible { outline: none; }
body.vv-mov .m3-tg:focus-visible .trilho { box-shadow: var(--focus-ring); }

/* ── P2 · o botão que espera (a vvBotaoFeito da s123, no automático) ──
   Quem liga é o vv-ui.js: clique num .m2-bt que dispara gravação no
   servidor → `vv-fazendo` enquanto grava, `vv-feito` (✓) quando deu,
   `vv-erro` (tremidinha) quando não deu. Com ícone, o giro fica NO
   LUGAR do ícone e o rótulo fica; sem ícone, o giro fica no centro e
   o rótulo some só enquanto espera. A largura nunca muda. */
body.vv-mov .m2-bt.vv-fazendo, body.vv-mov .m2-bt.vv-feito { pointer-events: none; position: relative; }
body.vv-mov .m2-bt.vv-fazendo.vv-com-ic > svg:first-child,
body.vv-mov .m2-bt.vv-feito.vv-com-ic > svg:first-child { visibility: hidden; }
body.vv-mov .m2-bt.vv-fazendo:not(.vv-com-ic), body.vv-mov .m2-bt.vv-feito:not(.vv-com-ic) { color: transparent !important; }
/* sem ícone: o giro e o ✓ no centro, o rótulo some só enquanto espera */
body.vv-mov .m2-bt.vv-fazendo:not(.vv-com-ic)::after {
  content: ""; position: absolute; width: 14px; aspect-ratio: 1; border-radius: 50%;
  left: calc(50% - 7px); top: calc(50% - 7px);
  border: 2px solid rgba(255,255,255,.45); border-top-color: #fff;
  animation: vv-gira .7s linear infinite;
}
body.vv-mov .m2-bt.borda.vv-fazendo:not(.vv-com-ic)::after, body.vv-mov .m2-bt.m3-bt-perigo.vv-fazendo:not(.vv-com-ic)::after {
  border-color: rgba(19,32,26,.15); border-top-color: var(--accent);
}
body.vv-mov .m2-bt.vv-feito:not(.vv-com-ic)::after {
  content: ""; position: absolute; width: 5px; aspect-ratio: 5 / 9;   /* o ✓: um L girado (sem "height": a escada dos botões é pra botão, não pro risco) */
  left: calc(50% - 3px); top: calc(50% - 6px);
  border: solid #fff; border-width: 0 2.4px 2.4px 0; transform: rotate(45deg) scale(.4); opacity: 0;
  animation: vv-risca 280ms var(--curva) forwards;
}
body.vv-mov .m2-bt.borda.vv-feito:not(.vv-com-ic)::after, body.vv-mov .m2-bt.m3-bt-perigo.vv-feito:not(.vv-com-ic)::after { border-color: var(--accent); }
/* (s260h) com ícone: a peça é um SVG irmão do ícone — mesmo tamanho, lugar, traço e cor (vv-ui.js) */
body.vv-mov .m2-bt > .vv-ic-sobre { position: absolute; display: block; pointer-events: none; }
body.vv-mov .m2-bt > .vv-ic-sobre.giro { animation: vv-gira .7s linear infinite; }
body.vv-mov .m2-bt > .vv-ic-sobre.ok path { stroke-dasharray: 22; stroke-dashoffset: 22; animation: vv-risca-traco 260ms var(--curva) forwards; }
@keyframes vv-risca-traco { to { stroke-dashoffset: 0; } }
body.vv-mov .m2-bt.vv-erro { animation: vv-treme 320ms var(--curva); }
@keyframes vv-gira { to { transform: rotate(360deg); } }
@keyframes vv-risca { to { transform: rotate(45deg) scale(1); opacity: 1; } }
@keyframes vv-treme { 20% { transform: translateX(-3px); } 40% { transform: translateX(3px); } 60% { transform: translateX(-2px); } 80% { transform: translateX(1px); } }

/* ── P4 · Salvar com obrigatório vazio: o campo que falta dá UM pulso ── */
/* (s260f) nome próprio: "vv-cobra" já é a cobrinha do aviso (toast, seção de cima) — o mesmo nome aqui apagava ela */
body.vv-mov .vv-cobra { animation: vv-cobra-campo 500ms var(--curva); }
@keyframes vv-cobra-campo { 40% { box-shadow: 0 0 0 5px rgba(192,57,43,.22); } 100% { box-shadow: 0 0 0 0 rgba(192,57,43,0); } }

/* ── P5 · a linha que mudou acende (a peça .v2-atualizou, que tinha 0 usos) ── */
body.vv-mov tr.v2-atualizou > td { animation: v2-blink 900ms ease-out; }

/* ── P6 · o número que sobe pulsa uma vez ── */
body.vv-mov .vv-pulsa { animation: vv-pulsa 500ms var(--curva); }
@keyframes vv-pulsa { 35% { transform: scale(1.25); } }

/* ── P7 · menu ⋯: entra como os outros menus e o botão fica marcado ── */
body.vv-mov .jt-mais.aberto .jt-menu { animation: vv-entra var(--t-flutua) var(--curva); }
body.vv-mov .jt-mais.aberto > .jt-btn { background: var(--surface-2); color: var(--ink); }
@keyframes vv-entra { from { opacity: 0; transform: translateY(-3px); } }
@keyframes vv-entra-cima { from { opacity: 0; transform: translateY(3px); } }

/* ── P8 · a lista suspensa entra do campo, na direção certa ── */
body.vv-mov .vv-combo-painel { animation: vv-entra var(--t-flutua) var(--curva) both; }
body.vv-mov .vv-combo-painel.cima { animation-name: vv-entra-cima; }

/* ── (s289 · 8) o popup da casa entra no relógio: véu e caixa juntos, 190, curva da casa ── */
body.vv-mov .vv-conf-overlay { animation: v2-fade var(--t-medio) var(--curva) both; }
body.vv-mov .vv-conf { animation: v2-pop var(--t-medio) var(--curva) both; }
/* (s289 · 26) a caixa que veio de outra nasce no MESMO véu: nada entra de novo (o vv-ui.js troca o de dentro) */
body.vv-mov .vv-conf-overlay.vv-passou, body.vv-mov .vv-conf-overlay.vv-passou .vv-conf { animation: none; }

/* ── P10 · a confirmação fecha suave (o vv-ui.js põe .sai e espera) ── */
body.vv-mov .vv-conf-overlay.sai { animation: vv-some var(--t-sai) var(--curva-sai) forwards; pointer-events: none; }
body.vv-mov .vv-conf-overlay.sai .vv-conf { animation: vv-some-caixa var(--t-sai) var(--curva-sai) forwards; }
@keyframes vv-some { to { opacity: 0; } }
@keyframes vv-some-caixa { to { opacity: 0; transform: scale(.98); } }

/* ── P13 · a dica espera um instante antes de aparecer ── */
/* (s293) a dica é do que flutua: entra no --t-flutua e sai no --t-sai, na mola (a peça fica igual no painel velho) */
body.vv-mov .vv-tip { transition: opacity var(--t-sai) var(--curva-sai), transform var(--t-sai) var(--curva-sai); }
body.vv-mov .vv-tip.mostra { transition-duration: var(--t-flutua); transition-timing-function: var(--curva); transition-delay: 300ms; }
/* (s289 · 18) a dica QUENTE: passando pro vizinho em até 600 ms, troca na hora (vv-ui.js) */
body.vv-mov .vv-tip.mostra.quente { transition: none; }

/* ── (s289 · 1) o que flutua sai em 120 ms (vvSome · o ⋯ · a lista do campo) ──
   o clique já atravessa (pointer-events) e os seletores de "está aberto?" pulam `.vv-sai` */
body.vv-mov .vv-sai { animation: vv-some var(--t-sai) var(--curva-sai) forwards !important; pointer-events: none !important; }

/* ── (s289 · 16) o fundo da aba desliza (vv-ui.js): um indicador com o fundo da aba anda de lá
   pra cá, 190; enquanto anda, as abas não pintam o próprio fundo ── */
body.vv-mov .vv-aba-rel { position: relative; }
body.vv-mov .vv-aba-ind { position: absolute; z-index: 0; pointer-events: none; box-sizing: border-box; margin: 0; }
body.vv-mov .vv-aba-desl > .vista-pill { position: relative; z-index: 1; }
body.vv-mov .vv-aba-desl > .vista-pill.ativo { background: transparent !important; border-color: transparent !important; box-shadow: none !important; }
body.vv-mov .vv-aba-sem-tr > .vista-pill { transition: none !important; }

/* ── (s289 · 17) copiar: o valor fica, ✓ riscado da casa, a linha acende de leve 1,2 s ── */
.vv-copiado { position: relative; }
.vv-copia-ok { position: absolute; right: 8px; top: 50%; margin-top: -7px; color: var(--accent); pointer-events: none; }
.vv-copiado-fora > .vv-copia-ok { right: auto; left: calc(100% + 6px); }
.vv-copia-ok path { stroke-dasharray: 22; stroke-dashoffset: 0; }
body.vv-mov .vv-copia-ok path { stroke-dashoffset: 22; animation: vv-risca-traco 260ms var(--curva) forwards; }
body.vv-mov .vv-copiado:not(.vv-copiado-fora) { background-color: var(--accent-soft); }
body.vv-mov :is(.jd-item, .pac-fd-copia) { transition: background-color var(--t-rapido) var(--curva), color var(--t-rapido) var(--curva); }

/* ── (s289 · 25) na troca suave, o que não muda fica PARADO: abas, cabeçalho da coluna, barras de
   baixo e de passo têm nome próprio (vv-ui.js · VV_FIXAS) — sem animação, por cima da tela que
   sobe, e sem a foto velha delas (senão as duas abas acesas aparecem juntas) ── */
::view-transition-group(*.vv-fixa) { animation: none; z-index: 3; }
::view-transition-old(*.vv-fixa) { display: none; }
::view-transition-new(*.vv-fixa) { animation: none; }

/* ── P14 · troca lenta: esmaece SÓ se passar de ¼ de segundo (nunca pisca) ── */
body.vv-mov .vv-lento { opacity: .6; transition: opacity 160ms var(--curva) .25s; }
/* (s260i) o "Carregando…" só aparece depois de ¼ s (vv-ui.js marca) — carga rápida não pisca */
body.vv-mov .vv-espera { animation: vv-espera-tarde 420ms linear both; }
@keyframes vv-espera-tarde { 0%, 60% { opacity: 0; } 100% { opacity: 1; } }

/* ═══ (s294 · Revisão das Peças) O CARTÃO DO CONVÊNIO — um desenho só: o agendamento (Meus convênios) e a prévia
   da cor no Cadastros. A cor vem do cadastro (--band/--corpo no .ct; sem cor, neutro). Montado pelo vvCartaoHTML (vv-ui). */
.ct { --band:#14211a; --corpo:#e9ede7; display:flex; flex-direction:column; gap:8px; }
/* (s254e — ele) a cor do cartão é CADASTRO (`convenio.cor_cartao`): a tela põe
   --band/--corpo no .ct; sem cor, o cartão é neutro (tarja escura, corpo claro) */
.ct-palco { width:100%; max-width:326px; align-self:center; }
.ct-caixa { position:relative; width:100%; aspect-ratio:1.586; }
.ct-face { position:absolute; inset:0;
  border-radius:var(--r); overflow:hidden; display:flex; flex-direction:column; background: var(--corpo);
  box-shadow: 0 5px 14px rgba(8,30,22,.16); }
.ct-band { background: var(--band); height:38%; display:flex; align-items:center; justify-content:flex-end; padding:0 10px; }
.ct-logo { height:54%; max-height:42px; width:auto; }
/* ⛔ (s260) a logo chega numa MOLDURA de altura fixa com o peso da régua já
   dentro (core/faturamento.py::convenio_logo_tela) — 42px = 1,6x os 26px de antes */
/* (s253l) sem logo no cadastro entra o apelido — e ele precisa de pele:
   nasceu na s253h sem regra nenhuma, escuro em cima da tarja escura. */
.ct-nome { color:#fff; font-family: var(--font-display); font-weight:700;
  font-size: var(--fs-corpo); letter-spacing:.01em; line-height:1; }
.ct-corpo { flex:1; padding:8px 10px; display:flex; flex-direction:column; gap:6px; justify-content:center; }
.ct-num { position:relative; display:flex; gap:6px; align-items:baseline; font-family: var(--font-dados);
  font-size:var(--fs-corpo); font-weight:700; color:#16281c; letter-spacing:.04em; padding:2px 4px; border-radius:6px; white-space:nowrap; }
.ct-pref { background: rgba(255,255,255,.75); border-radius:4px; padding:0 3px; }
.ct-resto { opacity:.55; }
.ct-linhas { display:flex; flex-direction:column; gap:4px; }
.ct-linhas i { height:4px; border-radius:3px; background: rgba(0,0,0,.14); display:block; }

/* ═══ §18 · (s302) A FAIXA DE PROGRESSO — os passos com ícone, a linha do tempo e o «voltar» do passo feito.
   Nasceu no agendamento online (o resumo da versão web, s263); o popup da nota fiscal do painel novo usa a MESMA
   peça (protótipo v6). Mesma largura do agendar: a partir de 1024 px (o celular do agendar não muda). Quem veste a
   faixa (a linha que liga os ícones, o tamanho) é o dono: `.wp-lado` no agendar, `.nf-passos` no popup. ═══ */
@media (min-width: 1024px) {
  .wl-passos { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
  .wl-lin { display: flex; align-items: center; gap: 12px; padding: 8px 10px; border-radius: 10px; min-height: 48px; }
  .wl-ico { width: 32px; height: 32px; border-radius: 9px; flex: none; display: inline-flex; align-items: center; justify-content: center;
    background: var(--surface-2); color: var(--ink-3); }
  .wl-ico svg { width: 17px; height: 17px; }
  .wl-txt { min-width: 0; flex: 1; display: flex; flex-direction: column; font-size: var(--fs-corpo); line-height: 1.35; text-align: left; }
  .wl-txt span { color: var(--ink-3); }
  .wl-txt b { font-weight: 600; color: var(--ink); overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }
  .wl-lin.feito .wl-ico { background: var(--accent-soft); color: var(--accent-strong); }
  .wl-lin.atual { background: var(--surface-2); }
  .wl-lin.atual .wl-ico { background: var(--accent); color: #fff; }
  .wl-lin.atual .wl-txt span { color: var(--ink); font-weight: 600; }
  .wl-lin.depois .wl-ico { background: none; border: 1px dashed var(--line-strong); }
  .wl-volta { display: flex; align-items: center; gap: 12px; width: 100%; border: 0; background: none; padding: 0; margin: 0; font: inherit; color: inherit; cursor: pointer; text-align: left; }
  .wl-lin:has(> .wl-volta) { cursor: pointer; }
  .wl-lin:has(> .wl-volta):hover { background: var(--surface-2); }
  .wl-volta > svg:last-child { margin-left: auto; width: 16px; height: 16px; color: var(--ink-faint); opacity: 0; transition: opacity var(--t-rapido); flex: none; }
  .wl-lin:hover .wl-volta > svg:last-child, .wl-volta:focus-visible > svg:last-child { opacity: 1; }
  .wl-volta:focus-visible { outline: none; }
  .wl-lin:has(> .wl-volta:focus-visible) { box-shadow: var(--focus-ring); }
  body.vv-mov .wl-lin .wl-ico { transition: background-color var(--t-rapido) var(--curva), color var(--t-rapido) var(--curva); }
}

/* ═══ §19 · (s306n) A ESCRITA QUE TROCA — o botão (ou rótulo) que muda de nome no clique ═══
   Ele (02/10, protótipo «Caixa por lançamento» v10, decisão 5 = 2): "botão que troca não tem o efeito de um botão
   comum" — a escrita ROLA: a velha sobe e sai, a nova vem de baixo, juntas, na mola (`--t-medio`), recortadas na
   altura da linha. Vale pra toda troca de escrita (o texto todo pode mudar). Quem troca é o `vvRola` (vv-ui.js).
   As escritas moram empilhadas no mesmo lugar: com todas presentes (`data-vv-rola-fica`), a peça não muda de tamanho.
   Uso: <span class="vv-rola" data-vv-rola-fica><span>Ver por lançamento</span><span class="vai">Ver por procedimento</span></span>
   Sem body.vv-mov (ou com movimento reduzido): troca seca. */
.vv-rola{display:inline-grid;vertical-align:top;overflow:hidden;clip-path:inset(0 -4px);text-align:left}
.vv-rola > span{grid-area:1/1;white-space:nowrap}
body.vv-mov .vv-rola > span{transition:transform var(--t-medio) var(--curva),opacity var(--t-medio) linear}
.vv-rola > .vai{transform:translateY(-100%);opacity:0}
.vv-rola > .vem{transform:translateY(100%);opacity:0}
@media (prefers-reduced-motion:reduce){body.vv-mov .vv-rola > span{transition:none}}
