:root {
  /* Paleta padrão = "vinho" (2026-09-02, pedido do cliente junto com a
     logo nova: "atualizar o sistema para acompanhar essa cor... sendo
     ele a opção primária até o usuário decida mudar") - a antiga paleta
     verde-floresta (a original deste app) não sumiu, virou a alternativa
     em [data-cor="floresta"] (ver bloco logo abaixo do dark mode) -
     selecionável no mesmo botão que já troca claro/escuro (nav.php +
     assets/theme.js). */
  --primary: #7a2f3f;
  --primary-dark: #4a1c26;
  --heading: var(--primary-dark);
  --accent: #a97c3f;
  --accent-light: #d4b876;
  --bg: #f4efe4;
  --bg-alt: #ebe3d2;
  --card: #fffdf8;
  --ink: #2a2520;
  --ink-dim: #6f6459;
  --border: #ddd2bd;
  --success: #2f6b45;
  --warn: #92651f;
  --danger: #a4453a;
  /* Paleta dedicada do donut/barras "Resumo do mês" - REDESENHADA 2026-08-31
     (cliente, depois de "Remarcações" virar a 5ª categoria: "esta mostrando
     24 cancelamentos... vamos colocar mais uma cor", depois "não gostei da
     harmonia das cores... não combinam entre si", depois "troca as cores de
     remarcada e realizados"). Mesma receita OKLCH (L=0.61 C=0.17, só o
     matiz muda por fatia). "Realizadas" ficou provado preso à família
     verde-azulada (matiz ~170°) - verde puro colide com âmbar/vermelho pra
     quem tem deuteranopia/protanopia, não passa no validador ao lado das
     outras cores fixas. O que mudou de verdade: "Cancelamentos" e
     "Remarcações" trocaram de lugar no espectro - cancelamento assume o
     ciano que remarcação tinha, remarcação vira azul-violeta (matiz 275°),
     opção "B" aprovada numa prévia comparativa. Validado nas DUAS sequências
     reais em que essas cores encostam (donut: pendente→realizado→falta→
     cancelado→remarcado; barras: realizado→pendente→cancelado→falta→
     remarcado) - ver validate_palette.js
     "#bc6f00,#00a273,#d65141,#009db3,#6876e7" e
     "#00a273,#bc6f00,#009db3,#d65141,#6876e7" --mode light. */
  --status-pendente: #bc6f00;
  --status-realizado: #00a273;
  --status-falta: #d65141;
  --status-cancelado: #009db3;
  --status-remarcado: #6876e7;
  --radius: 14px;
  --radius-sm: 8px;
  --display: 'Fraunces', Georgia, serif;
  --body: 'Manrope', -apple-system, BlinkMacSystemFont, sans-serif;
  --shadow: 0 2px 6px rgba(42, 37, 32, 0.06), 0 8px 24px rgba(42, 37, 32, 0.06);
  /* Fundo da tela de login (login.php's .auth-page) - sempre "escuro
     imponente" independente do claro/escuro do resto do app (ver
     comentário ali). Em tokens (não mais literal fixo) pra poder variar
     por [data-cor], ver blocos abaixo. */
  --auth-bg-1: #6b2c3a;
  --auth-bg-2: #4a1c26;
  --auth-bg-3: #200d12;
  --auth-glow-2: #8a4054;
}

/* Cor de seleção de texto própria (2026-09-08, achado real do cliente:
   "ainda está difícil de ler quando fica selecionado") - sem isto, o
   navegador usa a cor de destaque do PRÓPRIO SISTEMA OPERACIONAL (ex:
   rosa/magenta no Windows com esse tema de cores) pra marcar texto
   arrastado/selecionado - sem contraste nenhum garantido contra os
   blocos coloridos da Agenda (evento verde/laranja + texto branco +
   seleção rosa = ilegível). --primary (o vinho da marca) com texto
   branco garante contraste em qualquer bloco, em vez de depender do
   tema de cores de quem estiver usando o sistema. */
::selection { background: var(--primary); color: #fff; }

/* Dark mode - toggled via [data-theme] on <html>, set by partials/head.php's
   inline pre-paint script (localStorage, falling back to the OS preference)
   and flipped by assets/theme.js's button. Warm charcoal, not pure black -
   keeps the same "estúdio aconchegante" register as the light palette
   instead of going generic-dark-UI. --primary/--accent get lifted a shade
   brighter than their light-mode values since the originals were tuned for
   contrast against a pale background, not a dark one. */
:root[data-theme="dark"] {
  --primary: #a85068;
  --primary-dark: #7a2f3f;
  /* --heading é um token SEPARADO de --primary-dark - achado real na
     auditoria visual de 2026-08-04: títulos (h1/h2/h3, nav ativo, valores
     de resumo) usavam --primary-dark direto, que no escuro é só um verde-
     floresta escuro (bom como FUNDO de botão com texto branco em cima, mas
     quase ilegível como TEXTO sobre o próprio fundo escuro do card). Separar
     os dois usos resolve sem afetar onde --primary-dark já funcionava bem
     (hover de botão, .fc-button-active). */
  --heading: #dba7b3;
  --accent: #e0c48f;
  --accent-light: #f2ddb0;
  --bg: #1f1418;
  --bg-alt: #2a1a1f;
  --card: #2e1c22;
  --ink: #f0ead9;
  --ink-dim: #b4a999;
  --border: #4a2f38;
  --success: #6fbf8f;
  --warn: #e0b35a;
  --danger: #e0776a;
  /* Mesma receita OKLCH do modo claro acima (L/matizes iguais), só a
     luminosidade sobe pra L=0.64 (faixa aceita no escuro é 0.48-0.67,
     diferente da faixa clara) - ver validate_palette.js
     "#c67800,#00ab7c,#e05b4a,#00a7bd,#707ff1" e
     "#00ab7c,#c67800,#00a7bd,#e05b4a,#707ff1" --mode dark. */
  --status-pendente: #c67800;
  --status-realizado: #00ab7c;
  --status-falta: #e05b4a;
  --status-cancelado: #00a7bd;
  --status-remarcado: #707ff1;
  --shadow: 0 2px 6px rgba(0, 0, 0, 0.35), 0 8px 24px rgba(0, 0, 0, 0.35);
}

/* Paleta "floresta" (2026-09-02) - a paleta ORIGINAL deste app
   (verde-floresta + dourado), agora a alternativa de COR pra quem
   preferir - "vinho" (base do :root acima) virou o padrão novo, pedido
   explícito do cliente junto com a logo nova, mas "floresta" continua
   selecionável no mesmo botão que já troca claro/escuro (ver nav.php +
   assets/theme.js). Mesma estrutura clara/escura de sempre, só a família
   de cor muda. */
:root[data-cor="floresta"] {
  --primary: #2f4a3e;
  --primary-dark: #203228;
  --heading: var(--primary-dark);
  --accent: #b08a3e;
  --accent-light: #d4b876;
  --auth-bg-1: #3c5c4c;
  --auth-bg-2: #203228;
  --auth-bg-3: #1a2820;
  --auth-glow-2: #4f7c62;
}
:root[data-cor="floresta"][data-theme="dark"] {
  --primary: #4f7c62;
  --primary-dark: #2f4a3e;
  --heading: #9dc4ac;
  --accent: #d4a94a;
  --accent-light: #e8cb84;
  --bg: #1c1a16;
  --bg-alt: #262219;
  --card: #29251e;
  --border: #423c32;
  --auth-bg-1: #3c5c4c;
  --auth-bg-2: #203228;
  --auth-bg-3: #1a2820;
  --auth-glow-2: #4f7c62;
}

* { box-sizing: border-box; }

svg[aria-hidden="true"] { vertical-align: -0.15em; flex: 0 0 auto; }

html, body {
  margin: 0;
  padding: 0;
  font-family: var(--body);
  background: var(--bg);
  color: var(--ink);
  font-size: 16px;
  line-height: 1.5;
}

h1, h2, h3, .clinica-nav-brand {
  font-family: var(--display);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--heading);
  margin: 0;
  text-wrap: balance;
}
h1 { font-size: 1.7rem; }
h2 { font-size: 1.2rem; }
h3 { font-size: 1.02rem; }

a { color: var(--primary); text-decoration: none; }
a:hover { text-decoration: underline; }

.clinica-link-btn {
  background: none; border: none; padding: 0; margin: 0;
  color: var(--primary); font-family: var(--body); font-size: inherit; font-weight: 400;
  cursor: pointer; display: inline-flex; align-items: center; gap: 0.3rem;
}
.clinica-link-btn[hidden] { display: none; }
.clinica-link-btn:hover { text-decoration: underline; background: none; }

/* Prompt inline "Confirmar próxima sessão" (2026-08-09) - aparece logo
   depois da pílula de status virar "Realizado" pra um candidato a
   recorrência. Quebra de linha própria (display:flex + flex-basis:100%)
   pra não brigar de largura com o resto de .session-row-actions. */
.proxima-sessao-prompt {
  display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap;
  flex-basis: 100%; margin-top: 0.4rem; padding: 0.4rem 0.6rem;
  background: var(--surface-alt, rgba(122, 92, 138, 0.08)); border-radius: var(--radius-sm);
  font-size: 0.85rem;
}

button, .btn {
  font-family: var(--body);
  font-weight: 600;
  font-size: 0.95rem;
  border: none;
  border-radius: var(--radius-sm);
  padding: 0.7rem 1.3rem;
  cursor: pointer;
  background: var(--primary);
  color: #fff;
  transition: background 0.15s ease, transform 0.1s ease;
}
button:hover, .btn:hover { background: var(--primary-dark); }
button:active, .btn:active { transform: scale(0.98); }
button.btn-secondary { background: transparent; color: var(--primary); border: 1px solid var(--border); }
button.btn-secondary:hover { background: var(--bg-alt); }
/* Estado "ligado" (2026-08-08) - botão de notificações agora alterna de
   verdade entre ativar/desativar, precisa parecer visivelmente diferente
   nos dois estados. */
button.btn-secondary.is-ativo { background: var(--primary); color: #fff; border-color: var(--primary); }
button.btn-secondary.is-ativo:hover { background: var(--primary-dark); }

/* Botão "Gerar link de satisfação" (2026-08-26, pedido do cliente: "quero
   um botão bonito e animado") - gradiente sutil (primary -> accent, mesma
   dupla de cor que a marca já usa) + um brilho pulsando por trás (anel
   desfocado, ver .satisfacao-gerar-btn-glow) + um brilho que varre da
   esquerda pra direita ao passar o mouse. Discreto de propósito (clínica
   de alto padrão, pediu "bonito", não "chamativo") - a pulsação é lenta e
   o brilho de hover é rápido e sutil, nada de piscar ou saltar. */
.satisfacao-gerar-btn {
  position: relative;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  background: linear-gradient(135deg, var(--primary), var(--accent));
  color: #fff;
  isolation: isolate;
}
.satisfacao-gerar-btn svg { width: 1.05rem; height: 1.05rem; transition: transform 0.25s ease; }
.satisfacao-gerar-btn:hover svg { transform: scale(1.15) rotate(-6deg); }
.satisfacao-gerar-btn:hover { background: linear-gradient(135deg, var(--primary-dark), var(--accent)); }
.satisfacao-gerar-btn::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(115deg, transparent 40%, rgba(255,255,255,0.35) 50%, transparent 60%);
  transform: translateX(-100%);
  transition: transform 0.6s ease;
}
.satisfacao-gerar-btn:hover::after { transform: translateX(100%); }
.satisfacao-gerar-btn-glow {
  position: absolute; inset: -6px;
  border-radius: inherit;
  background: var(--accent);
  filter: blur(10px);
  opacity: 0.35;
  z-index: -1;
  animation: satisfacaoGlowPulso 2.6s ease-in-out infinite;
}
@keyframes satisfacaoGlowPulso {
  0%, 100% { opacity: 0.25; transform: scale(0.96); }
  50% { opacity: 0.5; transform: scale(1.04); }
}
@media (prefers-reduced-motion: reduce) {
  .satisfacao-gerar-btn-glow { animation: none; opacity: 0.3; }
  .satisfacao-gerar-btn::after { transition: none; }
  .satisfacao-gerar-btn:hover svg { transform: none; }
}

/* Ícone de observação da sessão - papiro (Recepção, 2026-09-10, 2ª
   iteração: "achei o chamar atenção do nosso ícone de observação muito
   sutil, fraco, achei o símbolo também meio feio... quero algo mais
   voltado pra um papiro") - substitui o texto livre que ficava sempre
   visível embaixo do nome do paciente. Parado (cinza, sem brilho) quando
   não tem observação nenhuma - só convida a clicar pra adicionar. Quando
   JÁ tem uma observação escrita (.tem-obs) balança de leve + pulsa um
   brilho dourado bem mais forte que a 1ª versão (escala maior, drop-shadow
   mais intenso) - tem que chamar atenção de verdade, não só sugerir.
   Clicar abre o popover com uma animação de "desenrolar" (ver
   .session-obs-popover abaixo e assets/sessao-observacao.js). */
.session-obs-icone {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; padding: 0; border: none; border-radius: 50%;
  background: transparent !important; color: var(--ink-dim) !important;
  opacity: 0.45; cursor: pointer; vertical-align: middle;
  transition: opacity 0.15s ease, background 0.15s ease, color 0.15s ease;
}
.session-obs-icone svg { width: 16px; height: 16px; }
.session-obs-icone:hover, .session-obs-icone:focus-visible {
  opacity: 1; background: var(--card-alt, rgba(0,0,0,0.05)) !important;
  color: var(--ink) !important;
}
.session-obs-icone.tem-obs {
  opacity: 1; color: #b8860b !important;
  animation: sessaoObsIconePulso 1.8s ease-in-out infinite;
}
@keyframes sessaoObsIconePulso {
  0%, 100% { filter: drop-shadow(0 0 0 transparent); transform: scale(1) rotate(0deg); }
  25% { transform: scale(1.05) rotate(-6deg); }
  50% { filter: drop-shadow(0 0 7px #d4a017) drop-shadow(0 0 2px #d4a017); transform: scale(1.3) rotate(6deg); }
  75% { transform: scale(1.05) rotate(-3deg); }
}
@media (prefers-reduced-motion: reduce) {
  .session-obs-icone.tem-obs { animation: none; }
}
/* Popover da observação (2ª iteração, 2026-09-10: "aqui ficou exagerado,
   acho que poderia fazer parecido com o anotações" - trocado o textarea
   + Cancelar/Salvar sempre visíveis pelo MESMO padrão view/edit do card
   de Anotações (.anotacoes-vista em paciente_perfil.php): abre em
   visualização (texto ou dica de clicar), só vira textarea quando clica
   em cima, e salva sozinho (Enter ou clicar fora) - sem botão nenhum. Só
   uma pontinha de papiro (borda + fundo levemente amarelado) pra combinar
   com o ícone nota o que é, sem pesar como a versão anterior. Continua
   "abrindo" com uma animação leve de desenrolar. */
.session-obs-popover {
  position: absolute; z-index: 30; margin-top: 0.4rem;
  width: min(240px, 90vw);
  background: var(--card);
  border: 1px solid #c9a86a; border-left: 3px solid #c9a86a; border-radius: var(--radius-sm);
  padding: 0.5rem 0.6rem; box-shadow: 0 8px 20px rgba(0,0,0,0.16);
  transform-origin: top center;
  animation: sessaoObsPopoverDesenrolar 0.22s ease-out;
}
@keyframes sessaoObsPopoverDesenrolar {
  0% { transform: scaleY(0.4); opacity: 0; }
  100% { transform: scaleY(1); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .session-obs-popover { animation: none; }
}
.session-row-info { position: relative; }
.session-obs-popover-vista {
  margin: 0; cursor: pointer; font-size: 0.85rem; color: var(--ink);
  border-radius: var(--radius-sm); padding: 0.2rem; margin: -0.2rem;
  transition: background 0.15s ease;
}
.session-obs-popover-vista:hover { background: var(--bg-alt); }
.session-obs-popover-vazia { color: var(--ink-dim); font-style: italic; }
.session-obs-popover-texto {
  width: 100%; font-family: var(--body); font-size: 0.85rem;
  padding: 0.4rem; border: 1px solid var(--border); border-radius: 4px; resize: vertical;
}

label { display: block; font-size: 0.85rem; font-weight: 600; color: var(--ink-dim); margin-bottom: 0.35rem; }
/* Tela de login aceitando CPF ou e-mail (2026-09-15) - "ou e-mail" some
   discreto ao lado do rótulo principal, sem competir com ele. */
.auth-field-ou { font-weight: 400; color: var(--ink-faint); }
input[type="text"], input[type="password"], input[type="tel"], input[type="date"], input[type="time"], input[type="email"], input[type="url"], input[type="number"], select, textarea {
  width: 100%;
  font-family: var(--body);
  font-size: 1rem;
  padding: 0.65rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--card);
  color: var(--ink);
}
input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--accent-light);
  outline-offset: 1px;
}
.field { margin-bottom: 1.1rem; }

/* Duração em Horas+Minutos (2026-08-11, pedido do cliente: campo de
   minutos cru era ruim pra "5 horas ou mais" - virou dois number inputs
   lado a lado). input[type="number"] tinha ficado de fora da regra
   compartilhada acima até agora (só text/date/time/etc.), então esses dois
   campos apareciam com o estilo cru do navegador (setinhas de
   incremento, borda diferente) destoando do resto do formulário - daí o
   "feio" reportado. Setinhas escondidas de propósito (não fazem falta pra
   digitar duração; teclado numérico normal já resolve). */
.duracao-hm { display: flex; align-items: center; gap: 0.5rem; }
.duracao-hm input[type="number"] { width: 4.5rem; text-align: center; -moz-appearance: textfield; }
.duracao-hm input[type="number"]::-webkit-outer-spin-button,
.duracao-hm input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.duracao-hm span { color: var(--ink-dim); font-size: 0.85rem; }

.form-error {
  background: #f6e3df;
  color: #7a2e22;
  border-radius: var(--radius-sm);
  padding: 0.6rem 0.9rem;
  font-size: 0.9rem;
  margin-bottom: 1rem;
}
:root[data-theme="dark"] .form-error { background: #3d2420; color: #f0a998; }

/* Aviso não-bloqueante (2026-08-26) - mesma estrutura de .form-error, cor
   âmbar em vez de vermelha: usado pro alerta de "paciente parecido com um
   bloqueado" (que ainda deixa cadastrar, ao contrário de .form-error) e
   pro selo "Bloqueado" no perfil do paciente. */
.form-warning {
  background: #f6ecd8;
  color: #7a5a1c;
  border-radius: var(--radius-sm);
  padding: 0.6rem 0.9rem;
  font-size: 0.9rem;
  margin-bottom: 1rem;
}
:root[data-theme="dark"] .form-warning { background: #3d3320; color: #e8c988; }

/* Sugestões de horário livre ao dar choque (2026-08-08, pedido do
   cliente: "a sugestão é só uma sugestão" - por isso pílulas clicáveis
   que só preenchem data/hora, nunca aplicam ou salvam sozinhas; ignorar é
   só continuar editando os campos normalmente). */
.clinica-sugestoes-horario { margin: -0.4rem 0 1rem; display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.clinica-sugestoes-horario[hidden] { display: none !important; }
.clinica-sugestoes-horario-label { font-size: 0.82rem; color: var(--ink-dim); margin-right: 0.2rem; }
/* Aviso de padrão recente (2026-09-08, item 2 dos pedidos do cliente:
   "aparecer uma msg explicando de forma divertida... dando a opção de
   forma animada") - lib/helpers.php's clinica_paciente_padrao_recente()
   + assets/calendar.js's ofertarPadraoRecente(). "Pop in" (escala +
   opacidade) em vez do fade simples de .clinica-sugestoes-horario acima
   - é uma mensagem nova chamando atenção, não uma lista de opções que já
   fazia parte da tela. [hidden] precisa do !important explícito - mesmo
   motivo de .clinica-sugestoes-horario[hidden] logo acima, um elemento
   com display: flex próprio sempre vence [hidden] sozinho. */
.padrao-recente-aviso {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem;
  margin: -0.4rem 0 1rem; padding: 0.6rem 0.9rem;
  background: color-mix(in srgb, var(--accent) 10%, var(--card));
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border));
  border-radius: var(--radius-sm);
  font-size: 0.85rem;
  animation: padraoRecentePopIn 0.35s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.padrao-recente-aviso[hidden] { display: none !important; }
@keyframes padraoRecentePopIn {
  0% { opacity: 0; transform: scale(0.92) translateY(-4px); }
  100% { opacity: 1; transform: scale(1) translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .padrao-recente-aviso { animation: none; }
}
.clinica-sugestao-pill {
  background: var(--bg-alt); color: var(--ink); border: 1px solid var(--border);
  border-radius: 999px; padding: 0.35rem 0.8rem; font-size: 0.82rem; font-weight: 600;
  cursor: pointer; font-family: var(--body);
}
.clinica-sugestao-pill:hover { border-color: var(--primary); color: var(--primary); }
/* Estado selecionado (2026-08-13, chips de duração rápida no compromisso)
   - mesma pílula, reaproveitada pra um uso ligeiramente diferente (escolha
   que PREENCHE e fica marcada, não só sugestão descartável). */
.clinica-sugestao-pill.is-ativo { background: var(--primary); border-color: var(--primary); color: #fff; }

.form-note-info {
  background: var(--bg-alt);
  color: var(--ink-dim);
  border-radius: var(--radius-sm);
  padding: 0.6rem 0.9rem;
  font-size: 0.9rem;
  margin-bottom: 1rem;
}
/* Sucesso/aviso pós-salvar (2026-08-13) - mesmo molde do .form-note-info
   acima, só troca o tom. Usado em paciente_perfil.php pra confirmar o
   salvamento e, quando aplicável, avisar que alguma sessão combinada não
   entrou na agenda por colidir com algo que já estava lá (antes esse
   aviso não existia - o retorno de clinica_gerar_ocorrencias() era
   descartado silenciosamente). */
.form-note-success { background: #e3f0e6; color: #1f5c34; }
.form-note-warning { background: #f6ecd9; color: #7a5a1f; }
:root[data-theme="dark"] .form-note-success { background: #1f3327; color: #8fd4a5; }
:root[data-theme="dark"] .form-note-warning { background: #3d3220; color: #e8c987; }

/* --- Login page (2026-09-01, redesenho pedido pelo cliente: "quero algo
   profissional, quero ver a marca imponente, quero animações") --- */
body.auth-page {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* "safe center" (2026-09-02, achado real: "não está aparecendo o botão
     pra quem não usa o sistema conhecer") - com justify-content:center
     puro, conteúdo mais alto que a tela (telas pequenas, ou depois da
     tagline/eyebrow novos) ficava com o topo cortado E inacessível -
     "safe" muda pra alinhamento no topo (scroll normal) só quando o
     conteúdo não cabe, mantém centralizado quando cabe. */
  justify-content: safe center;
  background: radial-gradient(circle at 20% 15%, var(--auth-bg-1) 0%, var(--auth-bg-2) 55%, var(--auth-bg-3) 100%);
  padding: 1.3rem 1rem;
  position: relative;
  overflow-x: hidden;
}
/* Glow ambiente, bem lento (18s) e bem sutil - dá vida ao fundo escuro
   sem competir com o card nem parecer "site de cassino". Position:fixed
   (não absolute) pra nunca crescer o scroll da página numa tela baixa. */
.auth-glow {
  position: fixed; border-radius: 50%; pointer-events: none; z-index: 0;
  filter: blur(70px); opacity: 0.35;
  animation: authGlowFloat 18s ease-in-out infinite;
}
.auth-glow-1 { width: 420px; height: 420px; background: var(--accent); top: -10%; left: -8%; }
.auth-glow-2 { width: 380px; height: 380px; background: var(--auth-glow-2); bottom: -12%; right: -6%; animation-delay: -9s; }
@keyframes authGlowFloat {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50% { transform: translate(4%, 3%) scale(1.08); }
}
/* Anel gigante atrás da marca (2026-09-02, achado real do cliente: "a
   página está sem graça") - mesmo motivo do anel do ícone do app, bem
   apagado, centralizado atrás de tudo, só textura/profundidade - respira
   bem devagar, não chama atenção pra si mesmo. */
.auth-ring {
  position: fixed; top: 50%; left: 50%; z-index: 0; pointer-events: none;
  width: min(78vw, 780px); height: min(78vw, 780px);
  transform: translate(-50%, -50%);
  border: 1.5px solid rgba(244, 239, 228, 0.14);
  border-radius: 50%;
  animation: authRingBreathe 12s ease-in-out infinite;
}
.auth-ring::before {
  content: ''; position: absolute; inset: 7%;
  border: 1px solid rgba(212, 169, 74, 0.16);
  border-radius: 50%;
}
@keyframes authRingBreathe {
  0%, 100% { opacity: 0.6; transform: translate(-50%, -50%) scale(1); }
  50% { opacity: 1; transform: translate(-50%, -50%) scale(1.015); }
}
.auth-brand {
  color: #f4efe4;
  text-align: center;
  margin-bottom: 1.3rem;
  position: relative; z-index: 1;
}
/* Entrada escalonada (2026-09-02, "precisamos de mais animações agora") -
   eyebrow, marca, nome e frase entram um de cada vez (--stagger-delay
   inline no PHP), não tudo junto de uma vez só - reforça a hierarquia em
   vez de só "a tela toda aparece". */
.auth-stagger {
  opacity: 0;
  animation: authStaggerIn 0.6s cubic-bezier(0.22, 1, 0.36, 1) var(--stagger-delay, 0s) both;
}
@keyframes authStaggerIn {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: translateY(0); }
}
/* A marca (2026-09-01, "quero ver a marca imponente") - mesmo ícone do PWA
   (assets/icons/icon-512.png), grande, com uma respiração lenta contínua
   (não é hover, é ambiente - o "imponente" pedido vem de tamanho +
   presença constante, não de ficar chamando atenção toda hora). Entrada
   é só opacidade (não translateY como as outras) - já tem a respiração
   contínua usando `transform`, as duas juntas na mesma propriedade
   brigariam (só a última da lista "ganharia" a cada instante).
*/
.auth-brand-mark {
  display: block; margin: 0 auto 0.6rem;
  border-radius: 22%;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(212, 169, 74, 0.25);
  animation: authStaggerFade 0.6s ease var(--stagger-delay, 0s) both, authMarkBreathe 5s ease-in-out 0.6s infinite;
}
@keyframes authStaggerFade {
  from { opacity: 0; }
  to { opacity: 1; }
}
/* "Sistema" acima da marca (2026-09-02) - mesmo eyebrow da logo nova
   (assets/icons), reforça "Sistema MEP" também aqui, não só no ícone.
   Espaçamento apertado 2026-09-02 (achado real: "não está aparecendo o
   botão pra quem não usa o sistema conhecer" - o CTA embaixo do card
   estava só fora da tela, ficou alto demais depois da tagline maior +
   este eyebrow novo). */
.auth-eyebrow {
  font-size: 0.75rem; font-weight: 600; letter-spacing: 0.2em; text-transform: uppercase;
  color: rgba(212, 169, 74, 0.75); margin-bottom: 0.3rem;
}
@keyframes authMarkBreathe {
  0%, 100% { transform: scale(1); box-shadow: 0 12px 40px rgba(0,0,0,0.45), 0 0 0 1px rgba(212,169,74,0.25); }
  50% { transform: scale(1.035); box-shadow: 0 16px 50px rgba(0,0,0,0.5), 0 0 0 1px rgba(212,169,74,0.4); }
}
.auth-brand-name {
  font-family: var(--display);
  font-size: 2.1rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.auth-brand-tagline {
  font-size: 0.9rem;
  color: rgba(244, 239, 228, 0.7);
  margin-top: 0.15rem;
}
.auth-card {
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);
  padding: 1.7rem 2rem;
  width: 100%;
  max-width: 380px;
  position: relative; z-index: 1;
  overflow: hidden;
  animation: authFadeUp 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.12s both;
}
/* Barra dourada no topo do card (2026-09-02, achado real do cliente: "a
   página está sem graça") - detalhe de acabamento simples, assina o card
   sem exigir nenhum elemento novo grande. Brilho passando devagar por
   cima (2026-09-02, "precisamos de mais animações agora") - faixa clara
   translúcida varrendo da esquerda pra direita, contínua e bem lenta,
   sem parecer "botão de propaganda". */
.auth-card::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 4px;
  background: linear-gradient(90deg, var(--accent) 0%, var(--accent) 35%, var(--accent-light) 50%, var(--accent) 65%, var(--accent) 100%);
  background-size: 260% 100%;
  animation: authBarShine 6s linear infinite;
  z-index: 2;
}
@keyframes authBarShine {
  0% { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}
.auth-card::after { z-index: 0; }
.auth-card { isolation: isolate; }
.auth-card .field.auth-field, .auth-card button.auth-field { position: relative; z-index: 1; }
/* Campos e botão entram em cascata, logo depois do card (2026-09-02,
   "precisamos de mais animações agora") - reaproveita o mesmo padrão de
   --stagger-delay já usado na marca acima. */
.auth-field { opacity: 0; animation: authStaggerIn 0.55s cubic-bezier(0.22, 1, 0.36, 1) both; }
.auth-field:nth-of-type(1) { animation-delay: 0.3s; }
.auth-field:nth-of-type(2) { animation-delay: 0.38s; }
.auth-field:nth-of-type(3) { animation-delay: 0.46s; }
/* Segunda rodada (2026-09-02, "ainda sinto que está sem graça") - o card
   era um retângulo branco liso sobre um fundo cheio de atmosfera, o
   contraste em si já lia como "sem graça". Textura sutil (arco dourado
   apagado no canto) + fundo levemente aquecido em vez de branco puro -
   ainda lê como "cartão claro", só para de parecer recortado do resto da
   página. */
.auth-card { background: linear-gradient(155deg, var(--card) 60%, color-mix(in srgb, var(--accent) 7%, var(--card)) 100%); }
.auth-card::after {
  content: ''; position: absolute; top: -40%; right: -30%; width: 65%; height: 65%;
  border-radius: 50%; background: radial-gradient(circle, color-mix(in srgb, var(--accent) 16%, transparent) 0%, transparent 70%);
  pointer-events: none;
  z-index: 0;
}
@keyframes authFadeUp {
  from { opacity: 0; transform: translateY(18px); }
  to { opacity: 1; transform: translateY(0); }
}
.auth-card h1 {
  position: relative; z-index: 1;
  padding-bottom: 0.7rem; margin-bottom: 1.3rem;
}
.auth-card h1::after {
  content: ''; position: absolute; left: 0; bottom: 0; width: 2.6rem; height: 3px;
  background: linear-gradient(90deg, var(--accent), transparent);
  border-radius: 2px;
}
.auth-card > * { position: relative; z-index: 1; }
.auth-card button { width: 100%; margin-top: 0.5rem; font-size: 1rem; padding: 0.8rem; transition: transform 0.15s ease, box-shadow 0.15s ease; }
.auth-card button:hover { box-shadow: 0 6px 18px rgba(47, 74, 62, 0.35); }
.auth-card button:active { transform: scale(0.98); }
/* Campos com mais presença (2026-09-02, "ainda sinto que está sem
   graça") - sombra interna sutil em vez de campo achatado igual o resto
   do app, condiz com o tom mais "joia/emblema" do resto da tela de
   login. */
.auth-card input {
  box-shadow: inset 0 1px 3px rgba(30, 20, 24, 0.08);
  transition: box-shadow 0.2s ease, border-color 0.2s ease;
}
/* Foco visível e "vivo" nos campos - respiração leve de sombra dourada
   enquanto o campo está em foco, some ao sair. */
.auth-card input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: inset 0 1px 3px rgba(30, 20, 24, 0.08), 0 0 0 3px rgba(212, 169, 74, 0.18);
}
.auth-clinica-travada {
  display: flex; align-items: center; justify-content: space-between; gap: 0.6rem;
  background: var(--bg-alt); border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 0.65rem 0.9rem; font-weight: 600; color: var(--heading);
}
.auth-clinica-travada a { font-size: 0.8rem; font-weight: 500; color: var(--ink-dim); white-space: nowrap; }
.auth-signup-cta {
  position: relative; z-index: 1;
  margin-top: 1rem; font-size: 0.88rem; color: rgba(244, 239, 228, 0.75); text-align: center;
  animation: authFadeUp 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.24s both;
}
.auth-signup-cta a { color: #f4efe4; font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }
.auth-esqueci-senha { display: block; text-align: center; margin-top: 0.9rem; font-size: 0.82rem; color: rgba(244, 239, 228, 0.6); text-decoration: none; }
.auth-esqueci-senha:hover { color: #f4efe4; text-decoration: underline; }
/* Seletor de clínica (2026-09-01, pedido do cliente: "aparecer em botões
   animados as escolhas que ela tem para logar") - cada opção entra em
   cascata (--delay por item, definido inline no PHP) em vez de tudo junto,
   reforça que são opções distintas, não uma lista estática. */
.auth-picker-sub { color: var(--ink-dim); font-size: 0.9rem; margin-top: -0.4rem; margin-bottom: 1.2rem; }
.auth-picker-lista { display: flex; flex-direction: column; gap: 0.7rem; }
.auth-picker-item {
  margin: 0;
  animation: authFadeUp 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: calc(0.15s + var(--delay, 0s));
}
.auth-picker-item button {
  width: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 0.2rem;
  background: var(--bg-alt); border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 0.85rem 1rem; text-align: left; cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.auth-picker-item button:hover { border-color: var(--accent); box-shadow: 0 6px 18px rgba(47, 74, 62, 0.15); transform: translateY(-1px); }
.auth-picker-item button:active { transform: scale(0.98); }
.auth-picker-clinica { font-weight: 600; color: var(--heading); }
.auth-picker-user { font-size: 0.82rem; color: var(--ink-dim); }
.auth-picker-voltar {
  display: block; text-align: center; margin-top: 1.1rem;
  font-size: 0.85rem; font-weight: 500; color: var(--ink-dim); text-decoration: none;
}
.auth-picker-voltar:hover { color: var(--heading); text-decoration: underline; }
@media (prefers-reduced-motion: reduce) {
  .auth-glow, .auth-ring { animation: none; }
  .auth-brand-mark { animation: none; }
  .auth-picker-item { animation: none; opacity: 1; transform: none; }
  .auth-brand, .auth-card, .auth-signup-cta { animation: none; opacity: 1; transform: none; }
  .auth-stagger, .auth-field, .auth-card::before { animation: none; opacity: 1; transform: none; }
}

/* Busca de clínica no login (2026-08-06) - dropdown próprio em JS, não
   <datalist> nativo: Safari no iPhone praticamente não exibe sugestões de
   datalist, então a lista nunca aparecia no celular real do cliente. */
.clinica-busca-wrap { position: relative; }
.clinica-busca-lista {
  display: none;
  position: absolute; top: calc(100% + 0.3rem); left: 0; right: 0; z-index: 30;
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-sm);
  box-shadow: var(--shadow); max-height: 220px; overflow-y: auto; padding: 0.3rem;
}
.clinica-busca-lista.aberta { display: block; }
.clinica-busca-item {
  padding: 0.55rem 0.7rem; border-radius: var(--radius-sm); cursor: pointer;
  font-size: 0.9rem; color: var(--ink);
}
.clinica-busca-item:hover { background: var(--bg-alt); }
.clinica-busca-sem-resultado { padding: 0.55rem 0.7rem; font-size: 0.85rem; color: var(--ink-dim); }

/* --- Nav --- */
.clinica-nav {
  display: flex;
  align-items: center;
  gap: 2rem;
  padding: 1rem 2rem;
  background: var(--card);
  border-bottom: 1px solid var(--border);
}
.clinica-nav-brand { font-size: 1.3rem; }
.clinica-nav-brand-wrap { display: inline-flex; align-items: center; gap: 0.35rem; }
.clinica-nav-sobre-btn {
  width: 18px; height: 18px; border-radius: 50%; border: 1px solid var(--ink-faint);
  background: none; color: var(--ink-faint); font-size: 0.7rem; font-weight: 700;
  line-height: 1; display: inline-flex; align-items: center; justify-content: center;
  padding: 0; cursor: pointer;
}
.clinica-nav-sobre-btn:hover { color: var(--primary); border-color: var(--primary); }
.clinica-nav-links { display: flex; gap: 1.5rem; flex: 1; flex-wrap: wrap; row-gap: 0.4rem; }
/* white-space:nowrap (2026-08-10, achado real) - sem isso, quando o menu
   fica apertado (10 abas agora, com a nova "Pendências") o texto de UM
   item quebra sozinho no meio, deixando o número do nav-badge numa
   segunda linha isolada em vez de ficar ao lado do texto. flex-wrap no
   container pai acima é o lugar certo pra "sobrar" espaço - entre itens
   inteiros, nunca dentro de um item só. */
.clinica-nav-links a { color: var(--ink-dim); font-weight: 600; padding: 0.3rem 0; border-bottom: 2px solid transparent; white-space: nowrap; }
.clinica-nav-links a:hover, .clinica-nav-links a.is-active { color: var(--heading); border-bottom-color: var(--accent); text-decoration: none; }
.nav-badge {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--danger); color: #fff; font-size: 0.7rem; font-weight: 800;
  border-radius: 999px; min-width: 1.1rem; height: 1.1rem; padding: 0 0.3rem;
  margin-left: 0.3rem; vertical-align: middle;
}
/* Badge miniatura da sidebar recolhida (2026-09-02) - escondido por
   padrão SEMPRE (achado real do cliente: "as pendências mostram números
   duplicados" - a regra de escondê-la só existia dentro do
   @media (min-width:1301px), então em telas menores ela aparecia sem
   nada escondendo, duplicando o número junto do badge normal do texto).
   Só reaparece dentro do bloco de sidebar recolhida, mais abaixo. */
.clinica-nav-badge-recolhida { display: none; }
.clinica-nav-user { display: flex; align-items: center; gap: 1rem; font-size: 0.9rem; color: var(--ink-dim); }
/* Tema + cor sempre lado a lado (2026-09-02, "não gostei das bolinhas
   ficarem uma debaixo da outra na tela reduzida") - base sempre-ativa,
   vale em qualquer largura de tela; só no desktop com a sidebar recolhida
   (ver @media min-width:1301px mais abaixo) é que empilha. */
.clinica-nav-toggles-row { display: flex; flex-direction: row; gap: 0.5rem; }
.clinica-nav-avatar-link { display: flex; align-items: center; gap: 0.5rem; color: var(--ink-dim); }
.clinica-nav-avatar-link:hover { text-decoration: none; color: var(--heading); }

.clinica-avatar-wrap { display: inline-flex; position: relative; flex: 0 0 auto; }
.clinica-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; overflow: hidden; flex: 0 0 auto;
}
.clinica-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.clinica-avatar-fallback { color: #fff; font-weight: 800; font-size: 0.75em; }

/* Bolinha de presença - sempre visível (vermelha = offline por padrão),
   assets/presenca.js liga .is-online (verde) via polling de
   api/presenca-status.php assim que confirma o heartbeat de cada um.
   Fica no wrapper, fora do .clinica-avatar (que tem overflow:hidden pra
   recortar foto/iniciais em círculo - dentro dele a bolinha ficava cortada
   e nunca aparecia, mesmo com a pessoa online). */
.clinica-avatar-wrap[data-presence-user]::after {
  content: ""; position: absolute; right: -1px; bottom: -1px;
  width: 32%; height: 32%; min-width: 8px; min-height: 8px;
  /* Cinza neutro, não vermelho - achado real do cliente (2026-08-18): a
     paleta de cor por profissional (CLINICA_PALETA_CORES em lib/helpers.php)
     tem vários tons avermelhados, e "offline" em vermelho ficava
     confundível com a própria cor de identidade de quem tem avatar sem
     foto. Verde continua reservado só pra "online". */
  background: #9a9188; border-radius: 50%;
  border: 2px solid var(--surface, #fff); z-index: 1;
}
.clinica-avatar-wrap[data-presence-user].is-online::after {
  background: var(--success, #2f9e6b);
}

.clinica-avatar-wrap[data-presence-user] { cursor: pointer; }

/* Pastilha "Equipe" da Recepção - abre um dropdown com toda a equipe
   (online e offline, api/chat-equipe-lista.php) que leva pro mini-chat
   flutuante (assets/chat-mini.js) sem sair da página. A conversa completa
   (histórico, emoji, apagar) mora em conversas.php?aba=equipe - o
   dropdown/mini-chat são só o atalho rápido. */
.clinica-equipe-pill-wrap { position: relative; }
.clinica-equipe-pill {
  display: inline-flex; align-items: center; gap: 0.5rem;
  background: rgba(255,255,255,0.12); border: 1px solid rgba(255,255,255,0.22);
  border-radius: 999px; padding: 0.4rem 0.9rem 0.4rem 0.5rem;
  color: #fff; font-size: 0.82rem; font-weight: 600; cursor: pointer;
  position: relative; transition: background 0.15s; font-family: inherit;
}
.clinica-equipe-pill:hover { background: rgba(255,255,255,0.2); }
.clinica-equipe-pill-avatares { display: flex; }
.clinica-equipe-pill-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%;
  color: #fff; font-weight: 800; font-size: 0.65rem;
  border: 2px solid var(--primary-dark, #1f3529); margin-left: -8px;
}
.clinica-equipe-pill-avatar:first-child { margin-left: 0; }
.clinica-equipe-pill-mais { background: rgba(255,255,255,0.3); }
.clinica-equipe-pill-badge {
  position: absolute; top: -6px; right: -6px; min-width: 17px; height: 17px;
  border-radius: 999px; background: var(--danger, #c0392b); color: #fff;
  font-size: 0.65rem; font-weight: 800; display: flex; align-items: center;
  justify-content: center; padding: 0 4px; border: 2px solid var(--primary-dark, #1f3529);
}

.clinica-equipe-pill-dropdown {
  position: absolute; top: calc(100% + 8px); left: 0; z-index: 40;
  background: var(--surface, var(--card, #fff)); border: 1px solid var(--border);
  border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,0.18);
  min-width: 220px; max-height: 300px; overflow-y: auto; padding: 0.4rem;
  color: var(--ink);
}
.clinica-equipe-pill-dropdown[hidden] { display: none; }
.clinica-equipe-pill-dropdown-carregando { padding: 0.6rem; font-size: 0.85rem; color: var(--ink-dim); }
.clinica-equipe-online-dropdown-item {
  display: flex; align-items: center; gap: 0.5rem; width: 100%;
  padding: 0.5rem 0.55rem; border: none; background: transparent;
  border-radius: 8px; cursor: pointer; text-align: left; font-size: 0.85rem;
  color: var(--ink, inherit); font-family: inherit;
}
.clinica-equipe-online-dropdown-item:hover { background: var(--bg-alt, rgba(0,0,0,0.05)); }
.clinica-equipe-online-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 50%; color: #fff;
  font-weight: 800; font-size: 0.7rem; flex: 0 0 auto; position: relative;
}
.clinica-equipe-online-avatar[data-presence-dot]::after {
  content: ""; position: absolute; right: -1px; bottom: -1px;
  width: 9px; height: 9px; background: #9a9188; border-radius: 50%;
  border: 2px solid var(--surface, var(--card, #fff));
}
.clinica-equipe-online-avatar[data-presence-dot].is-online::after { background: var(--success, #2f9e6b); }
.clinica-equipe-online-badge {
  margin-left: auto; min-width: 17px; height: 17px; border-radius: 999px;
  background: var(--danger, #c0392b); color: #fff; font-size: 0.65rem; font-weight: 800;
  display: flex; align-items: center; justify-content: center; padding: 0 4px;
}

/* Mini-chat flutuante - vive em partials/nav.php (presente em toda página
   logada), aberto por assets/chat-mini.js ao clicar em qualquer avatar do
   sistema ou num item do dropdown acima. */
.clinica-mini-chat {
  position: fixed; bottom: 0; right: 24px; width: 300px; height: 400px;
  max-height: 70vh; background: var(--card, #fff); border: 1px solid var(--border);
  border-bottom: none; border-radius: 12px 12px 0 0; box-shadow: 0 -8px 24px rgba(0,0,0,0.2);
  display: flex; flex-direction: column; z-index: 60;
}
.clinica-mini-chat[hidden] { display: none; }
@media (max-width: 480px) {
  .clinica-mini-chat { right: 0; left: 0; width: auto; }
}
.clinica-mini-chat-topo {
  display: flex; align-items: center; gap: 0.5rem; padding: 0.6rem 0.8rem;
  border-bottom: 1px solid var(--border); border-radius: 12px 12px 0 0;
  background: var(--bg-alt, rgba(0,0,0,0.03));
}
.clinica-mini-chat-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 50%; color: #fff;
  font-weight: 800; font-size: 0.7rem; flex: 0 0 auto;
}
.clinica-mini-chat-nome { font-weight: 700; font-size: 0.9rem; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.clinica-mini-chat-expandir, .clinica-mini-chat-fechar {
  background: transparent; border: none; cursor: pointer; color: var(--ink-dim);
  display: inline-flex; align-items: center; justify-content: center; padding: 0.2rem;
}
.clinica-mini-chat-expandir-icon { width: 15px; height: 15px; transform: rotate(45deg); }
.clinica-mini-chat-fechar { font-size: 1.3rem; line-height: 1; }
.clinica-mini-chat-status {
  flex: 0 0 auto; padding: 0.15rem 0.8rem 0.4rem; font-size: 0.72rem; color: var(--ink-dim);
  min-height: 1em;
}
.clinica-mini-chat-status.is-digitando { color: var(--primary); font-style: italic; }
.clinica-mini-chat-mensagens {
  flex: 1; overflow-y: auto; padding: 0.6rem 0.7rem; display: flex;
  flex-direction: column; gap: 0.35rem;
}
.clinica-mini-chat-vazio { color: var(--ink-dim); font-size: 0.8rem; text-align: center; margin: auto; }
.clinica-mini-chat-msg {
  max-width: 78%; padding: 0.4rem 0.6rem; border-radius: 10px; font-size: 0.85rem;
  word-break: break-word; position: relative;
}
.clinica-mini-chat-msg.enviada { align-self: flex-end; background: var(--primary); color: #fff; }
.clinica-mini-chat-msg.recebida { align-self: flex-start; background: var(--bg-alt, rgba(0,0,0,0.06)); }
.clinica-mini-chat-apagar, .clinica-mini-chat-editar {
  position: absolute; top: -7px; width: 17px; height: 17px;
  border-radius: 50%; border: none; color: #fff; font-size: 0.75rem; line-height: 1;
  cursor: pointer; display: none; align-items: center; justify-content: center; padding: 0;
}
.clinica-mini-chat-apagar { left: -7px; background: var(--danger, #c0392b); }
.clinica-mini-chat-editar { left: 13px; background: var(--ink-dim, #888); }
.clinica-mini-chat-msg.enviada:hover .clinica-mini-chat-apagar,
.clinica-mini-chat-msg.enviada:hover .clinica-mini-chat-editar { display: flex; }
.clinica-mini-chat-msg-hora { display: block; font-size: 0.65rem; opacity: 0.75; margin-top: 0.15rem; }
.clinica-mini-chat-anexo-imagem { display: block; margin-bottom: 0.3rem; }
.clinica-mini-chat-anexo-imagem img { max-width: 160px; max-height: 160px; border-radius: 8px; display: block; }
.clinica-mini-chat-anexo-arquivo {
  display: flex; align-items: center; gap: 0.35rem; padding: 0.35rem 0.5rem;
  background: rgba(0,0,0,0.08); border-radius: 8px; margin-bottom: 0.3rem;
  font-size: 0.78rem; color: inherit; text-decoration: none; word-break: break-all;
}
.clinica-mini-chat-form {
  display: flex; gap: 0.4rem; padding: 0.5rem; border-top: 1px solid var(--border);
}
.clinica-mini-chat-anexo-btn {
  background: none; border: none; font-size: 1.1rem; line-height: 1; cursor: pointer;
  padding: 0.4rem; border-radius: 50%; flex: 0 0 auto; align-self: flex-end;
}
.clinica-mini-chat-anexo-btn:hover { background: var(--bg-alt); }
.clinica-mini-chat-form textarea {
  flex: 1; resize: none; border: 1px solid var(--border); border-radius: 8px;
  padding: 0.4rem 0.5rem; font: inherit; font-size: 0.85rem; max-height: 80px;
  background: var(--bg); color: var(--ink);
}
.clinica-mini-chat-form button {
  border: none; background: var(--primary-dark, #2f4a3e); color: #fff; border-radius: 8px;
  width: 34px; flex: 0 0 auto; cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.clinica-mini-chat-form button svg { width: 16px; height: 16px; transform: rotate(90deg); }

.clinica-icon-btn {
  background: transparent; border: 1px solid var(--border); border-radius: 50%;
  width: 2.1rem; height: 2.1rem; padding: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--ink-dim);
}
.clinica-icon-btn:hover { background: var(--bg-alt); }
.clinica-icon-btn .icon-lua { display: none; }
:root[data-theme="dark"] .clinica-icon-btn .icon-sol { display: none; }
:root[data-theme="dark"] .clinica-icon-btn .icon-lua { display: flex; }

/* Bolinha do botão de cor (2026-09-02) - metade vinho, metade floresta,
   sempre as DUAS cores fixas (não var(--accent), que mudaria com o tema
   ativo - o botão precisa mostrar a opção OUTRA, não a que já está
   ligada, senão parece que não faz nada). */
.clinica-cor-swatch {
  width: 1.1rem; height: 1.1rem; border-radius: 50%; display: block;
  background: linear-gradient(135deg, #7a2f3f 0%, #7a2f3f 50%, #2f4a3e 50%, #2f4a3e 100%);
  border: 1px solid rgba(0,0,0,0.15);
}

.clinica-page { max-width: 1100px; margin: 0 auto; padding: 2rem; }
/* Agenda especificamente precisa de mais espaço (2026-08-14, achado real:
   cliente numa tela larga o bastante pra caber segunda-sexta inteiras na
   visão Semana, mas o limite genérico de 1100px forçava rolagem/corte de
   qualquer forma, mesmo sobrando tela). Não é max-width:none como
   .clinica-page-full (isso é pra layout tipo chat, altura de viewport
   inteira) - só um teto mais alto, ainda com respiro nas laterais em
   monitores muito largos. */
.clinica-page-wide { max-width: 1400px; }

/* --- Reception --- */
.reception-hero {
  background:
    radial-gradient(circle at 88% -10%, rgba(255,255,255,0.10) 0%, transparent 45%),
    linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
  color: #f4efe4;
  border-radius: var(--radius);
  padding: 2.2rem 2rem;
  margin-bottom: 2rem;
  position: relative;
  overflow: visible;
}
.reception-hero h1 { color: #fff; font-size: 1.9rem; }
.reception-hero p { color: rgba(244, 239, 228, 0.8); margin-top: 0.4rem; }

.reception-hero .clinica-equipe-pill-wrap { position: absolute; top: 1.3rem; right: 1.6rem; }
@media (max-width: 640px) {
  .reception-hero .clinica-equipe-pill-wrap { position: static; margin-bottom: 1rem; }
}

/* Estatísticas da saudação, como chips em vez de frase corrida (2026-08-09,
   pedido do cliente: "quantidade de pacientes cadastrados" precisava de um
   lugar melhor que uma linha de texto solta). O total de pacientes vira um
   link pra pacientes.php - é o único dos três que faz sentido navegar a
   partir daqui. */
.reception-hero-stats { display: flex; gap: 2.2rem; flex-wrap: wrap; margin-top: 1.1rem; }
.reception-stat { text-decoration: none; }
a.reception-stat:hover .reception-stat-num { text-decoration: underline; }
.reception-stat-num {
  font-family: var(--display); font-size: 1.8rem; font-weight: 700;
  color: #fff; line-height: 1.1;
}
.reception-stat-label { font-size: 0.82rem; color: rgba(244, 239, 228, 0.75); margin-top: 0.2rem; }

.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 1.5rem;
}
.card + .card { margin-top: 1.5rem; }

.session-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.8rem 0.6rem;
  margin: 0 -0.6rem;
  border-bottom: 1px solid var(--border);
  border-radius: var(--radius-sm);
  transition: background 0.15s ease, transform 0.15s ease;
}
.session-row:last-child { border-bottom: none; }

/* Pendências (2026-08-10, redesenhado no mesmo dia depois de feedback real
   do cliente: "formatação feia", "difícil de editar") - fileira única de
   "chips" do mesmo tamanho visual (responsável/categoria/prazo/paciente),
   em vez do <select> nativo solto numa linha própria de antes. */
.pendencia-item {
  padding: 0.7rem 0.9rem; border-radius: var(--radius-sm);
  background: var(--bg-alt); border: 1px solid var(--border); border-left: 3px solid var(--border);
}
.pendencia-item-topo { display: flex; justify-content: space-between; align-items: flex-start; gap: 0.6rem; }
.pendencia-item-topo .pendencia-texto { text-align: left; font-weight: 600; color: var(--heading); flex: 1; min-width: 0; }
.pendencia-item-acoes { display: flex; gap: 0.3rem; flex: 0 0 auto; }
.pendencia-item-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; margin-top: 0.5rem; }

/* Pendência "Quero nota fiscal" (2026-09-01) - precisa "chamar mais
   atenção que as outras" na lista (pedido explícito do cliente), mas sem
   virar irritante - pulsação lenta na borda + leve resplandor, mesma
   família visual/velocidade de .satisfacao-gerar-btn-glow (a clínica já
   pediu "bonito", não "chamativo" nesse outro botão - reaproveita o mesmo
   bom senso aqui). border-left-color inline (definida em PHP por
   atrasada/urgente) continua funcionando por baixo; isso só soma um selo
   por cima.*/
.pendencia-item-notafiscal {
  position: relative;
  border-left-width: 4px;
  animation: pendenciaNotaFiscalPulso 2.2s ease-in-out infinite;
}
@keyframes pendenciaNotaFiscalPulso {
  0%, 100% { box-shadow: 0 0 0 0 rgba(176, 138, 62, 0.35); }
  50% { box-shadow: 0 0 0 5px rgba(176, 138, 62, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .pendencia-item-notafiscal {
    animation: none;
    box-shadow: 0 0 0 2px rgba(176, 138, 62, 0.35);
  }
}

/* "Pacote concluído" (2026-09-03, pedido do cliente: "tem como fazer algo
   animado ai?") - só dispara UMA VEZ ao carregar a tela (não fica pulsando
   pra sempre feito alerta - isso já é uma boa notícia, não uma pendência),
   um pequeno "pop" com leve estouro (cubic-bezier com overshoot) simulando
   confete se assentando. Ver paciente_historico.php. */
.perfil-pacote-concluido {
  display: inline-block;
  animation: perfilPacoteConcluidoPop 0.7s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
@keyframes perfilPacoteConcluidoPop {
  0% { transform: scale(0.5) rotate(-8deg); opacity: 0; }
  60% { transform: scale(1.12) rotate(3deg); opacity: 1; }
  100% { transform: scale(1) rotate(0); }
}
@media (prefers-reduced-motion: reduce) {
  .perfil-pacote-concluido { animation: none; }
}

.pendencia-chip {
  display: inline-flex; align-items: center;
  font-size: 0.78rem; font-family: var(--body); color: var(--ink-dim);
  padding: 0.2rem 0.55rem; border-radius: 999px;
  background: var(--card); border: 1px solid var(--border);
  cursor: pointer; max-width: 220px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
select.pendencia-chip { padding-right: 1.4rem; } /* espaço pra seta nativa do select não cortar o texto */
.pendencia-chip:hover { background: var(--bg-alt); text-decoration: none; }
a.pendencia-chip { color: var(--ink); }

.pendencia-paciente-wrap { display: inline-flex; align-items: center; gap: 0.2rem; }
.pendencia-paciente-remover {
  width: 1.1rem; height: 1.1rem; border-radius: 50%; border: none; background: none;
  color: var(--ink-faint); cursor: pointer; font-size: 0.7rem; display: inline-flex; align-items: center; justify-content: center;
}
.pendencia-paciente-remover:hover { background: var(--danger); color: #fff; }

/* Campo/busca que substitui um chip durante edição inline - mesma altura/
   fonte do chip que ele troca de lugar, pra não "pular" o layout. */
.pendencia-chip-input { font-size: 0.82rem; padding: 0.2rem 0.5rem; border-radius: var(--radius-sm); min-width: 160px; }
.pendencia-paciente-busca-wrap { position: relative; display: inline-block; }
a.session-row:hover, .session-row:has(a:hover) { background: var(--bg-alt); }
a.session-row:hover { transform: translateX(2px); }
@media (prefers-reduced-motion: reduce) { .session-row { transition: none; } a.session-row:hover { transform: none; } }
.session-time { font-weight: 700; color: var(--heading); min-width: 5.5rem; font-variant-numeric: tabular-nums; }
.session-patient { font-weight: 600; }
.session-notes { color: var(--ink-dim); font-size: 0.85rem; }
/* Achado real 2026-08-05 (screenshot do celular do cliente): o nome do
   paciente ficava numa <div> comum sem flex:1/min-width:0 dentro de
   .session-row - sem isso, um flex item só encolhe até o tamanho do seu
   conteúdo (min-width:auto por padrão), então um nome comprido empurrava
   o status-pill/ações pra fora da tela em vez de dividir o espaço
   direito. .session-row-info agora é a classe padrão pra essa coluna em
   index.php/pacientes.php (era inline style="flex:1" inconsistente antes
   - só pacientes.php tinha, index.php não tinha nenhum). */
.session-row-info { flex: 1 1 140px; min-width: 0; }
.session-row-actions { display: flex; align-items: center; gap: 0.9rem; font-size: 0.9rem; flex: 0 0 auto; }

.status-pill {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 700;
  padding: 0.25rem 0.7rem;
  border-radius: 999px;
  color: #fff;
  white-space: nowrap;
}

/* Pílula de status clicável (assets/status-pill.js) - pedido do cliente
   2026-08-05, "clicar no pendente e poder alterar pra realizado". O botão
   herda toda a aparência de .status-pill (mesmo bloco acima) e só some o
   reset nativo de <button>; o dropdown reaproveita o mesmo visual já
   estabelecido em .conversas-menu-dropdown (ver mais abaixo) em vez de
   inventar um estilo novo. */
.status-pill-wrap { position: relative; display: inline-block; }
.status-pill-btn { border: none; cursor: pointer; font-family: var(--body); }
.status-pill-btn:hover { filter: brightness(1.08); }
.status-pill-btn:disabled { opacity: 0.6; cursor: wait; }
.status-pill-dropdown {
  position: absolute; top: calc(100% + 0.4rem); left: 0; z-index: 20;
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-sm);
  box-shadow: var(--shadow); min-width: 160px; padding: 0.35rem;
  display: flex; flex-direction: column; gap: 0.15rem;
}
.status-pill-dropdown button {
  display: block; width: 100%; text-align: left; border: none; background: none;
  padding: 0.5rem 0.6rem; border-radius: var(--radius-sm);
  color: var(--ink); font-size: 0.85rem; font-weight: 600; font-family: var(--body); cursor: pointer;
}
.status-pill-dropdown button:hover { background: var(--bg-alt); }
/* Achado real (2026-08-06) - dropdown de sessão perto do fim da lista
   nascia parcialmente fora da tela (sempre abria pra baixo). Classe
   adicionada via JS (status-pill.js, ajustarPosicaoDropdown()) depois de
   medir a posição real do menu já no DOM. */
.status-pill-dropdown.abre-para-cima { top: auto; bottom: calc(100% + 0.4rem); }

/* Campos clicáveis do Histórico (assets/status-pill.js, 2026-08-05) -
   profissional e observações editáveis direto na linha, mesmo espírito
   das pílulas de status/pagamento. */
.pfield-btn {
  display: block; width: 100%; text-align: left; background: none; border: none; padding: 0.1rem 0.3rem;
  margin: 0 -0.3rem; border-radius: var(--radius-sm); color: inherit; font-family: var(--body);
  font-size: 0.85rem; color: var(--ink-dim); cursor: pointer;
}
.pfield-btn:hover { background: var(--bg-alt); }
.pfield-btn[data-campo="observacoes"]:empty::before,
.pfield-obs { font-style: normal; }
.pfield-editando { display: flex; flex-direction: column; gap: 0.4rem; }
.pfield-editando textarea {
  width: 100%; padding: 0.4rem 0.6rem; border-radius: var(--radius-sm); border: 1px solid var(--border);
  background: var(--bg); color: var(--ink); font-family: var(--body); font-size: 0.85rem; resize: vertical;
}
.pfield-editando-acoes { display: flex; gap: 0.5rem; }
.pfield-editando-acoes button { padding: 0.3rem 0.7rem; font-size: 0.8rem; }

.empty-state { color: var(--ink-dim); text-align: center; padding: 2rem 0; }
.empty-state svg { width: 30px; height: 30px; opacity: 0.6; }
.empty-state svg.empty-illustration { width: 64px; height: 64px; opacity: 0.9; stroke-width: 1.6; }

.pendencia-badges { display: inline-flex; gap: 0.3rem; margin-left: 0.5rem; vertical-align: middle; }
/* Vira <a> quando tem pra onde levar (2026-08-05, "seria legal poder
   clicar neles e levar direto pra informação pendente") - sem sublinhado/
   cor de link padrão, o ícone colorido já é o próprio indicador visual. */
.pendencia-badge { display: inline-flex; border-radius: 4px; }
.pendencia-badge:hover { background: var(--bg-alt); text-decoration: none; }
.pendencia-badge svg { width: 16px; height: 16px; }

/* "Medalhas" de pacotes concluídos (2026-09-08, pedido do cliente:
   "quando esse paciente contratar o próximo pacote, eu quero que
   continue indicando esse primeiro pacote concluído... sem poluição
   visual como uma medalha, essa conquista para cada pacote") - selo
   compacto e discreto, uma medalha por pacote (até 3, depois vira
   "🏅 ×N" pra não crescer sem limite numa lista de paciente antigo).
   Ver bloco "Já concluiu N pacotes" em paciente_historico.php. */
.pacotes-medalhas { display: inline-flex; align-items: center; gap: 0.15rem; padding: 0.15rem 0.5rem; border-radius: 999px; background: color-mix(in srgb, var(--success) 12%, transparent); font-size: 0.82rem; }
.pacotes-medalhas .medalha-icone { font-size: 0.9rem; }

/* Selo "Alta frequência" (2026-09-08, pedido do cliente: "com animação
   legal") - clinica_alta_frequencia_html() em lib/helpers.php. Diferente
   dos outros .pendencia-badge (só ícone), este tem texto também, então
   ganha seu próprio padding/fundo em vez de herdar o ícone-só. Pulso
   sutil no box-shadow (mesmo espírito de @keyframes satisfacaoGlowPulso
   logo acima) - celebra sem competir visualmente com um alerta de
   pendência de verdade (dinheiro/pagamento continuam mais chamativos). */
.alta-frequencia-badge {
  padding: 0.15rem 0.55rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--success);
  background: color-mix(in srgb, var(--success) 12%, transparent);
  animation: altaFrequenciaPulso 2.8s ease-in-out infinite;
}
@keyframes altaFrequenciaPulso {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--success) 35%, transparent); }
  50% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--success) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .alta-frequencia-badge { animation: none; }
}

/* Selo "De férias" (2026-09-08, item 3 dos pedidos do cliente: "com
   animação") - clinica_paciente_ferias_html() em lib/helpers.php. Mesmo
   tratamento do selo de alta frequência acima (próprio padding/fundo +
   pulso no box-shadow), cor diferente (--status-cancelado, um teal calmo
   - "pausado", não "urgente" nem "comemorando") pra nunca ser confundido
   com os outros dois selos coloridos que já existem nesta mesma linha
   (aniversário em --accent, alta frequência em --success). */
.ferias-badge {
  padding: 0.15rem 0.55rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--status-cancelado);
  background: color-mix(in srgb, var(--status-cancelado) 12%, transparent);
  animation: feriasPulso 3.4s ease-in-out infinite;
}
@keyframes feriasPulso {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--status-cancelado) 30%, transparent); }
  50% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--status-cancelado) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .ferias-badge { animation: none; }
}

/* Legenda (2026-08-05, "falta uma legenda pra dizer o que eles
   significam") - lib/helpers.php's clinica_pendencias_legenda_html(). */
.pendencia-legenda {
  display: flex; flex-wrap: wrap; gap: 1rem;
  font-size: 0.78rem; color: var(--ink-dim);
  padding: 0.6rem 0.8rem; margin-bottom: 1rem;
  background: var(--bg-alt); border-radius: var(--radius-sm);
}
.pendencia-legenda-item { display: inline-flex; align-items: center; gap: 0.35rem; }
.pendencia-legenda-item svg { width: 15px; height: 15px; flex: 0 0 auto; }

.money-pill {
  display: inline-block; font-size: 0.72rem; font-weight: 700;
  padding: 0.2rem 0.6rem; border-radius: 999px; white-space: nowrap;
  border: 1px solid; margin-left: 0.5rem;
}
.money-pill.is-pago { color: var(--success); border-color: var(--success); }
.money-pill.is-pendente { color: var(--danger); border-color: var(--danger); }
/* "A realizar" (2026-09-10) - mesma situação de "A receber" (ainda não
   marcada paga), mas já coberta por saldo/crédito do paciente (pacote
   pago adiantado) - cor neutra (primary), não vermelha, pra não parecer
   dívida em aberto quando o dinheiro já está garantido. */
.money-pill.is-coberto { color: var(--primary); border-color: var(--primary); }

/* Progresso de pacote em "barrinha de loading" (2026-09-10, pedido do
   mestre pra lista Hoje/Próximos dias) - substitui a pílula colorida que
   ficava pesada demais numa lista com várias linhas. O brilho que varre
   dentro do preenchido é decoração (reforça "em andamento"), some com
   prefers-reduced-motion. */
.restantes-loading { display: inline-flex; align-items: center; gap: 0.35rem; vertical-align: middle; margin-left: 0.4rem; }
.restantes-loading-track {
  width: 46px; height: 6px; border-radius: 999px; overflow: hidden;
  background: var(--border); position: relative;
}
.restantes-loading-fill {
  display: block; height: 100%; border-radius: 999px;
  transition: width 0.4s ease; position: relative; overflow: hidden;
}
.restantes-loading-fill::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(100deg, transparent 30%, rgba(255,255,255,0.55) 50%, transparent 70%);
  transform: translateX(-100%);
  animation: restantesLoadingVarre 2.2s ease-in-out infinite;
}
@keyframes restantesLoadingVarre {
  0% { transform: translateX(-100%); }
  60%, 100% { transform: translateX(200%); }
}
.restantes-loading-label { font-size: 0.72rem; font-weight: 700; color: var(--ink-dim); }
@media (prefers-reduced-motion: reduce) {
  .restantes-loading-fill::after { animation: none; }
}
/* "Cortesia" (2026-09-02, pedido do cliente) - sessão sem valor cobrado
   mas não paga; cor neutra (nem "sucesso" nem "pendência", pra não parecer
   um problema) e clicável quando dá pra corrigir o valor. min-width
   (achado do cliente: "o tamanho da pirula que estava pequeno" - texto
   curto ("Cortesia") deixava a pílula visualmente menor que "Pago"/"A
   receber · R$ x,xx" ao lado) - 8.7rem medido de verdade (Chrome headless,
   fonte Manrope real, box-sizing:border-box igual ao site) contra "A
   receber · R$ 350,00" (137px) e "Pago · R$ 375,00 · Pix" (140px) - não
   chute, é a média exata das duas medidas reais. */
.money-pill.is-cortesia { min-width: 8.7rem; text-align: center; }
.money-pill.is-cortesia { color: var(--ink-dim); border-color: var(--border); }
.money-pill-cortesia-btn { cursor: pointer; font-family: var(--body); background: none; }
.money-pill-cortesia-btn:hover { background: var(--bg-alt); }
.money-pill-cortesia-btn:disabled { opacity: 0.5; cursor: wait; }
/* "Cancelado sem cobrança" (2026-09-02) - mesmo esquecimento de sempre:
   virar <button> herda o "background: var(--primary); color: #fff" da
   regra global de botão (linha ~184) por cima da cor/borda neutra que
   .is-cortesia já define - ficava um preenchido vinho ilegível em vez do
   outline neutro. background:none resolve, mesma correção já feita pras
   outras pirulas-botão. */
.money-pill-cancelado-cobrar-btn { cursor: pointer; font-family: var(--body); background: none; }
.money-pill-cancelado-cobrar-btn:hover { background: var(--bg-alt); }
.money-pill-cancelado-cobrar-btn:disabled { opacity: 0.5; cursor: wait; }
/* "A receber" clicável (2026-08-05) - substitui o antigo .marcar-pago-btn
   isolado (só existia em paciente_historico.php) por essa mesma pílula
   virando botão, igual .status-pill-btn já faz.
   Bug real (achado pelo cliente, print no celular): virar <button> herdou
   o "background: var(--primary)" da regra global de botão (linha ~91) por
   baixo do texto/borda vermelha - a pílula ficava verde com texto vermelho
   em vez do outline vermelho transparente que o .is-pendente original
   (quando era um <span>) sempre teve. background:none restaura isso -
   .money-pill/.is-pendente já cuidam de border/color, só faltava isso. */
/* Achado real (2026-08-06, "a formatação fica estranha quando desce na
   lista"): faltava position:relative aqui - diferente do
   .status-pill-wrap, que já tinha isso desde o início. Sem isso, o menu
   dropdown (position:absolute) não se ancorava nesta pirula - ele subia a
   árvore do DOM procurando o ancestral posicionado mais próximo, que
   varia dependendo de onde a linha está na página, causando um
   posicionamento diferente (e errado) pra cada sessão. */
.money-pill-wrap { position: relative; display: inline-block; }
.money-pill-btn { cursor: pointer; font-family: var(--body); background: none; }
.money-pill-btn:hover { background: var(--danger); color: #fff; }
.money-pill-btn:disabled { opacity: 0.5; cursor: wait; }
.money-pill-btn.is-lote-selecionado { background: var(--danger); color: #fff; }

/* Barra de pagamento em lote (assets/status-pill.js, 2026-08-05) - fixa
   embaixo da tela enquanto o modo lote está ativo, pra ficar visível
   rolando a página inteira selecionando sessões. */
.plote-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
  background: var(--card); border-top: 1px solid var(--border); box-shadow: 0 -6px 20px rgba(0,0,0,0.12);
  padding: 0.8rem 1.2rem; display: flex; align-items: center; gap: 0.8rem; flex-wrap: wrap;
}
.plote-bar .plote-resumo { font-weight: 700; color: var(--heading); }
.plote-bar select { padding: 0.4rem 0.6rem; border-radius: var(--radius-sm); border: 1px solid var(--border); background: var(--bg); color: var(--ink); font-family: var(--body); }
.plote-bar .plote-confirmar { margin-left: auto; }
@media (max-width: 640px) {
  .plote-bar { flex-direction: column; align-items: stretch; }
  .plote-bar .plote-confirmar { margin-left: 0; }
}

.resumo-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 1rem; margin-bottom: 1.2rem;
}
.resumo-stat { text-align: center; padding: 0.8rem 0.5rem; border-radius: var(--radius-sm); background: var(--bg-alt); }
a.resumo-stat { display: block; color: inherit; text-decoration: none; transition: background 0.15s ease; }
a.resumo-stat:hover { background: var(--border); text-decoration: none; }
.resumo-stat-value { font-family: var(--display); font-size: 1.6rem; font-weight: 600; color: var(--heading); line-height: 1.1; font-variant-numeric: tabular-nums; display: flex; align-items: center; justify-content: center; gap: 0.4rem; }
.resumo-stat-label { font-size: 0.75rem; color: var(--ink-dim); margin-top: 0.3rem; }
/* Liga visualmente cada número do resumo à fatia correspondente do donut
   ao lado (2026-08-13) - antes não havia nenhum jeito de saber qual fatia
   era qual sem adivinhar pela cor sozinha. */
.resumo-stat-dot { width: 0.55rem; height: 0.55rem; border-radius: 50%; flex: 0 0 auto; }
.resumo-financeiro { display: flex; gap: 2rem; flex-wrap: wrap; padding-top: 1rem; border-top: 1px solid var(--border); }
.resumo-financeiro-item .valor { font-family: var(--display); font-size: 1.3rem; font-weight: 600; color: var(--heading); font-variant-numeric: tabular-nums; }
.resumo-financeiro-item .label { font-size: 0.8rem; color: var(--ink-dim); }
/* Achado real testando celular estreito (2026-08-10, ao acrescentar
   Despesas/Lucro líquido ao card do Financeiro): com 6 itens em vez de 4,
   o flex-wrap às vezes encaixa uma dupla numa linha que passa alguns
   pixels da largura da tela (o wrap decide por linha, não por item —
   nenhum item sozinho ultrapassa, mas um PAR específico pode). Abaixo de
   480px cada item vira sua própria linha - elimina esse risco de vez, em
   vez de depender de larguras de texto que podem mudar no futuro. */
@media (max-width: 480px) {
  .resumo-financeiro-item { flex-basis: 100%; }
}

.dia-group + .dia-group { margin-top: 1.8rem; padding-top: 1.4rem; border-top: 2px solid var(--border); }
.dia-group-label {
  display: inline-block;
  font-size: 0.78rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--primary); background: var(--bg-alt);
  padding: 0.3rem 0.75rem; border-radius: 999px; margin-bottom: 0.6rem;
}

/* --- Patients list --- */
/* Achado real na auditoria visual de 2026-08-04: sem isso, uma tabela
   larga (ex: Ranking de clientes) estica a PÁGINA INTEIRA horizontalmente
   em telas estreitas em vez de só a tabela rolar - confirmado via
   document.body.scrollWidth > viewport num teste real em 390px. */
.table-wrap { overflow-x: auto; }
/* min-width força a tabela a manter sua largura natural em vez de
   comprimir colunas até o texto virar ilegível em 2-3 linhas (achado real
   no celular do cliente 2026-08-05, ranking do Financeiro com 6 colunas -
   nome/valor quebrando em várias linhas dentro de cada célula). Com
   white-space:nowrap nas células, o .table-wrap acima passa a rolar de
   verdade na horizontal em vez de espremer o conteúdo. */
.patients-table { width: 100%; min-width: 640px; border-collapse: collapse; }
.patients-table td { font-variant-numeric: tabular-nums; white-space: nowrap; }
.patients-table th { text-align: left; font-size: 0.8rem; color: var(--ink-dim); text-transform: uppercase; letter-spacing: 0.03em; padding: 0.5rem 0.8rem; border-bottom: 1px solid var(--border); white-space: nowrap; }
.patients-table td { padding: 0.7rem 0.8rem; border-bottom: 1px solid var(--border); }
.patients-table tr:hover { background: var(--bg-alt); }

/* --- Calendar (FullCalendar re-theme) --- */
#calendar { background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); padding: 1.2rem; position: relative; min-height: 480px; }
/* Achado real (2026-08-06, construindo a Semana sob medida): o próprio
   FullCalendar define "display: flex" via style inline no container raiz
   - isso vence o "display: none" padrão do atributo [hidden] (inline
   sempre tem prioridade sobre regra de classe/ID sem !important), então
   só setar calendarEl.hidden=true no JS não escondia nada de verdade.
   Precisa de !important pra realmente ganhar do inline do FullCalendar. */
#calendar[hidden] { display: none !important; }

/* Loading enquanto o FullCalendar busca os eventos (api/calendario.php) -
   trocado 2026-08-05 pelo mesmo estilo de "constelação" já usado no
   painel do Ledger (ledger/index.php), só recolorido pra paleta da
   Clínica em vez de reinventar um visual novo - ver a animação de canvas
   em assets/calendar.js, ligada ao mesmo callback loading() de sempre. */
.calendar-skeleton {
  position: absolute; inset: 1.2rem; background: var(--card); border-radius: var(--radius-sm);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.9rem; z-index: 5;
}
.calendar-skeleton[hidden] { display: none; }
.calendar-skeleton p { color: var(--ink-dim); font-size: 0.85rem; letter-spacing: 0.02em; margin: 0; font-family: var(--body); }
.fc { font-family: var(--body); --fc-border-color: var(--border); --fc-page-bg-color: var(--card); --fc-neutral-bg-color: var(--bg-alt); --fc-today-bg-color: rgba(176, 138, 62, 0.12); }
.fc .fc-toolbar-title { font-family: var(--display); font-weight: 600; color: var(--heading); }
/* Capitaliza só a 1ª letra ("agosto de 2026" -> "Agosto de 2026") - o
   locale pt-br do FullCalendar devolve o mês em minúscula (gramática
   correta em frase corrida, mas título pede maiúscula). */
.fc .fc-toolbar-title::first-letter, .agenda-semana-titulo::first-letter { text-transform: uppercase; }
/* Cor de campanha do mês (2026-08-14) - bolinha antes do título, nome da
   campanha no title (tooltip) em vez de escrever por extenso e competir
   com o título - ver MES_CAMPANHA em calendar.js. Aumentada + brilho
   colorido (achado real: 11px sem destaque nenhum passava despercebida -
   mesma linguagem visual da "luzinha" já usada nos compromissos da
   agenda, glow na cor certa em vez de só um contorno). */
.clinica-mes-cor-dot {
  display: inline-block; width: 16px; height: 16px; border-radius: 50%;
  margin-right: 0.65rem; vertical-align: middle; border: 1.5px solid rgba(0,0,0,0.22);
  box-shadow: 0 0 0 1px rgba(255,255,255,0.5) inset, 0 0 10px 2px var(--mes-dot-glow, transparent);
}
/* Achado real na auditoria visual de 2026-08-04: em telas estreitas o
   título do mês espremia entre os botões e quebrava linha letra por letra,
   sobrepondo os botões Mês/Semana/Dia. Empilhar as 3 seções do toolbar
   (navegação / título / seletor de view) resolve sem remover nenhum botão. */
@media (max-width: 640px) {
  #calendar { padding: 0.8rem; }
  .fc .fc-toolbar { flex-direction: column; gap: 0.7rem; }
  .fc .fc-toolbar-title { font-size: 1.15rem; text-align: center; }
  .fc .fc-toolbar-chunk { display: flex; justify-content: center; width: 100%; }
  .fc .fc-button { padding: 0.4rem 0.6rem; font-size: 0.82rem; }
  /* Achado real numa análise geral 2026-08-05: com dias mais cheios, o
     pill de evento na visão Mês virava texto ilegível no celular (largura
     de coluna pequena demais pro badge + hora + nome inteiros - sobrava só
     "M 10", sem informação nenhuma). Corta a hora (a lista "Horários do
     dia" ao tocar no dia já mostra isso) pra abrir espaço só pro nome, que
     é o dado que realmente importa "de relance". dayMaxEvents (ver
     calendar.js) já limita quantos pills cabem antes de virar "+N mais",
     então o corte de texto aqui é sobre legibilidade, não sobre altura. */
  .clinica-event-time { display: none; }
  .clinica-event-badge { width: 1rem; height: 1rem; font-size: 0.6rem; }
  .clinica-event-content { padding: 2px 3px; gap: 0.25rem; }
  .fc-daygrid-event { font-size: 0.72rem; }
  /* Achado real (2026-08-06, celular do cliente) - a Semana sob medida
     reaproveita as mesmas classes .clinica-event-* da visão Mês (mesma
     linguagem visual, ver criarConteudoEventoLista() em calendar.js), mas
     a coluna da Semana tem espaço de sobra - o "esconde a hora" acima é
     só sobre a célula apertada do Mês, não deveria valer aqui também. */
  .agenda-semana-evento .clinica-event-time { display: inline; }
  .agenda-semana-evento .clinica-event-badge { width: 1.3rem; height: 1.3rem; font-size: 0.7rem; }
  .fc-daygrid-more-link { width: 1.3rem; height: 1.3rem; font-size: 0.62rem; margin: 2px auto 0; }

  /* .session-row overflow fix (achado real, screenshot do celular do
     cliente 2026-08-05) - status-pill/money-pill/ações ficavam cortados
     na borda da tela porque a linha nunca quebrava. Com flex-wrap, o que
     não couber ao lado do nome desce pra uma segunda linha em vez de
     estourar a largura da tela; margin-left:auto mantém o pill grudado
     na direita tanto na 1ª linha (se couber) quanto na 2ª (se não). */
  .session-row { flex-wrap: wrap; row-gap: 0.35rem; }
  .session-row > .status-pill,
  .session-row > .status-pill-wrap,
  .session-row > .money-pill,
  .session-row > .money-pill-wrap { margin-left: auto; }
  /* Achado real 2026-08-08 (screenshot da Equipe no celular) - essa linha
     de ações passou de 2 pra 4 botões (Cor, Promover, ver
     equipe.php) e a versão de largura total continuava numa fileira só
     sem quebrar - "Desativar" saía cortado na borda da tela. flex-wrap
     deixa os botões que não couberem descerem pra uma 2ª linha em vez de
     estourar. */
  .session-row-actions { flex-basis: 100%; padding-left: calc(38px + 0.9rem); flex-wrap: wrap; row-gap: 0.5rem; }
}
/* Bolinha em vez de link de texto "+N mais" - pedido do cliente 2026-08-05,
   pra ficar mais compacto e discreto, no mesmo espírito visual dos badges
   de profissional (círculo colorido). moreLinkText (calendar.js) já
   devolve só "+N", sem a palavra "mais". */
.fc-daygrid-more-link {
  display: flex !important; align-items: center; justify-content: center;
  width: 1.6rem; height: 1.6rem; margin: 3px auto 0;
  border-radius: 50%; background: var(--bg-alt); color: var(--ink-dim) !important;
  font-size: 0.72rem; font-weight: 700; text-decoration: none !important;
}
.fc-daygrid-more-link:hover { background: var(--primary); color: #fff !important; }
.fc .fc-button { background: var(--primary); border: none; text-transform: capitalize; }
.fc .fc-button:hover { background: var(--primary-dark); }
.fc .fc-button-active { background: var(--primary-dark) !important; }
.fc .fc-daygrid-day-number, .fc .fc-col-header-cell-cushion { color: var(--ink); text-decoration: none; }
/* Redesign da visão Mês (2026-09-13, pedido do cliente: "esse visual da
   agenda pro mês está muito feio, confuso, não dá pra entender nada
   direito" - comparando com a visão Semana, que ele achou ótima).
   FullCalendar vem com cinza genérico de fábrica pras bordas/cabeçalho
   e as caixinhas de sessão ficavam grudadas sem respiro nenhum - nada
   disso muda a MECÂNICA de sempre (cor de fundo = profissional, faixa
   lateral = status, badge = inicial) - só integra com a paleta do resto
   do app e dá mais ar entre os elementos. */
.fc, .fc-theme-standard td, .fc-theme-standard th, .fc-theme-standard .fc-scrollgrid { border-color: var(--border); }
.fc-theme-standard .fc-col-header-cell { background: var(--bg-alt); }
.fc .fc-col-header-cell-cushion {
  padding: 0.6rem 0.3rem; font-weight: 700; font-size: 0.78rem;
  letter-spacing: 0.02em; text-transform: uppercase; color: var(--ink-dim);
}
.fc-day-sat .fc-col-header-cell-cushion, .fc-day-sun .fc-col-header-cell-cushion { color: var(--accent); }
.fc-day-sat:not(.fc-col-header-cell), .fc-day-sun:not(.fc-col-header-cell) { background: var(--bg-alt); }
.fc .fc-daygrid-day-top { padding: 0.35rem 0.35rem 0; }
.fc .fc-daygrid-day-number { font-weight: 700; font-size: 0.85rem; padding: 0.1rem 0.35rem; border-radius: 50%; }
.fc-day-today { background: var(--card) !important; box-shadow: inset 0 0 0 2px var(--primary); }
.fc-day-today .fc-daygrid-day-number { background: var(--primary); color: #fff !important; }
.fc-daygrid-day-events { margin-top: 0.25rem; }
.fc-daygrid-event-harness { margin-bottom: 3px !important; }
.fc-event { border: none; cursor: pointer; border-radius: var(--radius-sm); }
/* Faixa de status como sombra INTERNA, não border-left (2026-08-10,
   achado real do cliente: "a cor de canto da caixinha fica quebrada" -
   border-left é reto e vaza pra fora do border-radius do FullCalendar nos
   cantos arredondados; inset box-shadow é sempre recortado pela própria
   curva do elemento, nunca vaza). --stripe-shadow é setada via JS em
   calendar.js pra TODO evento (sessão e compromisso). Também vale pra
   .agenda-semana-evento (visão Semana, não é o FullCalendar mas tem o
   mesmo border-radius arredondado e o mesmo bug antes desta correção). */
.fc-event, .agenda-semana-evento { box-shadow: var(--stripe-shadow, none); }
/* Luzinha de ambiente nos compromissos (2026-08-10, "o Mardônio gosta de
   luzes... um efeito de luzes ao redor da caixinha") - brilho suave
   pulsando, na cor saturada do profissional (--luz-cor, setada via JS em
   calendar.js). Só nos compromissos (.clinica-evento-luzes), nunca nas
   sessões clínicas - continuam sóbrias de propósito. Pulso lento e suave
   (nunca um blink duro) - ambiente, não estroboscópico. Cada keyframe
   inclui --stripe-shadow JUNTO com o brilho (box-shadow aceita uma lista
   separada por vírgula) - senão a animação substituiria a faixa de status
   inteira, apagando-a durante o pulso.*/
.clinica-evento-luzes { animation: clinicaLuzesPulso 2.6s ease-in-out infinite; }
@keyframes clinicaLuzesPulso {
  0%, 100% { box-shadow: var(--stripe-shadow, none), 0 0 3px 0 var(--luz-cor, transparent); }
  50% { box-shadow: var(--stripe-shadow, none), 0 0 9px 2px var(--luz-cor, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .clinica-evento-luzes { animation: none; box-shadow: var(--stripe-shadow, none), 0 0 5px 1px var(--luz-cor, transparent); }
}
.clinica-event-content { display: flex; align-items: center; gap: 0.35rem; padding: 3px 6px; overflow: hidden; }
.clinica-event-badge {
  flex: 0 0 auto;
  width: 1.15rem; height: 1.15rem;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.68rem; font-weight: 800;
  color: #2a2520;
  background: rgba(255, 253, 248, 0.92);
  box-shadow: 0 0 0 1px rgba(255,255,255,0.6);
}
.clinica-event-time { flex: 0 0 auto; font-weight: 700; color: inherit; text-shadow: inherit; }
.clinica-event-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: inherit; text-shadow: inherit; }

/* Selo "Aguardando confirmação do paciente" (2026-09-08, pedido do
   cliente: "uma animação diferente, divertida, que chame a atenção" -
   de propósito NÃO reaproveita clinicaLuzesPulso acima, que é um brilho
   ambiente sutil pros compromissos - este precisa ser notado de longe,
   é sobre não esquecer de acompanhar uma conversa em aberto com o
   paciente). Selo 🤞 clicável (mesmo tamanho/forma de .clinica-event-
   badge, mas com fundo/animação próprios pra se destacar dos outros
   badges do mesmo bloco) - clique já desmarca (ver
   criarSeloAguardandoConfirmacao() em calendar.js), sem abrir o modal. */
.clinica-aguardando-selo {
  flex: 0 0 auto;
  margin-left: auto;
  width: 1.4rem; height: 1.4rem;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.85rem;
  border: none;
  cursor: pointer;
  background: linear-gradient(135deg, #56ccf2, #2f80ed);
  box-shadow: 0 0 0 2px rgba(255,255,255,0.85), 0 1px 4px rgba(0,0,0,0.25);
  animation: aguardandoSeloBalanco 1.6s ease-in-out infinite;
}
.clinica-aguardando-selo:hover { background: linear-gradient(135deg, #6fd5f5, #1f6fe0); }
.clinica-aguardando-selo:disabled { opacity: 0.5; cursor: default; animation: none; }
/* Variante do selo acima pra uso INLINE, no meio de texto (2026-09-15,
   selo 🤞 na Recepção - index.php) - a versão original usa display:flex,
   que "blockifica" o botão (vira caixa de bloco própria, força quebra de
   linha) porque ali ele sempre vive dentro de uma linha-flex inteira
   (evento da Agenda). Aqui ele fica junto do nome do paciente, no meio
   de texto normal, então precisa ficar inline mesmo (achado real: sem
   isso o selo caía pra linha de baixo sozinho, feio, empurrando a
   pilulazinha de "restantes" pra ainda mais embaixo). Mesmo visual
   (gradiente, animação), só a caixa muda de comportamento. */
.clinica-aguardando-selo-inline {
  display: inline-flex; align-items: center; justify-content: center;
  vertical-align: middle;
  flex: 0 0 auto;
  width: 1.3rem; height: 1.3rem; padding: 0;
  margin: 0 0.4rem;
}
@keyframes aguardandoSeloBalanco {
  0%, 100% { transform: rotate(0deg); }
  20% { transform: rotate(-18deg); }
  40% { transform: rotate(14deg); }
  60% { transform: rotate(-8deg); }
  80% { transform: rotate(0deg); }
}
/* O bloco inteiro (sessão na Agenda - Mês/Dia via FullCalendar,
   .fc-event; Semana via .agenda-semana-evento) - balanço leve + brilho
   azul pulsando, combinado com --stripe-shadow (mesma técnica de
   clinicaLuzesPulso acima: box-shadow aceita lista separada por
   vírgula, senão a animação apagaria a faixa de status inteira).
   2026-09-08, feedback do cliente (2ª rodada): "brilho azul com
   degradê, o fundo vermelho do ícone ficou feio" - selo trocado pro
   gradiente azul acima; o brilho do bloco simula degradê empilhando
   DOIS tons de azul (ciano claro por dentro, azul mais profundo por
   fora - mesmo truque de "gradiente" que box-shadow consegue, já que
   ele não aceita um <gradient> de verdade). */
.clinica-aguardando-confirmacao {
  animation: aguardandoBlocoChamativo 1.8s ease-in-out infinite;
}
@keyframes aguardandoBlocoChamativo {
  0%, 100% { transform: rotate(0deg); box-shadow: var(--stripe-shadow, none), 0 0 0 0 rgba(86, 204, 242, 0.5), 0 0 0 0 rgba(47, 128, 237, 0.4); }
  50% { transform: rotate(-0.6deg); box-shadow: var(--stripe-shadow, none), 0 0 14px 4px rgba(86, 204, 242, 0.75), 0 0 26px 10px rgba(47, 128, 237, 0.6); }
}
@media (prefers-reduced-motion: reduce) {
  .clinica-aguardando-selo { animation: none; }
  .clinica-aguardando-confirmacao { animation: none; box-shadow: var(--stripe-shadow, none), 0 0 10px 3px rgba(86, 204, 242, 0.65), 0 0 18px 6px rgba(47, 128, 237, 0.5); }
}

/* Legenda de profissionais da Agenda - trocado de quadradinho-de-cor+nome
   pra avatar (foto ou iniciais coloridas, mesmo clinica_avatar_html() já
   usado em todo o resto do app) + nome, 2026-08-05. Achado do cliente:
   com só 2 profissionais o texto+quadradinho cabia, mas ele já avisou que
   isso "pode ser um grande problema" assim que a equipe crescer (tela
   flex-wrap sem limite = um monte de nome+quadradinho competindo por
   espaço com os filtros ao lado). Avatar circular é muito mais compacto
   por item, e no celular o nome esconde e sobra só o círculo (com o
   atributo title nativo fazendo as vezes de tooltip) - escala bem pra
   qualquer número de profissionais sem precisar de paginação/colapso.
   agenda.php loop over $profissionais - toda a lista real de
   profissionais ativos, então isso é o ponto único que precisa escalar. */
/* .agenda-filtros (2026-08-05, achado real via print do celular) - antes
   a legenda + os dois selects de filtro eram 3 irmãos soltos com
   flex-wrap num container só, sem nenhum agrupamento visual - no celular
   isso quebrava em blocos de largura desencontrada ("jogado", nas
   palavras do cliente). Agora cada um vira um bloco de largura cheia,
   empilhado na ordem do HTML, com espaçamento consistente entre eles -
   sem ambiguidade de onde cada filtro "pertence" visualmente. */
.agenda-filtros { display: flex; align-items: flex-end; gap: 1.5rem; flex-wrap: wrap; }
@media (max-width: 640px) {
  .agenda-filtros { flex-direction: column; align-items: stretch; gap: 0.9rem; }
  .agenda-filtros .field { max-width: none !important; }
}

.agenda-legenda-profissionais { display: flex; gap: 0.9rem; flex-wrap: wrap; align-items: center; }
.agenda-legenda-rotulo { font-size: 0.8rem; font-weight: 600; color: var(--ink-dim); }
.agenda-legenda-item { display: flex; align-items: center; gap: 0.4rem; font-size: 0.85rem; color: var(--ink-dim); }
@media (max-width: 640px) {
  .agenda-legenda-item { gap: 0; }
  .agenda-legenda-item .clinica-avatar { margin: 0; }
  .agenda-legenda-item { font-size: 0; }
}

/* Mini-calendário do perfil do paciente (assets/paciente-calendario.js,
   2026-08-05) - seleção de dias avulsos, propositalmente mais simples que
   o FullCalendar da Agenda (só precisa marcar dias, não arrastar/redimen-
   sionar eventos). */
.pcal-header {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 0.6rem; font-weight: 700; color: var(--heading);
}
.pcal-header button {
  background: var(--bg-alt); color: var(--ink); width: 2rem; height: 2rem;
  padding: 0; border-radius: 50%; font-size: 1.1rem; line-height: 1;
}
.pcal-header button:hover { background: var(--border); }
.pcal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0.25rem; }
.pcal-dow { text-align: center; font-size: 0.75rem; color: var(--ink-dim); font-weight: 700; padding: 0.3rem 0; }
.pcal-day {
  aspect-ratio: 1; background: var(--bg-alt); color: var(--ink); border-radius: var(--radius-sm);
  font-weight: 600; font-size: 0.85rem; padding: 0; display: flex; align-items: center; justify-content: center;
}
.pcal-day:hover { background: var(--border); }
.pcal-day.is-passado { color: var(--ink-dim); }
.pcal-day.is-selected { background: var(--primary); color: #fff; }
.pcal-day.is-selected.is-passado { background: var(--accent); }
#pcalToggleSeta { display: inline-flex; transition: transform 0.15s ease; }
#pcalToggleSeta svg { width: 14px; height: 14px; }
#extratoSaldoToggleSeta { display: inline-flex; transition: transform 0.15s ease; }
#extratoSaldoToggleSeta svg { width: 14px; height: 14px; }

/* --- Modal --- */
.clinica-modal-backdrop {
  position: fixed; inset: 0; background: rgba(42, 37, 32, 0.45);
  display: flex; align-items: center; justify-content: center; z-index: 100;
}
.clinica-modal-backdrop[hidden] { display: none; }
.clinica-modal {
  background: var(--card); border-radius: var(--radius); box-shadow: 0 20px 60px rgba(0,0,0,0.3);
  padding: 1.8rem; width: 100%; max-width: 560px; max-height: 90vh; overflow-y: auto;
}
.clinica-modal h2 { font-size: 1.3rem; margin-bottom: 1.2rem; }
.clinica-modal-actions { display: flex; gap: 0.7rem; margin-top: 1.3rem; }

/* Modal do dia com "Guia" ao lado (2026-09-08, pedido do cliente:
   "quero que me mostre AO LADO os pacientes... das últimas 2 semanas,
   como guia") - modal mais largo que o padrão de 560px só quando tem
   guia pra mostrar; a coluna da guia é sticky-ish só por ficar numa
   grade separada da lista de horários que rola sozinha. Empilha numa
   coluna só (guia embaixo) em telas estreitas - "ao lado" não cabe em
   celular. */
.clinica-modal-largo { max-width: 900px; }
/* Título clicável na visão Dia da Agenda (2026-09-08) - único jeito de
   abrir "Horários do dia" + guia nessa visão, já que a tela inteira É
   o dia (não tem célula de dia pra clicar como no Mês). Ver
   assets/calendar.js's datesSet/click delegado em calendarEl. */
.fc-toolbar-title-clicavel { cursor: pointer; text-decoration: underline dotted; text-underline-offset: 4px; }
.dia-modal-layout { display: grid; grid-template-columns: 1fr 260px; gap: 1.5rem; align-items: start; }
.dia-modal-principal { min-width: 0; }
.dia-modal-guia { border-left: 1px solid var(--border); padding-left: 1.2rem; }
@media (max-width: 720px) {
  .dia-modal-layout { grid-template-columns: 1fr; }
  .dia-modal-guia { border-left: none; padding-left: 0; border-top: 1px solid var(--border); padding-top: 1rem; margin-top: 0.5rem; }
}
/* Guia do dia - redesenho 2026-09-08 (pedido do cliente: "está muito
   bagunçado, seria bom se eu puder ver por horários, depois o nome do
   paciente... quero cores, ícones") - de cartão empilhado (nome em
   cima, hora embaixo, botão largo) pra uma linha de mini-agenda:
   horário em destaque à esquerda, barra colorida = profissional (mesma
   cor da Agenda, corDoProfissional() em calendar.js), linha inteira
   clicável. Entra em cascata (--i, ver calendar.js) - só um toque de
   movimento, nada exagerado. */
#diaGuiaLista { display: flex; flex-direction: column; gap: 0.4rem; }
.dia-guia-item {
  display: flex; align-items: center; gap: 0.7rem; padding: 0.55rem 0.7rem;
  border-radius: var(--radius-sm); background: var(--bg-alt);
  border: 1px solid var(--border); border-left: 3px solid var(--border);
  cursor: pointer; transition: transform 0.12s ease, box-shadow 0.12s ease, border-color 0.12s ease;
  animation: diaGuiaEntrada 0.28s ease backwards;
  animation-delay: calc(var(--i, 0) * 45ms);
}
.dia-guia-item:hover, .dia-guia-item:focus-visible {
  transform: translateX(2px); box-shadow: 0 2px 8px rgba(0,0,0,0.08); border-color: var(--primary); outline: none;
}
.dia-guia-item-hora {
  font-family: var(--display); font-weight: 700; font-size: 0.95rem; color: var(--heading);
  min-width: 3.1rem; flex-shrink: 0;
}
.dia-guia-item-corpo { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; flex: 1; }
.dia-guia-item-nome-linha { display: flex; align-items: center; gap: 0.35rem; min-width: 0; }
.dia-guia-item-nome { flex: 1 1 auto; font-weight: 600; font-size: 0.86rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.dia-guia-item-sub { font-size: 0.74rem; color: var(--ink-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* "Já tem/teve sessão essa semana" (2026-09-15, pedido do mestre: a 1ª
   versão em texto ficou "muito feia" - quebrava linha embaixo do nome e
   empurrava tudo pra baixo) - selinho redondo compacto, MESMA linha do
   nome, tooltip explica o resto. */
.dia-guia-item-semana-selo {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 1rem; height: 1rem; border-radius: 50%;
  background: var(--success, #2e7d32); color: #fff;
  font-size: 0.62rem; font-weight: 700; line-height: 1;
}
.dia-guia-item-seta { color: var(--ink-faint); font-size: 0.9rem; flex-shrink: 0; transition: transform 0.12s ease, color 0.12s ease; }
.dia-guia-item:hover .dia-guia-item-seta, .dia-guia-item:focus-visible .dia-guia-item-seta { transform: translateX(2px); color: var(--primary); }
@keyframes diaGuiaEntrada { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } }
@media (prefers-reduced-motion: reduce) {
  .dia-guia-item { animation: none; }
}

/* Recados do dia colapsáveis (2026-09-08, pedido do cliente: "está
   feio, não está muito prático") - resumo de 1 linha por padrão em vez
   de 3 textareas sempre abertas ocupando a metade do modal antes de
   chegar nos horários de verdade.
   #diaObservacoesToggle POR ID (não só classe) - achado real (2026-09-08,
   cliente reportou "cor do recado do dia deixa invisível"): mesmo bug JÁ
   DOCUMENTADO neste arquivo antes (ver .money-pill-cortesia-btn/
   .money-pill-cancelado-cobrar-btn acima, ~linha 1195) - um elemento que
   vira <button> herda "background: var(--primary); color: #fff" da regra
   global (topo do arquivo) por cima de overrides de classe, de um jeito
   que já se provou não-confiável só com especificidade de classe nas
   outras 2 vezes que isso aconteceu neste mesmo projeto. ID (specificidade
   maior que classe) + !important tira qualquer dúvida - preferível a
   descobrir de novo da próxima vez que isso se repetir. */
#diaObservacoesToggle {
  display: flex; align-items: center; gap: 0.5rem; width: 100%; text-align: left;
  padding: 0.6rem 0.8rem; margin-bottom: 0.8rem; border-radius: var(--radius-sm);
  background: var(--bg-alt) !important; border: 1px solid var(--border); border-left: 3px solid var(--warn, #c9973f);
  font-family: var(--body); font-size: 0.88rem; font-weight: 600; color: var(--ink) !important; cursor: pointer;
  transition: border-color 0.15s ease, transform 0.1s ease, box-shadow 0.15s ease;
}
#diaObservacoesToggle:hover { border-color: var(--primary); transform: translateY(-1px); box-shadow: 0 2px 6px rgba(0,0,0,0.08); }
#diaObservacoesToggle.is-aberto { border-left-color: var(--primary); background: color-mix(in srgb, var(--primary) 8%, var(--bg-alt)) !important; }
/* [hidden] perde pra "display:flex" acima - mesmo gotcha do wrap logo
   abaixo (o botão só some de verdade antes do fetch de observações
   voltar, mas mesma correção defensiva). */
#diaObservacoesToggle[hidden] { display: none !important; }
.dia-observacoes-toggle-icone { font-size: 1rem; }
.dia-observacoes-toggle-seta { margin-left: auto; transition: transform 0.15s ease; color: var(--ink-dim); }
.dia-observacoes-toggle.is-aberto .dia-observacoes-toggle-seta { transform: rotate(180deg); }
/* Conteúdo expandido entra com uma leve queda + fade, não só um "pop"
   seco de [hidden] sumindo (pedido do cliente: "mais animações"). */
.dia-observacoes-wrap:not([hidden]) { animation: diaObsExpande 0.2s ease; }
@keyframes diaObsExpande { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }
@media (prefers-reduced-motion: reduce) {
  .dia-observacoes-wrap:not([hidden]) { animation: none; }
}

/* Madrugada colapsada por padrão (2026-09-08) - 00h-06h continua no
   expediente 24h (requisito já confirmado antes), só escondida atrás
   de 1 clique pra não estourar a lista com 7 linhas quase sempre
   vazias antes mesmo de chegar no horário comercial. */
/* #diaMadrugadaToggle por ID - mesma precaução do #diaObservacoesToggle
   logo acima, mesmo bug documentado neste arquivo (~linha 1195). */
#diaMadrugadaToggle {
  display: flex; align-items: center; gap: 0.4rem; width: 100%; text-align: left;
  padding: 0.4rem 0.6rem; margin-bottom: 0.4rem; border-radius: var(--radius-sm);
  background: transparent !important; border: 1px dashed var(--border); font-family: var(--body);
  font-size: 0.8rem; color: var(--ink-dim) !important; cursor: pointer; transition: border-color 0.15s ease, color 0.15s ease;
}
#diaMadrugadaToggle:hover { border-color: var(--primary); color: var(--ink) !important; }
#diaMadrugadaToggle.is-aberto { border-style: solid; border-color: var(--primary); color: var(--primary) !important; }
.dia-madrugada-toggle-seta { margin-left: auto; transition: transform 0.15s ease; }
.dia-madrugada-toggle.is-aberto .dia-madrugada-toggle-seta { transform: rotate(180deg); }
.field-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 1rem; }

/* Fade/slide transition instead of an abrupt [hidden] toggle - see
   assets/calendar.js's openModal()/closeModal() for the class timing.
   Respects prefers-reduced-motion like the rest of this stylesheet. */
.clinica-modal-backdrop { opacity: 0; transition: opacity 0.18s ease; }
.clinica-modal-backdrop .clinica-modal { transform: translateY(12px) scale(0.98); transition: transform 0.18s ease; }
.clinica-modal-backdrop.is-open { opacity: 1; }
.clinica-modal-backdrop.is-open .clinica-modal { transform: translateY(0) scale(1); }
.clinica-modal-sobre-mep { text-align: center; }
.clinica-modal-sobre-mep .sobre-mep-badge {
  display: inline-block; font-family: var(--display); font-weight: 700; font-size: 2rem;
  color: var(--primary); margin-bottom: 0.6rem;
}
.clinica-modal-sobre-mep .sobre-mep-slogan {
  font-family: var(--display); font-style: italic; font-size: 1.15rem; color: var(--heading); margin-bottom: 0.3rem;
}
.clinica-modal-sobre-mep .sobre-mep-significado { color: var(--ink-dim); font-size: 0.85rem; margin-bottom: 1.3rem; }
.clinica-modal-sobre-mep p { text-align: left; line-height: 1.6; color: var(--ink-dim); margin-bottom: 0.9rem; }
.clinica-modal-sobre-mep .clinica-modal-actions { justify-content: center; }
@media (prefers-reduced-motion: reduce) {
  .clinica-modal-backdrop, .clinica-modal-backdrop .clinica-modal { transition: none; }
}

@media (max-width: 560px) {
  .field-grid { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  button, .btn { transition: none; }
}

/* --- Conversas (WhatsApp inbox) --- */
.clinica-page-full { max-width: none; padding: 0; height: calc(100vh - 4.2rem); display: flex; flex-direction: column; }
.conversas-modo-seguro {
  flex: 0 0 auto; display: flex; align-items: center; gap: 0.6rem;
  background: #f6e3df; color: #7a2e22; padding: 0.6rem 1.2rem; font-size: 0.85rem;
}
:root[data-theme="dark"] .conversas-modo-seguro { background: #3d2420; color: #f0a998; }
.conversas-modo-seguro svg { flex: 0 0 auto; width: 18px; height: 18px; }
.conversas-layout { display: flex; width: 100%; flex: 1; min-height: 0; }

/* Avatar circular com iniciais - não temos foto real de contato (a Cloud
   API não expõe foto de perfil de usuários comuns), a cor vem de um hash
   simples do nome/telefone em assets/conversas.js, sempre a mesma cor pra
   a mesma pessoa. */
.conversas-avatar {
  flex: 0 0 auto; width: 2.6rem; height: 2.6rem; border-radius: 999px;
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-weight: 700; font-size: 1rem; font-family: var(--display);
  object-fit: cover; position: relative;
}
.conversas-avatar.is-pequeno { width: 2.1rem; height: 2.1rem; font-size: 0.85rem; }

/* Bolinha de presença na aba "Equipe" - só quando data-presence-dot está
   presente (conversas.js só põe isso nos itens da equipe, não em
   pacientes, que não têm status online/offline). Sem overflow:hidden no
   .conversas-avatar, então o ::after não precisa de wrapper à parte aqui
   (diferente de .clinica-avatar-wrap, que tem esse problema). */
.conversas-avatar[data-presence-dot]::after {
  content: ""; position: absolute; right: -1px; bottom: -1px;
  width: 11px; height: 11px; background: #9a9188;
  border-radius: 50%; border: 2px solid var(--card, #fff);
}
.conversas-avatar[data-presence-dot].is-online::after { background: var(--success, #2f9e6b); }

.conversas-tabs { display: flex; gap: 0.3rem; padding: 0.6rem 0.9rem 0; flex: 0 0 auto; }
.conversas-tab {
  flex: 1; background: var(--bg-alt); border: none; border-radius: 999px;
  padding: 0.4rem 0.6rem; font-size: 0.82rem; font-weight: 700; color: var(--ink-dim);
  cursor: pointer;
}
.conversas-tab.is-ativa { background: var(--primary); color: #fff; }

.conversas-lista { width: 340px; flex: 0 0 auto; display: flex; flex-direction: column; background: var(--card); border-right: 1px solid var(--border); position: relative; min-width: 68px; max-width: 70vw; }
/* Sidebar redimensionável/colapsável (2026-08-20). A alça é uma faixa fina
   invisível sobre a borda direita - largura maior que a borda visual de
   1px pra dar uma área de clique/arraste confortável (achado comum de UX,
   pegar exatamente 1px de borda no mouse é frustrante). */
.conversas-lista-resize {
  position: absolute; top: 0; right: -3px; width: 6px; height: 100%;
  cursor: ew-resize; z-index: 5; background: transparent;
}
.conversas-lista-resize:hover, .conversas-lista-resize.is-arrastando { background: var(--primary); opacity: 0.25; }
/* Achado real testando ao vivo (2026-08-20): a primeira versão (círculo
   flutuante com borda+sombra, deslocado -12px pra fora da borda) ficava
   "feio" e, colapsado, caía bem em cima do primeiro avatar da lista -
   trocado por uma barrinha fina embutida no topo (mesmo fundo da lista,
   sem borda/sombra própria, só o ícone), com padding-top reservado nos
   itens colapsados pra nunca mais sobrepor nada. */
/* Terceira versão (2026-08-20) - a segunda (barra cinza full-width com
   borda) ainda ficava "feia", uma tarja cortando a lista à toa. Trocado
   por um círculo pequeno (18px), sem fundo/borda própria (só no hover),
   flutuando discreto no canto superior direito - mesma linguagem visual
   dos outros botões pequenos do app (reagir/encaminhar). position estática
   (não absoluta) continua de propósito: filho normal logo depois de
   .conversas-tabs, reserva sua própria linha curta (18px) sem sobrepor
   nada abaixo, só que agora essa linha é "vazia" visualmente (sem cor de
   fundo/borda) exceto pelo próprio círculo alinhado à direita. */
.conversas-lista-colapsar-btn {
  position: absolute; top: 6px; right: 6px; z-index: 6;
  width: 18px; height: 18px; border-radius: 50%; padding: 0;
  border: none; background: none; color: var(--ink-dim); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.85rem; line-height: 1;
}
.conversas-lista-colapsar-btn:hover { background: var(--bg-alt); color: var(--ink); }
/* Reserva espaço pro botão não cair em cima do primeiro avatar quando
   colapsado (a lista some daquela largura, o botão continua no topo). */
.conversas-lista.is-colapsada .conversas-lista-scroll { padding-top: 26px; }
/* Modo colapsado ("só avatar") - largura fixa em 68px pelo JS, esconde
   tudo que não seja o círculo de iniciais. Item continua clicável normal
   (só perde o texto), e mensagem não lida vira um anel colorido no
   próprio avatar em vez do badge numérico (que não cabe mais). */
.conversas-lista.is-colapsada .conversas-tabs,
.conversas-lista.is-colapsada .conversas-lista-header,
.conversas-lista.is-colapsada .conversas-busca,
.conversas-lista.is-colapsada .conversas-lista-item-info {
  display: none;
}
.conversas-lista.is-colapsada { display: flex; flex-direction: column; }
.conversas-lista.is-colapsada .conversas-lista-scroll { flex: 1; }
.conversas-lista.is-colapsada .conversas-lista-item { justify-content: center; padding: 0.6rem 0.3rem; }
.conversas-lista.is-colapsada .conversas-lista-item.is-nao-lida .conversas-avatar {
  box-shadow: 0 0 0 2px var(--card), 0 0 0 4px var(--accent);
}
.conversas-lista.is-colapsada .conversas-lista-colapsar-btn { transform: rotate(180deg); }
.conversas-lista-header {
  flex: 0 0 auto; display: flex; align-items: center; gap: 0.7rem; padding: 0.9rem 1.1rem;
  border-bottom: 1px solid var(--border);
}
/* Mesmo achado de 2026-08-18 do .clinica-chat-painel: uma classe com
   "display" explícito sempre vence o [hidden] do HTML (a declaração do
   autor bate a do user-agent, mesma especificidade ou não) - sem isto,
   os cabeçalhos de "Pacientes" e "Equipe" ficavam os dois visíveis ao
   mesmo tempo, um embaixo do outro. */
.conversas-lista-header[hidden] { display: none; }
.conversas-perfil-btn {
  flex: 1; display: flex; align-items: center; gap: 0.7rem; min-width: 0;
  background: none; border: none; padding: 0; cursor: pointer; text-align: left; color: var(--ink);
}
.conversas-perfil-btn:hover { background: none; }
.conversas-perfil-nome { font-weight: 700; font-size: 0.95rem; font-family: var(--display); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.conversas-config-link {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  width: 2.1rem; height: 2.1rem; border-radius: 999px; color: var(--ink-dim);
}
.conversas-config-link:hover { background: var(--bg-alt); text-decoration: none; }
button.conversas-config-link { background: none; border: none; padding: 0; cursor: pointer; }
button.conversas-config-link:hover { background: var(--bg-alt); }

.conversas-menu-wrap { position: relative; }
.conversas-menu-dropdown {
  position: absolute; top: calc(100% + 0.4rem); right: 0; z-index: 20;
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-sm);
  box-shadow: var(--shadow); min-width: 220px; padding: 0.4rem;
}
.conversas-menu-dropdown a {
  display: block; padding: 0.55rem 0.7rem; border-radius: var(--radius-sm);
  color: var(--ink); font-size: 0.88rem; font-weight: 600;
}
.conversas-menu-dropdown a:hover { background: var(--bg-alt); text-decoration: none; }
.conversas-busca { position: relative; flex: 0 0 auto; padding: 0.7rem 1rem; border-bottom: 1px solid var(--border); }
.conversas-busca svg { position: absolute; left: 1.6rem; top: 50%; transform: translateY(-50%); width: 16px; height: 16px; color: var(--ink-dim); }
.conversas-busca input {
  width: 100%; padding: 0.5rem 0.8rem 0.5rem 2.3rem; border-radius: 999px; border: 1px solid var(--border);
  background: var(--bg); color: var(--ink); font-family: var(--body); font-size: 0.88rem;
}
.conversas-lista-scroll { flex: 1; overflow-y: auto; }

/* Redesenho da lista (2026-08-19) - achado real na pesquisa de
   referências (repos de WhatsApp clone): lista real não separa item por
   item com borda, o próprio hover/estado ativo já organiza visualmente;
   borda constante deixava a lista "quadriculada" demais numa conversa
   longa. Trocado por padding maior + transição suave. */
.conversas-lista-item {
  display: flex; align-items: center; gap: 0.8rem; padding: 0.7rem 1.1rem;
  cursor: pointer; background: none; width: 100%; border-left: 3px solid transparent;
  text-align: left; font-family: var(--body); color: var(--ink);
  transition: background 0.12s ease, border-color 0.12s ease;
}
.conversas-lista-item:hover { background: var(--bg-alt); }
.conversas-lista-item.is-ativa { background: var(--bg-alt); border-left-color: var(--primary); }
.conversas-lista-item-info { flex: 1; min-width: 0; }
.conversas-lista-item-topo { display: flex; justify-content: space-between; align-items: baseline; gap: 0.5rem; }
.conversas-lista-item-nome { font-weight: 600; font-size: 0.92rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.conversas-lista-item-hora { font-size: 0.7rem; color: var(--ink-dim); white-space: nowrap; flex: 0 0 auto; }
.conversas-lista-item-baixo { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; margin-top: 0.15rem; }
.conversas-lista-item-preview { font-size: 0.82rem; color: var(--ink-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Não lida - nome+prévia em destaque, mesmo sinal do WhatsApp real (antes
   só o número do badge indicava isso, fácil de não notar de relance). */
.conversas-lista-item.is-nao-lida .conversas-lista-item-nome { font-weight: 800; }
.conversas-lista-item.is-nao-lida .conversas-lista-item-preview { color: var(--ink); font-weight: 600; }
.conversas-lista-item.is-nao-lida .conversas-lista-item-hora { color: var(--primary); font-weight: 700; }
.conversas-badge {
  background: var(--accent); color: #fff; font-size: 0.7rem; font-weight: 800;
  border-radius: 999px; min-width: 1.1rem; height: 1.1rem; display: inline-flex;
  align-items: center; justify-content: center; padding: 0 0.3rem; flex: 0 0 auto;
}
.conversas-lista-vazia { padding: 2rem 1.2rem; text-align: center; color: var(--ink-dim); font-size: 0.9rem; }

.conversas-thread {
  flex: 1; display: flex; flex-direction: column; min-width: 0;
  background-color: var(--bg);
  background-image: radial-gradient(var(--border) 0.6px, transparent 0.6px);
  background-size: 22px 22px;
}
.conversas-thread-empty {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0.6rem; color: var(--ink-dim);
}
.conversas-thread-empty[hidden] { display: none; }
.conversas-thread-empty[hidden] { display: none; }
.conversas-thread-empty svg { width: 32px; height: 32px; opacity: 0.5; }
.conversas-thread-ativa { display: flex; flex-direction: column; height: 100%; }
.conversas-thread-ativa[hidden] { display: none; }
.conversas-thread-header {
  flex: 0 0 auto; padding: 0.7rem 1.5rem; background: var(--card); border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 0.8rem;
}
.conversas-thread-header-info { flex: 1; min-width: 0; }
.conversas-thread-header-info span:first-child { display: block; font-family: var(--display); font-weight: 600; font-size: 1.05rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.conversas-thread-telefone { font-size: 0.78rem; color: var(--ink-dim); }
.conversas-ficha-link { flex: 0 0 auto; font-size: 0.82rem; font-weight: 600; white-space: nowrap; }
.conversas-ficha-link[hidden] { display: none; }
/* Cabeçalho clicável (2026-08-20) - abre o painel de mídia/links. Reset de
   <button> pra não parecer botão (sem borda/fundo próprio), só um hover
   sutil avisando que é clicável. */
.conversas-thread-header-clicavel {
  display: flex; align-items: center; gap: 0.8rem; flex: 1; min-width: 0;
  background: none; border: none; padding: 0.2rem; margin: -0.2rem; border-radius: 8px;
  cursor: pointer; text-align: left; color: inherit; font: inherit;
}
.conversas-thread-header-clicavel:hover { background: var(--bg-alt); }

/* Painel de mídia/links (2026-08-20) - desliza da direita, mesmo padrão
   de overlay+aside de um drawer comum. */
.conversas-midias-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,0.3); z-index: 45;
}
.conversas-midias-overlay[hidden] { display: none; }
.conversas-midias-painel {
  position: fixed; top: 0; right: 0; bottom: 0; width: 340px; max-width: 90vw; z-index: 46;
  background: var(--card); box-shadow: var(--shadow); display: flex; flex-direction: column;
  border-left: 1px solid var(--border);
}
.conversas-midias-painel[hidden] { display: none; }
.conversas-midias-header {
  flex: 0 0 auto; padding: 1rem 1.2rem; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between;
  font-family: var(--display); font-weight: 700; font-size: 1rem;
}
.conversas-midias-header button {
  background: none; border: none; color: var(--ink-dim); font-size: 1.3rem; line-height: 1; cursor: pointer;
}
.conversas-midias-tabs { flex: 0 0 auto; display: flex; border-bottom: 1px solid var(--border); }
.conversas-midias-tab {
  flex: 1; background: none; border: none; padding: 0.7rem 0.5rem; font-size: 0.82rem; font-weight: 600;
  color: var(--ink-dim); cursor: pointer; border-bottom: 2px solid transparent;
}
.conversas-midias-tab.is-ativa { color: var(--primary); border-bottom-color: var(--primary); }
.conversas-midias-corpo { flex: 1; overflow-y: auto; padding: 1rem; }
.conversas-midias-vazio { text-align: center; color: var(--ink-dim); font-size: 0.85rem; padding: 2rem 1rem; }
.conversas-midias-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.4rem; }
.conversas-midias-grid-item {
  display: block; aspect-ratio: 1; border-radius: 6px; overflow: hidden; background: var(--bg-alt);
}
.conversas-midias-grid-item img, .conversas-midias-grid-item video { width: 100%; height: 100%; object-fit: cover; }
.conversas-midias-grid-audio { display: flex; align-items: center; justify-content: center; font-size: 1.6rem; }
.conversas-midias-lista-item {
  display: flex; align-items: center; gap: 0.7rem; padding: 0.6rem 0.3rem; border-radius: 8px;
  text-decoration: none; color: var(--ink);
}
.conversas-midias-lista-item:hover { background: var(--bg-alt); }
.conversas-midias-lista-icone { font-size: 1.3rem; flex: 0 0 auto; }
.conversas-midias-lista-texto { min-width: 0; display: flex; flex-direction: column; }
.conversas-midias-lista-texto strong { font-size: 0.85rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.conversas-midias-lista-texto small { font-size: 0.72rem; color: var(--ink-dim); }

.conversas-mensagens { flex: 1; overflow-y: auto; padding: 1.2rem 1.5rem; display: flex; flex-direction: column; gap: 0.4rem; }
.conversas-msg {
  max-width: 65%; padding: 0.5rem 0.7rem 0.4rem; border-radius: 10px; font-size: 0.9rem; line-height: 1.4;
  position: relative; box-shadow: 0 1px 1px rgba(0,0,0,0.08);
}
.conversas-msg.recebida { align-self: flex-start; background: var(--card); border: 1px solid var(--border); border-top-left-radius: 2px; }
.conversas-msg.enviada { align-self: flex-end; background: var(--primary); color: #fff; border-top-right-radius: 2px; }
/* Sticker (2026-08-20) - o real WhatsApp não desenha bolha nenhuma em
   volta de um sticker (fundo transparente, sem moldura/rabinho, bem menor
   que uma foto normal) - sem isso ficava um quadrado grande com fundo
   branco/verde atrás da imagem, "feio" comparado ao app real (feedback
   testando ao vivo). */
.conversas-msg.is-sticker {
  background: none !important; border: none !important; box-shadow: none; padding: 0;
  max-width: 130px;
}
.conversas-msg.is-sticker::before { display: none; }
.conversas-msg-sticker { display: block; width: 100%; height: auto; }
/* "Rabinho" da bolha (Bloco 3, 2026-08-19) - triângulo CSS puro no canto
   cortado acima, mesmo truque de border transparente usado nas referências
   de bolha de chat pesquisadas (sem imagem, sem framework). */
.conversas-msg.recebida::before {
  content: ""; position: absolute; top: 0; left: -7px; width: 0; height: 0;
  border-style: solid; border-width: 0 8px 8px 0;
  border-color: transparent var(--card) transparent transparent;
}
.conversas-msg.enviada::before {
  content: ""; position: absolute; top: 0; right: -7px; width: 0; height: 0;
  border-style: solid; border-width: 0 0 8px 8px;
  border-color: transparent transparent transparent var(--primary);
}

/* Divisor de dia (Bloco 3, 2026-08-19). */
.conversas-dia-divisor { display: flex; justify-content: center; margin: 0.5rem 0; }
.conversas-dia-divisor span {
  background: var(--bg-alt); color: var(--ink-dim); font-size: 0.72rem; font-weight: 600;
  padding: 0.25rem 0.7rem; border-radius: 999px;
}
.conversas-msg-meta { display: flex; justify-content: flex-end; align-items: center; gap: 0.25rem; font-size: 0.67rem; margin-top: 0.2rem; opacity: 0.75; }
.conversas-msg-meta svg { width: 14px; height: 14px; }
.conversas-msg-meta .is-lida { color: #53bdeb; opacity: 1; }
.conversas-msg-meta .is-falha { color: #e2685a; opacity: 1; }

/* Ações da bolha (2026-08-20, reprojetado) - achado real testando ao
   vivo: cada ação virando um ícone flutuante próprio (editar, apagar,
   reagir, encaminhar, responder, salvar) formava um "cercadinho" poluído
   em volta da bolha. Agora só 2 ícones no máximo: reagir (ação rápida,
   fica em destaque) e um "⋮" que abre a lista com o resto (ver
   .conversas-menu-acoes-painel abaixo e abrirMenuAcoes() no JS). */
.conversas-msg-reagir-btn, .conversas-msg-menu-btn {
  position: absolute; top: -8px; width: 20px; height: 20px;
  border-radius: 50%; border: none; background: var(--bg-alt, #eee); color: inherit;
  font-size: 0.8rem; line-height: 1; cursor: pointer; display: none;
  align-items: center; justify-content: center; padding: 0;
}
.conversas-msg-reagir-btn { right: -8px; }
.conversas-msg-menu-btn { right: 16px; font-weight: 700; }
.conversas-msg:hover .conversas-msg-reagir-btn,
.conversas-msg:hover .conversas-msg-menu-btn { display: flex; }
.conversas-msg-reacao {
  position: absolute; bottom: -10px; right: 6px; background: var(--card);
  border: 1px solid var(--border); border-radius: 999px; padding: 0.05rem 0.3rem;
  font-size: 0.85rem; line-height: 1.3; box-shadow: var(--shadow);
}
/* position/top/left vêm de posicionarFlutuante() no JS agora (2026-08-20)
   - preso ao viewport (position: fixed), não mais relativo à bolha, pra
   nunca mais vazar pra fora da área visível numa mensagem recebida perto
   da borda esquerda da tela (achado real testando ao vivo). */
.conversas-reacao-painel {
  z-index: 30; background: var(--card); border: 1px solid var(--border); border-radius: 999px;
  box-shadow: var(--shadow); padding: 0.3rem 0.4rem; display: flex; gap: 0.15rem;
}
.conversas-reacao-item {
  background: none; border: none; font-size: 1.15rem; cursor: pointer;
  padding: 0.15rem; border-radius: 50%; line-height: 1;
}
.conversas-reacao-item:hover, .conversas-reacao-item.is-ativa { background: var(--bg-alt); }

/* Painel do menu "⋮" e do encaminhar (que abre a partir de um item do
   menu agora, ver acao === 'encaminhar' no JS) compartilham o mesmo
   visual - lista vertical simples, uma ação por linha. */
.conversas-menu-acoes-painel, .conversas-encaminhar-painel {
  z-index: 30; width: 200px;
  max-height: 240px; overflow-y: auto;
  background: var(--card); border: 1px solid var(--border); border-radius: 10px;
  box-shadow: var(--shadow); padding: 0.3rem;
}
.conversas-menu-acoes-item, .conversas-encaminhar-item {
  display: block; width: 100%; text-align: left; background: none; border: none;
  padding: 0.45rem 0.6rem; border-radius: 6px; cursor: pointer; font-size: 0.85rem; color: var(--ink);
}
.conversas-menu-acoes-item:hover, .conversas-encaminhar-item:hover { background: var(--bg-alt); }
.conversas-menu-acoes-item.is-perigo { color: var(--danger, #c0392b); }
.conversas-encaminhar-vazio { padding: 0.6rem; font-size: 0.8rem; color: var(--ink-dim); }

/* Reenviar (2026-08-20, redesenhado 2026-08-20) - primeira versão era um
   badge circular sobreposto na bolha, igual editar/apagar/reagir, mas
   nesse tamanho (~20px) virava só uma bolinha vermelha ilegível (feedback
   real testando ao vivo). Virou link de texto na própria linha de
   metadados (junto do relógio de falha) - continua só existindo quando
   status === "falhou" (raro), mas agora é legível e óbvio sem precisar
   de hover pra descobrir. */
.conversas-msg-reenviar-link {
  background: none; border: none; padding: 0; margin: 0; cursor: pointer;
  color: var(--danger, #e2685a); font-size: inherit; text-decoration: underline;
  font-weight: 600;
}
.conversas-msg-reenviar-link:disabled { opacity: 0.5; cursor: default; text-decoration: none; }

/* Buscar dentro da conversa (Bloco 1, 2026-08-19). */
.conversas-busca-thread {
  display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem 1rem;
  border-bottom: 1px solid var(--border); background: var(--bg-alt); flex: 0 0 auto;
}
/* Achado real (2026-08-20): mesmo gotcha já documentado em outro lugar
   deste arquivo pro .clinica-chat-painel - uma classe com "display"
   explícito sempre vence o [hidden] do HTML (mesma especificidade, a
   regra do autor carrega depois da do user-agent), então o "x" que só
   fazia `buscaThreadBar.hidden = true` nunca escondia nada de verdade. */
.conversas-busca-thread[hidden] { display: none; }
.conversas-busca-thread svg { width: 16px; height: 16px; color: var(--ink-dim); flex: 0 0 auto; }
.conversas-busca-thread input {
  flex: 1; border: none; background: none; font: inherit; font-size: 0.88rem; color: var(--ink);
}
.conversas-busca-thread input:focus { outline: none; }
.conversas-busca-thread span { font-size: 0.78rem; color: var(--ink-dim); white-space: nowrap; }
.conversas-busca-thread button {
  background: none; border: none; color: var(--ink-dim); font-size: 1.2rem; line-height: 1;
  cursor: pointer; padding: 0.1rem 0.3rem;
}
.conversas-msg.is-busca-apagada { opacity: 0.35; }
.conversas-msg.is-busca-match { opacity: 1; box-shadow: 0 0 0 2px var(--accent, #c9962e); }
.conversas-msg.is-busca-atual { box-shadow: 0 0 0 2px var(--primary); }

/* Áudio (Bloco 2, 2026-08-19). */
.conversas-audio-btn {
  background: none; border: none; font-size: 1.2rem; line-height: 1; cursor: pointer;
  padding: 0.4rem; border-radius: 50%; align-self: flex-end; flex: 0 0 auto;
}
.conversas-audio-btn:hover { background: var(--bg-alt); }
.conversas-audio-btn[hidden] { display: none; }
.conversas-msg-anexo-audio { display: block; max-width: 220px; height: 36px; margin-bottom: 0.2rem; }
.conversas-audio-gravando {
  display: flex; align-items: center; gap: 0.6rem; padding: 0.6rem 1.5rem;
  background: var(--card); border-top: 1px solid var(--border); font-size: 0.85rem;
}
.conversas-audio-gravando[hidden] { display: none; }
.conversas-audio-ponto {
  width: 10px; height: 10px; border-radius: 50%; background: var(--danger, #c0392b);
  animation: conversasAudioPulso 1.1s ease-in-out infinite;
}
@keyframes conversasAudioPulso { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }
#conversasAudioTempo { font-variant-numeric: tabular-nums; color: var(--ink-dim); }
#conversasAudioCancelar {
  background: none; border: none; color: var(--ink-dim); cursor: pointer;
  text-decoration: underline; font-size: 0.85rem; margin-left: auto;
}

.conversas-editando-aviso {
  flex: 0 0 auto; padding: 0.4rem 1.5rem; font-size: 0.8rem; color: var(--ink-dim);
  background: var(--bg-alt); border-top: 1px solid var(--border);
  display: flex; align-items: center; gap: 0.5rem;
}
.conversas-editando-aviso[hidden] { display: none; }
.conversas-editando-aviso button {
  background: none; border: none; color: var(--primary); cursor: pointer;
  font-size: 0.8rem; font-weight: 600; padding: 0; text-decoration: underline;
}
/* Responder citando (2026-08-20). */
#conversasRespondendoPreview {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 320px;
}
.conversas-msg-responder-btn {
  position: absolute; top: -8px; left: 40px; width: 20px; height: 20px;
  border-radius: 50%; border: none; background: var(--bg-alt, #eee); color: inherit;
  font-size: 0.8rem; line-height: 1; cursor: pointer; display: none;
  align-items: center; justify-content: center; padding: 0;
}
.conversas-msg:hover .conversas-msg-responder-btn { display: flex; }
.conversas-msg-citacao {
  border-left: 3px solid rgba(255,255,255,0.5); background: rgba(0,0,0,0.08);
  border-radius: 6px; padding: 0.25rem 0.5rem; margin-bottom: 0.3rem;
  font-size: 0.78rem; opacity: 0.85; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap;
}
.conversas-msg.recebida .conversas-msg-citacao { border-left-color: var(--primary); background: var(--bg-alt); }

/* Indicador de envio de anexo/áudio (2026-08-20) - achado real: a
   ampulheta trocando no botão sozinha não convencia que algo estava
   acontecendo de verdade. Spinner girando de verdade + texto, mesma
   barra visual da "Editando mensagem" acima. */
.conversas-enviando-aviso {
  flex: 0 0 auto; padding: 0.4rem 1.5rem; font-size: 0.8rem; color: var(--ink-dim);
  background: var(--bg-alt); border-top: 1px solid var(--border);
  display: flex; align-items: center; gap: 0.5rem;
}
.conversas-enviando-aviso[hidden] { display: none; }
.conversas-spinner {
  width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid var(--border); border-top-color: var(--primary);
  animation: conversasSpinnerGira 0.7s linear infinite; flex: 0 0 auto;
}
@keyframes conversasSpinnerGira { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .conversas-spinner { animation: none; }
}
/* "x" de cancelar envio (2026-08-20, pedido do usuário testando ao vivo) -
   empurrado pro canto direito da barra via margin-left:auto, discreto até
   passar o mouse (mesma linguagem visual dos outros botões pequenos). */
.conversas-enviando-cancelar {
  margin-left: auto; width: 20px; height: 20px; border-radius: 50%;
  border: none; background: none; color: var(--ink-dim); cursor: pointer;
  font-size: 1rem; line-height: 1; display: flex; align-items: center; justify-content: center;
  flex: 0 0 auto;
}
.conversas-enviando-cancelar:hover { background: var(--border); color: var(--ink); }

.conversas-msg-anexo-imagem { display: block; margin-bottom: 0.3rem; }
.conversas-msg-anexo-imagem img { max-width: 220px; max-height: 220px; border-radius: 8px; display: block; }
.conversas-msg-anexo-video { max-width: 220px; max-height: 220px; border-radius: 8px; display: block; margin-bottom: 0.3rem; }
.conversas-msg-anexo-arquivo {
  display: flex; align-items: center; gap: 0.4rem; padding: 0.4rem 0.6rem;
  background: rgba(0,0,0,0.08); border-radius: 8px; margin-bottom: 0.3rem;
  font-size: 0.82rem; color: inherit; text-decoration: none; word-break: break-all;
}
.conversas-msg-anexo-arquivo:hover { background: rgba(0,0,0,0.14); text-decoration: none; }

.conversas-anexo-btn {
  background: none; border: none; font-size: 1.2rem; line-height: 1; cursor: pointer;
  padding: 0.4rem; border-radius: 50%; align-self: flex-end; flex: 0 0 auto;
}
.conversas-anexo-btn:hover { background: var(--bg-alt); }
.conversas-anexo-btn[hidden] { display: none; }

.conversas-emoji-wrap { position: relative; flex: 0 0 auto; align-self: flex-end; }
.conversas-emoji-btn {
  background: none; border: none; font-size: 1.3rem; line-height: 1; cursor: pointer;
  padding: 0.4rem; border-radius: 50%;
}
.conversas-emoji-btn:hover { background: var(--bg-alt); }
/* Ampliado (2026-08-20) - achado real testando ao vivo: 220px/6 colunas
   pra só 30 emojis "aparecia pouco" perto do picker de verdade do
   WhatsApp. Agora 320px/8 colunas com ~190 emojis (ver EMOJIS em
   conversas.js) - precisa rolar (max-height + overflow-y), mesmo padrão
   do picker real. */
.conversas-emoji-painel {
  position: absolute; bottom: calc(100% + 8px); left: 0; z-index: 30;
  background: var(--card); border: 1px solid var(--border); border-radius: 12px;
  box-shadow: var(--shadow); padding: 0.6rem; width: 320px; max-width: 90vw; max-height: 280px;
  overflow-y: auto; display: grid; grid-template-columns: repeat(8, 1fr); gap: 0.1rem;
}
.conversas-emoji-painel[hidden] { display: none; }
.conversas-emoji-item {
  background: none; border: none; font-size: 1.35rem; cursor: pointer;
  padding: 0.3rem; border-radius: 6px; line-height: 1.3;
}
.conversas-emoji-item:hover { background: var(--bg-alt); }

/* Sticker/GIF salvos (2026-08-20) - mesmo padrão do painel de emoji
   acima (posição, borda, sombra), grid de thumbnails quadradas em vez de
   texto/glifo. */
.conversas-stickers-painel {
  position: absolute; bottom: calc(100% + 8px); left: 0; z-index: 30;
  background: var(--card); border: 1px solid var(--border); border-radius: 12px;
  box-shadow: var(--shadow); padding: 0.5rem; width: 260px; max-width: 90vw; max-height: 280px;
  overflow-y: auto; display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.4rem;
}
.conversas-stickers-painel[hidden] { display: none; }
.conversas-sticker-item {
  background: none; border: none; cursor: pointer; padding: 0; border-radius: 8px;
  aspect-ratio: 1; overflow: hidden; display: flex; align-items: center; justify-content: center;
}
.conversas-sticker-item:hover { background: var(--bg-alt); }
.conversas-sticker-item:disabled { opacity: 0.5; cursor: default; }
.conversas-sticker-item img, .conversas-sticker-item video { width: 100%; height: 100%; object-fit: contain; }
.conversas-stickers-vazio { grid-column: 1 / -1; padding: 0.6rem; font-size: 0.78rem; color: var(--ink-dim); text-align: center; }

.conversas-form { flex: 0 0 auto; display: flex; align-items: flex-end; gap: 0.6rem; padding: 0.9rem 1.5rem; background: var(--card); border-top: 1px solid var(--border); }
/* Achado real (prints do cliente, 2026-08-19): a pílula usava
   background:var(--bg), quase idêntico a var(--card) (fundo desta barra)
   nos dois temas - contraste baixo demais, a caixa "sumia" virando um
   risco cinza fraco em vez de uma pílula nítida tipo WhatsApp de verdade.
   Trocado pra var(--bg-alt) (mais distante de --card) + borda mais forte
   + padding maior, pra realmente se destacar da barra ao redor. */
/* Corretor ortográfico embutido (2026-08-20, ver assets/ortografia.js) -
   reestruturado pra caber o <div> de fundo por trás do <textarea>: o
   VISUAL (borda, fundo, raio) que antes vivia direto no textarea agora
   vive no wrap, porque o textarea precisa ficar com fundo transparente
   pra deixar o sublinhado vermelho do <div> por trás aparecer através
   dele. Achado real (print do cliente, 2026-08-19, preservado aqui):
   resize:vertical só cresce pra baixo, sem sentido numa barra grudada no
   rodapé - resize:none + crescimento automático via JS continua igual. */
.conversas-ortografia-wrap {
  position: relative; flex: 1; min-width: 0; display: flex;
  border: 1px solid var(--border); border-radius: 1.3rem; background: var(--bg-alt);
}
.conversas-ortografia-wrap:focus-within {
  border-color: var(--primary); background: var(--card);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 15%, transparent);
}
/* fundo e textarea PRECISAM ter fonte/padding/quebra de linha idênticos,
   senão o sublinhado desalinha da palavra real - por isso os dois
   compartilham a mesma regra base aqui. */
.conversas-ortografia-fundo, .conversas-ortografia-wrap textarea {
  padding: 0.75rem 1.1rem; font-family: var(--body); font-size: 0.92rem; line-height: 1.35;
  white-space: pre-wrap; word-wrap: break-word; overflow-wrap: break-word;
}
.conversas-ortografia-fundo {
  position: absolute; inset: 0; margin: 0; overflow: hidden;
  color: transparent; pointer-events: none; z-index: 0;
}
/* Achado real testando ao vivo (2026-08-20): 2px de espessura ficava
   grosso/"feio" perto do sublinhado fino que corretor nativo de SO tem -
   afinado pra 1px + um pouco de transparência, mais discreto sem deixar
   de ser visível. */
.conversas-ortografia-fundo mark {
  background: none; color: transparent;
  text-decoration: underline wavy; text-decoration-color: color-mix(in srgb, var(--danger, #e2685a) 75%, transparent);
  text-decoration-thickness: 1px; text-underline-offset: 3px;
}
/* Sugestões de correção (2026-08-20) - clicar numa palavra sublinhada
   abre isto, mesmo visual dos outros painéis flutuantes do app. */
.conversas-ortografia-sugestoes {
  position: fixed; z-index: 40; min-width: 140px; max-width: 240px;
  background: var(--card); border: 1px solid var(--border); border-radius: 10px;
  box-shadow: var(--shadow); padding: 0.3rem;
}
.conversas-ortografia-sugestoes button {
  display: block; width: 100%; text-align: left; background: none; border: none;
  padding: 0.4rem 0.6rem; border-radius: 6px; cursor: pointer; font-size: 0.85rem; color: var(--ink);
}
.conversas-ortografia-sugestoes button:hover { background: var(--bg-alt); }
.conversas-ortografia-sugestoes .conversas-ortografia-vazio {
  padding: 0.4rem 0.6rem; font-size: 0.78rem; color: var(--ink-dim);
}
.conversas-ortografia-wrap textarea {
  position: relative; z-index: 1; flex: 1; resize: none;
  min-height: 2.9rem; max-height: 12rem; min-width: 0; border-radius: inherit;
  border: none; background: transparent; color: var(--ink);
}
.conversas-ortografia-wrap textarea::placeholder { color: var(--ink-dim); }
.conversas-ortografia-wrap textarea:focus { outline: none; }
.conversas-form button { align-self: flex-end; border-radius: 999px; }

/* Achado real (prints do celular do cliente, 2026-08-18): em telas
   estreitas, os botões de anexo/emoji + "Enviar" (com texto, não só ícone)
   sobravam pouca largura pro textarea - como é um <textarea>, o texto
   QUEBRA em vez de cortar, esmagando o placeholder em 2 linhas dentro da
   bolha arredondada. Aperta o padding/gap do form e esconde o rótulo
   "Enviar" (ícone sozinho já é auto-explicativo, mesmo padrão do
   mini-chat) - aria-label no botão mantém a acessibilidade. */
@media (max-width: 480px) {
  .conversas-form { padding: 0.6rem 0.7rem; gap: 0.35rem; }
  .conversas-form button[type="submit"] { padding: 0.6rem 0.75rem; }
  .conversas-enviar-label { display: none; }
  .conversas-anexo-btn, .conversas-emoji-btn { padding: 0.3rem; }
}

.conversas-voltar-btn { display: none; font-size: 1.4rem; line-height: 1; padding: 0.3rem 0.5rem; }

/* Achado real (screenshot do celular do cliente, 2026-08-06): o layout de
   duas colunas (lista + conversa) nunca tinha ajuste nenhum pra tela
   estreita - a lista sozinha (340px fixos) já quase enchia a tela, e a
   conversa ao lado vazava pra fora, cortada numa tira fina na borda
   direita. Mesmo padrão que qualquer app de WhatsApp de verdade usa no
   celular: uma coluna por vez, troca com um botão de voltar (JS em
   assets/conversas.js adiciona/remove .is-thread-aberta em .conversas-layout
   ao abrir/fechar uma conversa). */
@media (max-width: 720px) {
  .conversas-layout { position: relative; overflow: hidden; }
  .conversas-lista { width: 100% !important; border-right: none; }
  .conversas-lista-resize, .conversas-lista-colapsar-btn { display: none; }
  .conversas-thread { position: absolute; inset: 0; transform: translateX(100%); transition: transform 0.2s ease; }
  .conversas-layout.is-thread-aberta .conversas-lista { display: none; }
  .conversas-layout.is-thread-aberta .conversas-thread { transform: translateX(0); }
  .conversas-voltar-btn { display: inline-flex; align-items: center; justify-content: center; }
  @media (prefers-reduced-motion: reduce) { .conversas-thread { transition: none; } }
}

/* --- Perfil do WhatsApp Business --- */
.wperfil-voltar { display: inline-flex; align-items: center; gap: 0.3rem; font-size: 0.85rem; font-weight: 600; }
.wperfil-card-title { font-size: 1.05rem; margin-bottom: 1rem; }
.wperfil-loading { color: var(--ink-dim); text-align: center; }
.wperfil-aviso { padding: 0.6rem 0.9rem; border-radius: var(--radius-sm); font-size: 0.88rem; margin-bottom: 1rem; }
.wperfil-aviso.is-erro { background: #f6e3df; color: #7a2e22; }
:root[data-theme="dark"] .wperfil-aviso.is-erro { background: #3d2420; color: #f0a998; }
.wperfil-aviso.is-sucesso { background: var(--bg-alt); color: var(--ink-dim); }
.wperfil-foto-row { display: flex; align-items: center; gap: 1.2rem; }
.wperfil-foto { width: 72px; height: 72px; border-radius: 999px; object-fit: cover; background: var(--bg-alt); flex: 0 0 auto; }
.wperfil-hint { font-size: 0.78rem; color: var(--ink-dim); margin-top: 0.4rem; }
.wperfil-counter { display: block; font-size: 0.75rem; color: var(--ink-dim); text-align: right; margin-top: 0.2rem; }
.wperfil-salvar { width: 100%; margin-top: 0.3rem; }
.field label svg { width: 15px; height: 15px; vertical-align: -2px; margin-right: 0.2rem; }

/* --- Mensagens automáticas --- */
.msgauto-header-row, .msgauto-row {
  display: grid; grid-template-columns: 1fr 160px 160px; align-items: center; gap: 1rem;
  padding: 0.7rem 1rem;
}
.msgauto-header-row {
  font-size: 0.76rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em;
  color: var(--ink-dim); border-bottom: 1px solid var(--border);
}
.msgauto-header-row span:not(:first-child) { justify-self: center; }
.msgauto-row { border-bottom: 1px solid var(--border); }
.msgauto-row:last-child { border-bottom: none; }
.msgauto-row .msgauto-switch { justify-self: center; }

.msgauto-switch { position: relative; display: inline-block; width: 40px; height: 22px; flex: 0 0 auto; }
.msgauto-switch input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; z-index: 1; }
.msgauto-switch-track { position: absolute; inset: 0; background: var(--border); border-radius: 999px; transition: background 0.15s ease; }
.msgauto-switch-track::before {
  content: ""; position: absolute; width: 16px; height: 16px; left: 3px; top: 3px;
  background: #fff; border-radius: 999px; transition: transform 0.15s ease; box-shadow: 0 1px 2px rgba(0,0,0,0.25);
}
.msgauto-switch input:checked + .msgauto-switch-track { background: var(--primary); }
.msgauto-switch input:checked + .msgauto-switch-track::before { transform: translateX(18px); }
.msgauto-switch input:focus-visible + .msgauto-switch-track { outline: 2px solid var(--accent-light); outline-offset: 2px; }
.msgauto-switch input:disabled { cursor: not-allowed; }
.msgauto-switch input:disabled + .msgauto-switch-track { opacity: 0.5; }

@media (max-width: 560px) {
  .msgauto-header-row, .msgauto-row { grid-template-columns: 1fr 60px 60px; gap: 0.4rem; padding: 0.6rem 0.6rem; }
}

/* --- Pacotes (Recepção) --- */
.pacotes-grid { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.pacote-chip {
  display: flex; align-items: center; gap: 0.5rem; padding: 0.55rem 1rem; border-radius: 999px;
  background: var(--bg-alt); border: 1px solid var(--border); color: var(--ink);
  font-family: var(--body); font-size: 0.88rem; font-weight: 600;
}
.pacote-chip:hover { background: var(--card); border-color: var(--accent); }
.pacote-chip.is-aberto { background: var(--primary); color: #fff; border-color: var(--primary); }
.pacote-chip-preco { color: var(--accent); font-weight: 700; }
.pacote-chip.is-aberto .pacote-chip-preco { color: var(--accent-light); }
.pacote-descricao { margin-top: 0.9rem; padding: 0.8rem 1rem; background: var(--bg-alt); border-radius: var(--radius-sm); font-size: 0.9rem; }
.pacote-descricao[hidden] { display: none; }

/* --- Horários do dia (Agenda) --- */
/* --- Observação do dia (2026-08-14) --- */
.dia-observacoes-wrap:empty { display: none; }
.dia-observacoes-wrap { display: flex; flex-direction: column; gap: 0.6rem; margin-bottom: 1rem; }
/* [hidden] perde pra "display:flex" acima sem isto (mesmo gotcha que já
   aconteceu antes neste projeto - ver o mesmo comentário no widget de
   ausência em paciente_perfil.php) - achado real do cliente 2026-09-08:
   "não acontece nada clicando no recados do dia" - o wrap NUNCA
   escondia de verdade, então fechar (hidden=true) parecia não fazer
   nada porque continuava visível por baixo o tempo todo. */
.dia-observacoes-wrap[hidden] { display: none !important; }
.dia-observacao-row {
  display: flex; flex-direction: column; gap: 0.35rem; padding: 0.7rem 0.8rem;
  border-radius: var(--radius-sm); border: 1px solid var(--border); background: var(--bg-alt);
}
.dia-observacao-nome { font-size: 0.78rem; font-weight: 700; color: var(--ink-dim); text-transform: uppercase; letter-spacing: 0.02em; }
.dia-observacao-texto {
  width: 100%; min-height: 2.4rem; resize: vertical; font-family: var(--body); font-size: 0.9rem;
  color: var(--ink); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 0.5rem 0.6rem;
  background: var(--card);
}
.dia-observacao-texto:disabled { background: transparent; border-style: dashed; color: var(--ink-dim); resize: none; }
.dia-observacao-salvar { align-self: flex-end; font-size: 0.82rem; padding: 0.35rem 0.9rem; }

/* Recorrência de recado (2026-09-15, pedido da Thamyres via mestre) -
   badge da série + prompt "só hoje/esse e os próximos" + painel
   "Repetir esse recado", tudo dentro da mesma caixinha de sempre
   (.dia-observacao-row), sem modal por cima de modal (decisão via
   AskUserQuestion). */
.dia-observacao-recorrencia-badge {
  display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
  font-size: 0.78rem; color: var(--ink-dim);
}
.dia-observacao-recorrencia-desativar {
  font-size: 0.75rem; padding: 0.2rem 0.5rem; background: transparent;
  color: var(--danger, #b02a2a); border: 1px solid var(--border);
}
.dia-observacao-escolha {
  display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap;
  font-size: 0.82rem; align-self: flex-end;
}
.dia-observacao-escolha button { font-size: 0.8rem; padding: 0.35rem 0.7rem; }
.dia-observacao-escolha-cancelar {
  background: transparent; color: var(--ink-dim); padding: 0.2rem 0.4rem;
}
.dia-observacao-repetir-link {
  align-self: flex-start; background: transparent; color: var(--primary);
  font-size: 0.8rem; font-weight: 600; padding: 0; text-align: left;
}
.dia-observacao-repetir-link:hover { background: transparent; text-decoration: underline; }
.dia-observacao-repetir-painel {
  display: flex; flex-direction: column; gap: 0.5rem; padding: 0.6rem;
  border-radius: var(--radius-sm); border: 1px dashed var(--border); background: var(--card);
}
/* [hidden] perde pra "display:flex" acima sem isto (mesmo gotcha já
   documentado em .dia-observacoes-wrap[hidden] logo acima neste mesmo
   arquivo) - achado real do mestre: o painel "Repetir esse recado"
   aparecia sempre ABERTO, sem precisar clicar em nada. */
.dia-observacao-repetir-painel[hidden] { display: none !important; }
.dia-observacao-repetir-painel select,
.dia-observacao-repetir-painel input[type="date"] { width: auto; }
.dia-observacao-repetir-dias { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.dia-observacao-repetir-dias label { display: flex; flex-direction: column; align-items: center; gap: 0.15rem; font-size: 0.72rem; color: var(--ink-dim); }
.dia-observacao-repetir-datas label { display: flex; align-items: center; gap: 0.4rem; font-size: 0.82rem; }
.dia-observacao-repetir-erro { color: var(--danger, #b02a2a); font-size: 0.78rem; }

/* Balãozinho de "esse dia tem observação" - só aparece quando existe
   conteúdo (ver aplicarBaloesObservacaoMes/Semana em calendar.js), zero
   pegada visual nos dias sem nada. Mesmo elemento/classe nas duas views
   (Mês injeta em .fc-daygrid-day-top, Semana em .agenda-semana-dia-header),
   só a posição muda por contexto. */
.clinica-dia-obs-balao { font-size: 0.85rem; margin-left: 0.3rem; cursor: default; }
/* .agenda-semana-dia-header já é flex (space-between) - o balão só entra
   como mais um item flex, sem precisar de position:absolute. */
.agenda-semana-dia-header .clinica-dia-obs-balao { font-size: 0.9rem; margin-left: 0; }

.dia-horarios-lista { max-height: 55vh; overflow-y: auto; display: flex; flex-direction: column; gap: 0.3rem; margin-bottom: 1rem; }
.dia-horario-row {
  display: flex; justify-content: space-between; align-items: center; width: 100%; gap: 0.6rem;
  padding: 0.4rem 0.8rem; border-radius: var(--radius-sm); border: 1px solid var(--border);
  background: var(--card); font-family: var(--body); font-size: 0.88rem; font-weight: 600; color: var(--ink);
  animation: diaHorarioEntrada 0.22s ease backwards;
  animation-delay: calc(min(var(--i, 0), 12) * 12ms);
}
@keyframes diaHorarioEntrada { from { opacity: 0; } to { opacity: 1; } }
/* [hidden] perde pra "display:flex" acima sem isto - mesmo gotcha do
   .dia-observacoes-wrap logo acima. Achado real do cliente 2026-09-08:
   "não acontece nada clicando em ver a madrugada" - as linhas 00h-06h
   NUNCA escondiam de verdade (apareciam sempre, mesmo com o toggle
   fechado), então clicar não tinha efeito visível nenhum. */
.dia-horario-row[hidden] { display: none !important; }
@media (prefers-reduced-motion: reduce) {
  .dia-horario-row { animation: none; }
}
/* "Linha do agora" (2026-09-08, pedido do cliente: "mais animações e
   cores") - só aparece quando o dia aberto é HOJE, na hora certa,
   pulso sutil só pra chamar o olho pra "você está aqui" sem competir
   com os selos de pendência de verdade. */
.dia-horario-agora { border-color: var(--primary); border-left-width: 3px; background: color-mix(in srgb, var(--primary) 6%, var(--card)); }
.dia-horario-agora .dia-horario-hora { color: var(--primary); position: relative; }
.dia-horario-agora .dia-horario-hora::before {
  content: ''; position: absolute; left: -0.6rem; top: 50%; width: 6px; height: 6px; border-radius: 50%;
  background: var(--primary); transform: translateY(-50%); animation: diaHorarioAgoraPulso 1.6s ease-in-out infinite;
}
@keyframes diaHorarioAgoraPulso { 0%, 100% { opacity: 1; box-shadow: 0 0 0 0 color-mix(in srgb, var(--primary) 50%, transparent); } 50% { opacity: 0.6; box-shadow: 0 0 0 4px transparent; } }
@media (prefers-reduced-motion: reduce) {
  .dia-horario-agora .dia-horario-hora::before { animation: none; }
}
.dia-horario-hora { min-width: 3.2rem; flex-shrink: 0; }
/* Um chip por profissional, de propósito - achado real 2026-08-04: um
   único estado "ocupado/livre" por horário escondia que dois
   profissionais podem ter (ou não) sessão no MESMO horário
   independentemente um do outro. */
.dia-horario-profissionais { display: flex; gap: 0.4rem; flex-wrap: wrap; justify-content: flex-end; flex: 1; }
/* Preenchimento sólido leve (2026-09-08, pedido do cliente: "quero
   cores, ícones") - antes só a borda/texto mudavam de cor, difícil de
   escanear rápido numa lista de 24 linhas x N profissionais; o fundo
   colorido (com opacidade, funciona nos dois temas) dá o mesmo "escaneio
   por cor" que um calendário de verdade tem. */
.dia-horario-prof-btn {
  border: 1px solid var(--border); border-radius: 999px; padding: 0.3rem 0.7rem; cursor: pointer;
  font-size: 0.76rem; font-weight: 600; font-family: var(--body); background: var(--card); color: var(--ink);
  max-width: 190px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  transition: transform 0.1s ease, box-shadow 0.1s ease;
}
.dia-horario-prof-btn:hover { transform: translateY(-1px); box-shadow: 0 2px 6px rgba(0,0,0,0.1); }
.dia-horario-prof-btn.is-livre { color: var(--success); border-color: var(--success); background: color-mix(in srgb, var(--success) 10%, var(--card)); }
.dia-horario-prof-btn.is-livre:hover { background: color-mix(in srgb, var(--success) 18%, var(--card)); }
.dia-horario-prof-btn.is-ocupado { background: color-mix(in srgb, var(--ink-dim) 12%, var(--card)); color: var(--ink-dim); font-weight: 400; border-color: transparent; }
.dia-horario-prof-btn.is-ocupado:hover { border-color: var(--primary); color: var(--ink); }

/* --- Seletor de cor do profissional (Minha conta / Equipe, 2026-08-06) --- */
.cor-swatches { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.cor-swatch {
  width: 2.1rem; height: 2.1rem; border-radius: 50%; border: 2px solid transparent;
  cursor: pointer; padding: 0; box-shadow: inset 0 0 0 1px rgba(0,0,0,0.12);
}
.cor-swatch:hover { transform: scale(1.08); }
.cor-swatch.is-selecionada { border-color: var(--ink); box-shadow: 0 0 0 2px var(--card), 0 0 0 4px var(--ink); }

/* Botão "voltar ao topo" (2026-08-10, pedido do cliente, global em todas as
   páginas via partials/nav.php) - canto esquerdo pra não brigar com o grupo
   de botões flutuantes da Recepção (direita, abaixo) nem com a barra de
   seleção em lote (z-index 50, bottom:0 largura inteira). */
.clinica-voltar-topo {
  position: fixed; left: 20px; bottom: 20px; z-index: 40;
  width: 44px; height: 44px; border-radius: 50%; border: 1px solid var(--border);
  background: var(--card); color: var(--ink-dim);
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 4px 14px rgba(0,0,0,0.15);
  opacity: 0; transform: translateY(8px); pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease, background 0.15s ease;
}
.clinica-voltar-topo.is-visible { opacity: 1; transform: translateY(0); pointer-events: auto; }
.clinica-voltar-topo:hover { background: var(--bg-alt); color: var(--ink); }
.clinica-voltar-topo-icon { transform: rotate(-90deg); }
@media (max-width: 560px) {
  .clinica-voltar-topo { left: 14px; bottom: 14px; width: 40px; height: 40px; }
}
@media (prefers-reduced-motion: reduce) {
  .clinica-voltar-topo { transition: opacity 0.2s ease; }
}

/* Botão-estrela de favoritar (2026-08-10, pedido do cliente) - inline junto
   do nome do paciente, mesmo espírito de .pendencia-badge (ícone pequeno,
   clicável, sem borda), mas com cor de destaque quando ativo. */
.favorito-btn {
  display: inline-flex; align-items: center; justify-content: center;
  background: none; border: none; padding: 0; margin-left: 0.3rem;
  cursor: pointer; color: var(--ink-dim); vertical-align: middle;
  width: 1.35rem; height: 1.35rem; flex: 0 0 auto;
}
/* Wrapper de gráfico via Chart.js (2026-08-26) - usado no card de
   satisfação do perfil do paciente e na aba Análises; altura fixa porque
   Chart.js com maintainAspectRatio:false precisa de um contêiner com
   altura definida (senão o canvas colapsa a 0px). */
.analises-chart-wrap { position: relative; height: 240px; }

.favorito-btn:hover { color: #c9962e; }
.favorito-btn.is-favorito { color: #c9962e; }
.favorito-btn:disabled { opacity: 0.6; cursor: wait; }
.favorito-btn svg { width: 100%; height: 100%; }

/* Botão de bloquear paciente (2026-08-26, pedido do cliente) - ao lado da
   estrelinha de favorito de propósito, mesmo padrão visual/estrutural,
   cor de alerta (var(--danger)) em vez de dourado quando ativo. */
.bloquear-btn {
  display: inline-flex; align-items: center; justify-content: center;
  background: none; border: none; padding: 0; margin-left: 0.2rem;
  cursor: pointer; color: var(--ink-dim); vertical-align: middle;
  width: 1.35rem; height: 1.35rem; flex: 0 0 auto;
}
.bloquear-btn:hover { color: var(--danger); }
.bloquear-btn.is-bloqueado { color: var(--danger); }
.bloquear-btn:disabled { opacity: 0.6; cursor: wait; }
.bloquear-btn svg { width: 100%; height: 100%; }

/* "😴 Marcar inativa / Reativar" (2026-09-14, pedido do cliente - caso
   da Charlene: "um ícone animado no perfil dela, uma explicação de que
   ela está inativa"). Estado ATIVO (data-inativo="0") é só um botão
   discreto, mesmo espírito de .favorito-btn/.bloquear-btn - some entre
   os outros selos até ser preciso. Estado INATIVO (data-inativo="1")
   vira o selo .pendencia-badge normal (mesmo formato de "🌟 Alta
   frequência"), com uma pulsação lenta e suave (ambiente, não
   estroboscópica - mesmo espírito de clinicaLuzesPulso) pra realmente
   chamar atenção de que esse paciente está fora do fluxo normal. */
.paciente-inativo-btn[data-inativo="0"] {
  display: inline-flex; align-items: center; justify-content: center;
  background: none; border: none; padding: 0; margin-left: 0.3rem;
  cursor: pointer; opacity: 0.55; vertical-align: middle;
  font-size: 1rem; line-height: 1; flex: 0 0 auto;
}
.paciente-inativo-btn[data-inativo="0"]:hover { opacity: 1; }
.paciente-inativo-btn[data-inativo="0"]:disabled { opacity: 0.4; cursor: wait; }
.paciente-inativo-btn[data-inativo="1"] {
  color: var(--ink-dim); font-weight: 700;
  animation: pacienteInativoPulso 2.6s ease-in-out infinite;
}
.paciente-inativo-btn[data-inativo="1"]:disabled { cursor: wait; }
@keyframes pacienteInativoPulso {
  0%, 100% { opacity: 0.55; }
  50% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .paciente-inativo-btn[data-inativo="1"] { animation: none; opacity: 0.85; }
}

/* Ícone inline em título de card (h2) - mesmo tamanho/alinhamento dos
   emojis usados nos outros cabeçalhos de card da Recepção (🎂, ⏳, 🗓️). */
.clinica-icon-inline { width: 1.05em; height: 1.05em; vertical-align: -0.15em; color: #c9962e; }

/* Chips de favoritos na Recepção (2026-08-10) - avatar + nome, clicável,
   layout em linha que quebra (flex-wrap no container pai). */
.favorito-chip {
  display: inline-flex; align-items: center; gap: 0.45rem;
  padding: 0.35rem 0.7rem 0.35rem 0.35rem; border-radius: 999px;
  background: var(--bg-alt); border: 1px solid var(--border); color: var(--ink);
}
.favorito-chip:hover { background: var(--card); border-color: #c9962e; text-decoration: none; }
.favorito-chip span { font-size: 0.9rem; font-weight: 600; }

/* --- Botões flutuantes da Recepção (só psicologia-brandao, 2026-08-06) --- */
/* Grupo em coluna (2026-08-08, 2º botão) - cada botão fica estático dentro
   do grupo, e é o GRUPO que é fixed/ancorado no canto; column-reverse
   empilha de baixo pra cima na ordem do DOM, então o 1º botão escrito no
   HTML nasce por cima do 2º, sem cada um calcular sua própria posição. */
.mep-caixa-grupo {
  position: fixed; right: 24px; bottom: 24px; z-index: 90;
  display: flex; flex-direction: column-reverse; align-items: flex-end; gap: 12px;
  transition: bottom 0.2s ease;
}
@media (prefers-reduced-motion: reduce) { .mep-caixa-grupo { transition: none; } }
.mep-caixa-btn {
  position: static;
  width: 56px; height: 56px; border-radius: 50%;
  background: linear-gradient(160deg, #f4d35e, #c9702e);
  border: 3px solid var(--card); box-shadow: 0 8px 20px rgba(0, 0, 0, 0.25);
  font-size: 1.7rem; line-height: 1; cursor: pointer; padding: 0; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  animation: mepCaixaFloat 3s ease-in-out infinite;
}
.mep-caixa-btn:hover { transform: scale(1.08) rotate(-4deg); }
.mep-caixa-btn.is-tocando { animation: mepCaixaTocando 0.26s ease; }
/* Botão de imagem (2026-08-08) - mesma base circular flutuante, só troca
   o fundo em degradê por uma foto (recorte circular via object-fit, sem
   precisar editar a imagem original). */
.mep-caixa-btn-img { background: var(--card); animation-delay: 0.4s; }
.mep-caixa-btn-img img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
@keyframes mepCaixaFloat {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-6px); }
}
@keyframes mepCaixaTocando {
  0% { transform: scale(1) rotate(0deg); }
  40% { transform: scale(1.25) rotate(10deg); }
  100% { transform: scale(1) rotate(0deg); }
}
@media (prefers-reduced-motion: reduce) {
  .mep-caixa-btn { animation: none; }
}
/* Menorzinho no celular (pedido do cliente) - continua no canto inferior
   direito, só ocupando menos espaço. */
@media (max-width: 640px) {
  .mep-caixa-grupo { right: 14px; bottom: 14px; gap: 8px; }
  .mep-caixa-btn { width: 42px; height: 42px; font-size: 1.3rem; }
}
/* Sobe acima da barra de abas da Recepção (2026-08-21, achado real: os
   dois são position:fixed no canto inferior direito e passaram a colidir
   depois que a barra de abas foi adicionada - o botão flutuante ficava em
   cima da aba "Mais"). mep-caixa-grupo só existe em index.php, mesma
   página da .reception-tabbar, então não precisa de seletor condicional -
   sempre que os dois existem juntos é nesta tela. Altura aproximada da
   barra (padding + ícone + rótulo + safe-area) + uma folga. */
@media (max-width: 719px) {
  .mep-caixa-grupo { bottom: calc(72px + env(safe-area-inset-bottom, 0px)); }
}

/* --- Alternador de visão da Agenda (Mês/Semana/Dia) --- */
/* Substitui os botões de view nativos do FullCalendar (2026-08-06) - a
   visão Semana deixou de ser uma view do FullCalendar (ver calendar.js),
   então o alternador precisou sair do headerToolbar embutido e virar um
   controle próprio, estilizado pra continuar parecendo o mesmo grupo de
   botões de antes. */
.agenda-view-toggle { display: flex; gap: 0.4rem; margin-bottom: 1rem; }
.agenda-view-toggle-btn {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 0.45rem 0.9rem; font-size: 0.85rem; font-weight: 600; color: var(--ink);
  cursor: pointer; font-family: var(--body);
}
.agenda-view-toggle-btn:hover { background: var(--bg-alt); }
.agenda-view-toggle-btn.is-ativo { background: var(--primary); border-color: var(--primary); color: #fff; }

/* --- Semana sob medida (2026-08-06) --- */
/* Pedido direto do cliente: a grade de hora (timeGridWeek) virava blocos
   minúsculos ilegíveis com o dia cheio - isso é uma LISTA por dia (como a
   planilha que ele já usa), colunas lado a lado com scroll horizontal com
   "snap" pra dar a sensação de arrastar/passar pro próximo dia no celular
   (nativo do navegador, sem biblioteca de gesto nenhuma). */
.agenda-semana { background: var(--card); border-radius: var(--radius); padding: 1.2rem; }
.agenda-semana-header { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; margin-bottom: 0.3rem; }
.agenda-semana-nav { display: flex; gap: 0.4rem; }
/* Mesmo tratamento do título da visão Mês (.fc-toolbar-title) - fonte de
   destaque + peso 600 + cor de heading, pra não parecer texto solto num
   tamanho aleatório do lado dos botões de navegação (achado real
   2026-08-14, "confuso de ver"). */
.agenda-semana-titulo { margin: 0; font-size: 1.2rem; font-family: var(--display); font-weight: 600; color: var(--heading); }
.agenda-semana-dica { margin: 0 0 1rem; font-size: 0.8rem; color: var(--ink-dim); }
/* Sombreado nas bordas quando tem mais coluna pra rolar (2026-08-13,
   achado real: com a Semana abrindo já rolada pro dia de hoje, o dia
   seguinte às vezes fica pela metade na borda direita - sem esse indício
   visual parece bug/coluna quebrada em vez de "arraste pra ver mais"
   (que a dica de texto acima já explica, mas ninguém lê aviso). JS
   (calendar.js) liga/desliga as classes is-scrollable-left/-right
   conforme a posição de rolagem real. */
.agenda-semana-dias-wrap { position: relative; }
.agenda-semana-dias-wrap::before, .agenda-semana-dias-wrap::after {
  content: ''; position: absolute; top: 0; bottom: 0.4rem; width: 28px;
  pointer-events: none; opacity: 0; transition: opacity 0.15s ease; z-index: 1;
}
.agenda-semana-dias-wrap::before { left: 0; background: linear-gradient(to right, var(--card), transparent); }
.agenda-semana-dias-wrap::after { right: 0; background: linear-gradient(to left, var(--card), transparent); }
.agenda-semana-dias-wrap.is-scrollable-left::before { opacity: 1; }
.agenda-semana-dias-wrap.is-scrollable-right::after { opacity: 1; }
.agenda-semana-dias { display: flex; gap: 0.7rem; overflow-x: auto; padding-bottom: 0.4rem; scroll-snap-type: x proximity; }
.agenda-semana-dia {
  flex: 1 0 200px; min-width: 200px; scroll-snap-align: start;
  background: var(--bg-alt); border-radius: var(--radius-sm); padding: 0.6rem;
  display: flex; flex-direction: column; gap: 0.4rem;
}
/* Mesmo achado de #calendar[hidden] (ver acima) - a classe já define
   "display: flex" e empata em especificidade com o [hidden] padrão do
   navegador; sem !important a coluna "escondida" (sáb/dom vazios)
   continuava renderizando, só saía da tela pelo scroll horizontal. */
.agenda-semana-dia[hidden] { display: none !important; }
.agenda-semana-dia.is-hoje { outline: 2px solid var(--primary); outline-offset: -2px; }
/* Fundo/cor FORÇADOS em todo estado (normal, hover, foco, ativo) -
   achado real do cliente, 2 rodadas seguidas ("quando quinta está
   selecionado continua invisível", depois "não consigo ler terça e o
   dia direito ali quando fica selecionado") - esse botão continuava
   ficando ilegível ao ser clicado/focado mesmo depois da 1ª correção
   (que só mexeu no anel de foco). Em vez de caçar qual pseudo-classe
   exata o navegador do cliente está aplicando (foco, :focus-visible
   não bate com clique de mouse na maioria dos navegadores, hover,
   active...), força background/color EXPLÍCITOS com !important em
   TODOS eles de uma vez - impossível qualquer estado deixar isso
   ilegível de novo. */
button.agenda-semana-dia-header,
button.agenda-semana-dia-header:hover,
button.agenda-semana-dia-header:focus,
button.agenda-semana-dia-header:active {
  display: flex; justify-content: space-between; align-items: baseline; width: 100%;
  background: none !important; border: none; border-bottom: 1px solid var(--border); padding: 0 0 0.4rem;
  cursor: pointer; font-family: var(--body); text-align: left;
}
.agenda-semana-dia-header:focus { outline: none; }
.agenda-semana-dia-header:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; border-radius: 2px; }
.agenda-semana-dia-nome {
  font-size: 0.72rem; color: var(--ink-dim) !important; text-transform: uppercase; letter-spacing: 0.03em;
}
.agenda-semana-dia-numero { font-size: 1.15rem; font-weight: 700; color: var(--ink) !important; margin-left: 0.4rem; }
.agenda-semana-dia-header:hover .agenda-semana-dia-numero,
.agenda-semana-dia-header:focus .agenda-semana-dia-numero {
  color: var(--primary) !important;
}
.agenda-semana-dia-lista { display: flex; flex-direction: column; gap: 0.35rem; min-height: 2rem; flex: 1; cursor: pointer; }
.agenda-semana-evento { border-radius: var(--radius-sm); padding: 0.4rem 0.5rem; cursor: pointer; }
/* Quebra o texto em vez de cortar com "..." - diferente das células
   minúsculas do FullCalendar, a coluna aqui tem espaço de sobra, e o
   pedido do cliente foi clareza, então nome completo do paciente > nome
   cortado. */
/* overflow:hidden da regra base (.clinica-event-content, acima) é pensado
   pra célula de uma linha só do Mês/Dia - aqui o texto pode quebrar em
   2+ linhas (white-space:normal), e sem essa sobrescrita a 2ª linha de
   qualquer nome longo ficava cortada (achado real 2026-08-13, nome
   "Eduardo Caldas Borges Borges" cortado na sexta-feira). */
/* flex-wrap (achado real 2026-08-14, "Mentoria" 20:00-22:00) - quebrar só
   o texto do título (regra abaixo) não bastava: badge + horário longo
   ("20:00–22:00", um intervalo, mais largo que só "20:00") + título juntos
   já estouravam a largura do card numa linha só, e sem flex-wrap os itens
   flex não descem - só vazavam pra fora do card em vez de quebrar. */
.agenda-semana-evento .clinica-event-content { align-items: flex-start; white-space: normal; overflow: visible; flex-wrap: wrap; }
.agenda-semana-evento .clinica-event-title { white-space: normal; overflow: visible; text-overflow: clip; }
.agenda-semana-dia-vazio { font-size: 0.78rem; color: var(--ink-dim); text-align: center; padding: 0.6rem 0; margin: 0; }
@media (max-width: 640px) {
  .agenda-semana-dia { flex: 0 0 88vw; min-width: 88vw; }
}

/* --- Biblioteca (Google Drive) --- */
.biblio-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1rem; }
.biblio-card { display: flex; flex-direction: column; }
.biblio-card[hidden] { display: none; }

/* --- Aniversariantes (Recepção) --- */
.aniversario-banner {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem; width: 100%;
  background: none; border: none; padding: 0; text-align: left;
  font-family: var(--body); font-size: 0.95rem; font-weight: 600; color: var(--ink);
}
.aniversario-banner[hidden] { display: none; }
.aniversario-banner:hover { background: none; color: var(--primary); }
.aniversario-seta { flex: 0 0 auto; display: flex; color: var(--ink-dim); transition: transform 0.15s ease; }
.aniversario-banner:hover .aniversario-seta { transform: translateX(2px); color: var(--primary); }
.aniversario-seta svg { width: 16px; height: 16px; }

.aniversario-nivel-titulo { font-size: 0.78rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; color: var(--ink-dim); margin-bottom: 0.6rem; }
.aniversario-nav { display: flex; justify-content: space-between; align-items: center; gap: 1rem; margin-top: 0.8rem; padding-top: 0.8rem; border-top: 1px solid var(--border); }
.aniversario-voltar, .aniversario-avancar {
  display: inline-flex; align-items: center; gap: 0.3rem; background: none; border: none; padding: 0;
  color: var(--ink-dim); font-family: var(--body); font-size: 0.85rem; font-weight: 600;
}
.aniversario-voltar:hover, .aniversario-avancar:hover { background: none; color: var(--primary); }
.aniversario-voltar svg { transform: rotate(180deg); }
.aniversario-voltar svg, .aniversario-avancar svg { width: 15px; height: 15px; }

/* Menu colapsável - achado real na auditoria visual de 2026-08-04: sem
   isso, os itens de nav simplesmente estouravam a tela em telas menores.
   Breakpoint reavaliado em 2026-08-08: com 9 links + conta, o menu numa
   linha só já não cabe mais nem em larguras "de desktop" (~768-1024px) -
   por isso o corte de 1300px, bem acima do mínimo real medido (~1283px),
   em vez de só cobrir celular. .clinica-nav-toggle/.clinica-nav-conta-mobile/
   .clinica-nav-sair-mobile só existem visualmente abaixo desse ponto -
   acima disso o layout original (tudo numa linha só) continua igual. */
.clinica-nav-toggle { display: none; }
.clinica-nav-conta-mobile, .clinica-nav-sair-mobile { display: none; }
.clinica-nav-toggle .icon-menu-fechado { display: none; }
.clinica-nav-toggle.is-open .icon-menu-aberto { display: none; }
.clinica-nav-toggle.is-open .icon-menu-fechado { display: flex; }

/* Botão "Voltar" (2026-08-11, achado real do cliente: "quando usado pelo
   celular, se quiser voltar para a pagina anterior, nao aparece opção") -
   escondido em telas largas de propósito, o navegador de desktop já tem
   botão de voltar nativo. É só abaixo deste mesmo corte que passa a fazer
   falta de verdade: o app roda instalado como PWA (manifest.json,
   display:standalone) - sem chrome de navegador nenhum, sem gesto/botão
   nativo de voltar - e várias páginas de detalhe (histórico do paciente,
   detalhe financeiro, relatórios) não tinham nenhum link de volta próprio,
   só contavam com o "voltar" do navegador que nem existe nesse modo. Ver
   assets/voltar-pagina.js.
*/
.clinica-nav-voltar { display: none; order: -1; }

@media (max-width: 1300px) {
  .clinica-nav { flex-wrap: nowrap; gap: 0.8rem; padding: 1rem; position: relative; }
  .clinica-nav-toggle { display: flex; }
  .clinica-nav-voltar { display: flex; }
  .clinica-nav-links {
    display: none; flex-direction: column; align-items: stretch; gap: 0.1rem;
    position: absolute; top: 100%; left: 1rem; right: auto; z-index: 40;
    width: 240px;
    background: var(--card); border-radius: 14px; box-shadow: var(--shadow);
    padding: 0.6rem 0.8rem;
    /* Achado real (2026-09-02, "o menu mostra esse espaço todo em branco
       ocupando a tela toda") - "right:0" esticava a gaveta de ponta a
       ponta da tela, mas o CONTEÚDO (ícone + texto curto) é estreito -
       sobrava um vão enorme em branco à direita da lista. Largura fixa
       (do tamanho do conteúdo, não da tela) + ancorada no canto onde o
       menu foi aberto, como um dropdown normal - cantos arredondados nos
       4 lados agora que não é mais borda-a-borda.
       Teto de altura mais baixo (65vh, sempre sobra página visível
       embaixo) + itens compactos + fundo escurecido atrás reforçam que é
       um painel flutuante, não uma troca de tela.
       flex-wrap:nowrap explícito (achado real: a regra BASE de
       .clinica-nav-links, lá em cima, tem flex-wrap:wrap - com
       flex-direction:column + max-height juntos, "wrap" vira MÚLTIPLAS
       COLUNAS em vez de rolar). */
    /* Mais alongado (2026-09-02, "pode deixar mais alongado esse menu, não
       precisa reduzir ele") - 85vh cabe os 14 itens sem precisar rolar em
       telas normais, o que também resolve de quebra o canto direito
       quadrado que a barra de rolagem tava cortando. max-height continua
       como rede de segurança só pra tela MUITO baixa/celular deitado. */
    max-height: 85vh; overflow-y: auto; flex-wrap: nowrap;
  }
  /* Barra de rolagem invisível até o mouse tocar (2026-09-02, pedido do
     cliente) - resolve de quebra o canto quadrado: uma barra de 6px
     transparente não quebra visualmente o arredondamento como a padrão
     (mais grossa) do navegador quebrava. */
  .clinica-nav-links { scrollbar-width: thin; scrollbar-color: transparent transparent; }
  .clinica-nav-links:hover { scrollbar-color: var(--border) transparent; }
  .clinica-nav-links::-webkit-scrollbar { width: 6px; }
  .clinica-nav-links::-webkit-scrollbar-track { background: transparent; }
  .clinica-nav-links::-webkit-scrollbar-thumb { background: transparent; border-radius: 999px; }
  .clinica-nav-links:hover::-webkit-scrollbar-thumb { background: var(--border); }
  .clinica-nav-links.is-open { display: flex; }
  .clinica-nav-links a { padding: 0.55rem 0.4rem; border-radius: 8px; }
  .clinica-nav-links a:hover, .clinica-nav-links a.is-active { background: var(--bg-alt); }
  /* Fundo escurecido atrás do menu aberto (2026-09-02) - :has() já é usado
     em outros lugares deste projeto (ex: body:has(.clinica-nav) da
     sidebar) - reforça visualmente "isso é um painel flutuante por cima
     da página", não a tela inteira virando o menu. */
  body:has(.clinica-nav-links.is-open)::after {
    content: ''; position: fixed; inset: 0; background: rgba(20, 15, 16, 0.4); z-index: 39;
  }
  .clinica-nav-conta-mobile, .clinica-nav-sair-mobile { display: flex; }
  .clinica-nav-conta-desktop, .clinica-nav-sair-desktop { display: none; }
  .clinica-page { padding: 1.2rem; }
  .clinica-sidebar-toggle-btn { display: none; }
}

/* --- Barra lateral (2026-09-02, pedido do cliente: "essas abas no topo
   acabaram ficando muitas, coloca a aba lateral, retrátil") - só acima de
   1300px (abaixo disso continua a barra horizontal + gaveta de sempre,
   ver bloco @media (max-width: 1300px) acima, inalterado). Largura
   controlada por [data-sidebar] em <html> (assets/nav.js + o script
   pre-paint em partials/head.php, mesmo padrão de data-theme/data-cor) -
   "recolhida" vira só ícones, body ganha o respiro certo dos dois lados
   via :has(). */
@media (min-width: 1301px) {
  /* Sem transition de propósito (2026-09-02, "não gostei da animação") -
     troca instantânea, sem nenhum efeito de deslizar. */
  body:has(.clinica-nav) { padding-left: 224px; }
  html[data-sidebar="recolhida"] body:has(.clinica-nav) { padding-left: 72px; }

  .clinica-nav {
    position: fixed; top: 0; left: 0; bottom: 0; width: 224px;
    flex-direction: column; align-items: stretch; gap: 0;
    padding: 1.1rem 0.9rem; overflow-y: auto; z-index: 30;
  }
  /* Barra de rolagem invisível até o mouse tocar (2026-09-16, mesmo padrão
     já usado no menu-gaveta mobile abaixo de 1300px) - achado real: com um
     item novo (Assinatura), a sidebar cheia passou a precisar rolar em
     telas mais baixas e a barra PADRÃO do navegador (grossa, sempre visível)
     destoava do resto da UI cuidadosamente estilizada. */
  .clinica-nav { scrollbar-width: thin; scrollbar-color: transparent transparent; }
  .clinica-nav:hover { scrollbar-color: var(--border) transparent; }
  .clinica-nav::-webkit-scrollbar { width: 6px; }
  .clinica-nav::-webkit-scrollbar-track { background: transparent; }
  .clinica-nav::-webkit-scrollbar-thumb { background: transparent; border-radius: 999px; }
  .clinica-nav:hover::-webkit-scrollbar-thumb { background: var(--border); }
  html[data-sidebar="recolhida"] .clinica-nav { width: 72px; padding-left: 0.5rem; padding-right: 0.5rem; }

  /* "MEP" centralizado no topo da sidebar (2026-09-02, pedido do cliente).
     O "?" (Sobre o MEP) sai do fluxo do centro (position:absolute) pra não
     empurrar o nome pra fora do centro de verdade. */
  .clinica-nav-brand-wrap { position: relative; display: flex; justify-content: center; width: 100%; margin-bottom: 1.3rem; }
  .clinica-nav-sobre-btn { position: absolute; right: 0; top: 50%; transform: translateY(-50%); }
  html[data-sidebar="recolhida"] .clinica-nav-brand, html[data-sidebar="recolhida"] .clinica-nav-sobre-btn { display: none; }

  /* Recolher/expandir - 4ª tentativa (2026-09-02, "prefiro o botão aonde
     estava, sem animação, mas funcionando") - de volta a flutuante, FORA
     de <nav> (comentário completo em partials/nav.php). Sem
     transform/transition nenhuma dessa vez - só `left` puro, valor fixo
     em px calculado pra já nascer centralizado (sem depender de
     translate(-50%) recalculando em cima de um clique). */
  .clinica-sidebar-toggle-btn {
    position: fixed; top: calc(50vh - 12px); left: 212px;
    width: 24px; height: 24px; padding: 0; border-radius: 50%;
    border: 1px solid var(--border); background: var(--card); color: var(--ink-dim);
    display: flex; align-items: center; justify-content: center;
    box-shadow: 0 2px 6px rgba(0,0,0,0.18); z-index: 999;
  }
  html[data-sidebar="recolhida"] .clinica-sidebar-toggle-btn { left: 60px; }
  .clinica-sidebar-toggle-btn:hover { background: var(--bg-alt); }
  /* Ícone 'seta' aponta pra DIREITA por padrão (0°) - gira 180° só quando
     expandida (aponta pra ESQUERDA, "clique pra fechar"); recolhida fica
     no ângulo original ("clique pra abrir"). Sem transition - troca de
     ângulo instantânea. */
  .clinica-sidebar-toggle-icon { width: 11px; height: 11px; transform: rotate(180deg); }
  html[data-sidebar="recolhida"] .clinica-sidebar-toggle-icon { transform: rotate(0deg); }

  .clinica-nav-links { flex-direction: column; align-items: stretch; gap: 0.15rem; flex: 1; width: 100%; row-gap: 0; }
  .clinica-nav-links a {
    display: flex; align-items: center; gap: 0.7rem;
    padding: 0.55rem 0.7rem; border-radius: 10px; border-bottom: none !important;
  }
  .clinica-nav-links a:hover, .clinica-nav-links a.is-active { background: var(--bg-alt); color: var(--heading); }
  .clinica-nav-emoji { position: relative; font-size: 1.05rem; line-height: 1; flex: 0 0 auto; width: 1.2rem; text-align: center; }
  .clinica-nav-label { white-space: nowrap; }
  html[data-sidebar="recolhida"] .clinica-nav-label { display: none; }
  html[data-sidebar="recolhida"] .clinica-nav-links a { justify-content: center; padding: 0.6rem; }
  /* Badge miniatura (2026-09-02) - com o menu recolhido, o número de
     Conversas/Pendências/Solicitações não pode sumir junto com o texto -
     é exatamente o tipo de coisa que precisa continuar visível mesmo no
     modo compacto (a versão base, sempre escondida, está lá em cima perto
     de .nav-badge). Só reaparece quando recolhido. */
  html[data-sidebar="recolhida"] .clinica-nav-badge-recolhida {
    display: inline-flex; position: absolute; top: -4px; right: -8px;
    min-width: 0.9rem; height: 0.9rem; padding: 0 0.2rem; font-size: 0.58rem;
  }

  /* "conta"/"sair" mobile nunca deveriam aparecer aqui em cima de
     1300px - achado real (2026-09-02, "duplicação da bolinha com meu
     nome e do sair"): .clinica-nav-links a (regra logo acima) tem
     especificidade maior que a regra base "display:none" desses dois
     links (só uma classe), então ela vencia e reexibia os dois -
     duplicado com a versão desktop de .clinica-nav-user mais abaixo.
     Sempre escondidos aqui, não só quando recolhida. */
  .clinica-nav-conta-mobile, .clinica-nav-sair-mobile { display: none !important; }

  .clinica-nav-user {
    flex-direction: column; align-items: stretch; gap: 0.35rem;
    width: 100%; margin-top: auto; padding-top: 0.9rem; border-top: 1px solid var(--border);
  }
  .clinica-nav-conta-desktop, .clinica-nav-sair-desktop { display: flex; align-items: center; gap: 0.6rem; padding: 0.4rem 0.5rem; border-radius: 8px; }
  .clinica-nav-conta-desktop:hover, .clinica-nav-sair-desktop:hover { background: var(--bg-alt); }
  html[data-sidebar="recolhida"] .clinica-nav-conta-desktop, html[data-sidebar="recolhida"] .clinica-nav-sair-desktop { justify-content: center; }

  /* Tema + cor lado a lado quando expandida, empilhados quando recolhida
     (2026-09-02, pedido do cliente). */
  .clinica-nav-toggles-row { display: flex; flex-direction: row; gap: 0.5rem; align-self: center; }
  html[data-sidebar="recolhida"] .clinica-nav-toggles-row { flex-direction: column; }

  /* .clinica-page-full (conversas.php etc) descontava a altura da antiga
     barra HORIZONTAL do topo - a sidebar não ocupa altura nenhuma no topo,
     só largura à esquerda, então a página pode usar a viewport inteira. */
  .clinica-page-full { height: 100vh; }

  /* "Voltar ao topo" era posicionado a 20px da borda ESQUERDA da tela -
     com a sidebar ali agora, ficaria por cima dela. Desloca pra depois da
     sidebar, acompanhando recolhida/expandida. */
  .clinica-voltar-topo { left: 244px; transition: opacity 0.2s ease, transform 0.2s ease, background 0.15s ease, left 0.2s ease; }
  html[data-sidebar="recolhida"] .clinica-voltar-topo { left: 92px; }
}

/* --- Recepção: dashboard 2 colunas (desktop) + abas fixas (mobile) ---
   (2026-08-21, pedido do cliente: a Recepção virou um scroll longo mesmo
   com tudo bem feito - o problema era arquitetura de layout, não estética
   dos cards em si. Desktop ganha largura real (grid 2 colunas em vez de
   empilhar tudo numa coluna de 1100px numa tela de 1920px); mobile ganha
   navegação por abas (estilo app) em vez de rolar por ~14 seções
   seguidas. index.php marca cada card com data-reception-tab="hoje|fila|
   financeiro|mais" - no desktop isso não faz nada (tudo visível, só
   posicionado em coluna principal/lateral via .reception-col-main/-side);
   no mobile, main[data-active-tab] + CSS decide o que mostra, sem tocar
   em display de cada card individualmente via JS (só troca 1 atributo). */
.reception-grid { display: block; }
@media (min-width: 960px) {
  .reception-grid { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 1.5rem; align-items: start; }
  .reception-col-main, .reception-col-side { min-width: 0; }
}

.reception-tabbar { display: none; }
@media (max-width: 719px) {
  main.clinica-page[data-active-tab] { padding-bottom: 5rem; }
  [data-reception-tab] { display: none; }
  main[data-active-tab="hoje"] [data-reception-tab="hoje"],
  main[data-active-tab="fila"] [data-reception-tab="fila"],
  main[data-active-tab="financeiro"] [data-reception-tab="financeiro"],
  main[data-active-tab="mais"] [data-reception-tab="mais"] { display: block; }

  .reception-tabbar {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
    background: var(--card); border-top: 1px solid var(--border);
    padding: 0.5rem 0.4rem calc(0.5rem + env(safe-area-inset-bottom, 0px));
    box-shadow: 0 -2px 10px rgba(0,0,0,0.06);
  }
  .reception-tab-btn {
    flex: 1; display: flex; flex-direction: column; align-items: center; gap: 0.15rem;
    background: none; border: none; padding: 0.4rem 0.2rem; color: var(--ink-dim);
    font-family: var(--body); font-size: 0.7rem; cursor: pointer; position: relative;
  }
  /* :hover explícito aqui (2026-08-27, bug real: "aba fica feia/difícil de
     ler ao tocar") - no celular, tocar um botão ativa um :hover "grudado"
     até tocar em outro lugar. A regra genérica "button:hover { background:
     var(--primary-dark) }" (style.css, base de todo botão do sistema) tem
     MAIS especificidade que ".reception-tab-btn { background: none }"
     sozinho (pseudo-classe conta junto de classe no cálculo de
     especificidade, então "button:hover" vence ".reception-tab-btn" na
     prática) - pintava o botão tocado de verde escuro, com o texto
     ".is-active" (também verde) ilegível em cima. Precisa ficar
     transparente tanto parado quanto tocado. */
  .reception-tab-btn:hover,
  .reception-tab-btn:focus,
  .reception-tab-btn:focus-visible,
  .reception-tab-btn:active { background: none; }
  .reception-tab-btn svg { width: 20px; height: 20px; }
  /* Indicador da aba ativa (2026-08-27, cliente: "passa até despercebido
     que eu troquei do hoje para fila", depois "falta personalidade" numa
     1ª tentativa mais discreta) - pill SÓLIDA (não sutil) em --primary com
     ícone/texto em branco, "levantando" um pouco (translateY + sombra),
     pra bater o olho de longe igual um app de verdade, sem repetir o erro
     do fundo escuro com texto escuro em cima (aqui o texto é branco). */
  .reception-tab-btn.is-active {
    color: #fff; font-weight: 700;
  }
  .reception-tab-btn.is-active::before {
    content: ""; position: absolute; inset: -0.15rem 0.3rem auto 0.3rem; top: -0.15rem;
    height: 2.3rem; border-radius: 999px; background: var(--primary);
    box-shadow: 0 3px 8px color-mix(in srgb, var(--primary) 45%, transparent);
    animation: reception-tab-pop 0.18s ease-out;
  }
  .reception-tab-btn.is-active svg,
  .reception-tab-btn.is-active span:not(.reception-tab-badge) { position: relative; z-index: 1; }
  /* A badge (bolinha vermelha de contador) é um <span> irmão do rótulo -
     sem o :not() acima, a regra genérica de span também pegava ela e
     sobrescrevia seu "position: absolute" original pra "relative",
     fazendo o número "cair" pra fora do canto e ficar solto embaixo do
     botão quando a aba virava ativa (2026-08-27, cliente: "formatação do
     fila ficou estranho"). Aqui garante que ela sempre fique por cima da
     pill, no canto certo. */
  .reception-tab-btn.is-active .reception-tab-badge { z-index: 2; }
  @keyframes reception-tab-pop {
    from { transform: scale(0.85); opacity: 0.6; }
    to { transform: scale(1); opacity: 1; }
  }
  .reception-tab-badge {
    position: absolute; top: -0.1rem; right: 22%; min-width: 1.1rem; height: 1.1rem;
    border-radius: 999px; background: var(--danger); color: #fff; font-size: 0.62rem;
    font-weight: 700; display: flex; align-items: center; justify-content: center; padding: 0 0.25rem;
  }
}

/* Ícone de ajuda "?" (ver clinica_help_tip() em lib/helpers.php) - pedido
   explícito do cliente 2026-08-04 pra explicar conceitos novos (estimativa
   vs. contrato, pacotes, sessões restantes) sem precisar perguntar. CSS-only,
   funciona em hover E foco (acessível por teclado). */
.help-tip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.05rem; height: 1.05rem; border-radius: 50%;
  background: var(--border); color: var(--ink-dim);
  font-size: 0.68rem; font-weight: 700; line-height: 1;
  cursor: help; position: relative; flex-shrink: 0; vertical-align: middle;
}
.help-tip:hover, .help-tip:focus { background: var(--accent); color: #fff; outline: none; }
.help-tip::after {
  content: attr(data-tip);
  position: absolute; bottom: calc(100% + 0.5rem); left: 50%; transform: translateX(-50%);
  background: var(--ink); color: var(--card);
  padding: 0.5rem 0.7rem; border-radius: var(--radius-sm);
  font-size: 0.78rem; font-weight: 400; line-height: 1.4; white-space: normal;
  width: max-content; max-width: 230px; text-align: left; box-shadow: var(--shadow);
  opacity: 0; pointer-events: none; transition: opacity 0.15s ease; z-index: 50;
}
.help-tip:hover::after, .help-tip:focus::after { opacity: 1; }
/* Variante pequena (2026-08-31, cliente: "quero que você faça esse '?'
   fica menor") - só o de proveniência ao lado do nome nas listas de sessão
   (clinica_sessao_registro_tip_html()), não os outros "?" de ajuda
   espalhados pelo sistema, que continuam do tamanho normal. */
.help-tip-sm { width: 0.8rem; height: 0.8rem; font-size: 0.55rem; }

/* Variante "abre pra baixo" (2026-09-08, achado real do cliente: "a
   ajuda que aparece explicando sobre o guia do dia... está aparecendo
   feio") - o balão padrão abre pra CIMA (bottom: 100%), que só funciona
   quando sobra espaço acima do "?". O da Guia do dia fica perto do topo
   de um painel com scroll (.dia-modal-guia dentro de .clinica-modal com
   overflow-y:auto) - abrindo pra cima ele saía cortado/flutuando fora do
   modal. Passa clinica_help_tip(..., abrirPraBaixo: true) nesses casos. */
.help-tip-baixo::after { bottom: auto; top: calc(100% + 0.5rem); }

/* Variante "abre pra direita" (2026-09-10, achado real do cliente: o "?"
   da conquista de pacotes concluídos, perto do início da linha em tela
   de celular, tinha o balão centralizado nele mesmo - metade do balão
   (até 230px de largura) estourava a borda esquerda da tela, cortando o
   texto). Mesmo raciocínio do help-tip-baixo, só no eixo horizontal -
   ancora o balão na borda ESQUERDA do próprio ícone, crescendo pra
   direita, em vez de centralizado nele. Passa
   clinica_help_tip(..., abrirPraDireita: true) num "?" perto da borda
   esquerda da tela. */
.help-tip-direita::after { left: 0; transform: none; }

/* Layout em 2 colunas do perfil (2026-09-08, pedido do cliente): coluna
   principal (Anotações no topo + o resto) + coluna lateral com 3 blocos
   compactos clicáveis (Notas fiscais, Satisfação, Costuma vir) - "levam
   pra outra página" (paciente_historico.php, onde os cards cheios
   moram agora). Sticky na lateral - útil numa página comprida, os 3
   blocos ficam à vista rolando o resto. Empilha numa coluna só abaixo de
   900px (mesmo breakpoint espírito de .clinica-page-wide) - 3 caixinhas
   apertadas numa lateral estreita de celular seriam ilegíveis. */
.perfil-layout { display: grid; grid-template-columns: 1fr 260px; gap: 1.5rem; align-items: start; }
.perfil-layout-principal { min-width: 0; }
.perfil-layout-lateral { display: flex; flex-direction: column; gap: 1rem; position: sticky; top: 1rem; }
@media (max-width: 900px) {
  .perfil-layout { grid-template-columns: 1fr; }
  .perfil-layout-lateral { position: static; flex-direction: row; flex-wrap: wrap; }
  .perfil-layout-lateral .perfil-lateral-card { flex: 1 1 200px; }
}
.perfil-lateral-card {
  display: block; text-decoration: none; color: inherit;
  padding: 0.9rem 1rem; border-radius: var(--radius-sm);
  background: var(--card); border: 1px solid var(--border);
  transition: border-color 0.15s ease, transform 0.15s ease;
}
a.perfil-lateral-card:hover { border-color: var(--primary); transform: translateY(-1px); }
.perfil-lateral-card-topo { font-size: 0.8rem; font-weight: 600; color: var(--ink-dim); display: flex; align-items: center; gap: 0.3rem; }
.perfil-lateral-card-valor { font-family: var(--display); font-size: 1.15rem; font-weight: 600; color: var(--heading); margin-top: 0.3rem; }

/* Bloco "Dados do paciente" (paciente_perfil.php) e "Sessões combinadas"
   (paciente_form.php) - pedido explícito do cliente 2026-08-04. */
.perfil-stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 1rem; }
.perfil-stat { text-align: center; padding: 0.9rem 0.6rem; border-radius: var(--radius-sm); background: var(--bg-alt); }
.perfil-stat .valor { font-family: var(--display); font-size: 1.5rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.perfil-stat .label { font-size: 0.78rem; color: var(--ink-dim); margin-top: 0.3rem; display: flex; align-items: center; justify-content: center; gap: 0.3rem; }
.perfil-restantes-bar { height: 8px; border-radius: 4px; background: var(--border); overflow: hidden; margin-top: 0.5rem; }
.perfil-restantes-fill { height: 100%; background: var(--primary); border-radius: 4px; transition: width 0.3s ease; }

/* Caixinha de Ausência (2026-09-08, renomeada de "férias", movida do
   cadastro pro perfil - pedido do cliente: "caixinha pra clicar...
   informação atualizada de forma animada... podendo ser editado").
   Reaproveita o grid .perfil-stat-grid acima (mesma altura/fundo das
   outras estatísticas quando só mostrando o estado atual); ganha
   grid-column:1/-1 (linha inteira) só quando o formulário de edição
   está aberto - textarea+data precisam de mais espaço que um tile
   normal, texto centralizado não funciona bem num formulário. */
.ausencia-widget:has(.ausencia-widget-form:not([hidden])) { grid-column: 1 / -1; text-align: left; }
.ausencia-widget-vista { cursor: pointer; border-radius: var(--radius-sm); }
.ausencia-widget-vista:hover, .ausencia-widget-vista:focus-visible { background: color-mix(in srgb, var(--ink) 5%, transparent); }
/* Estado "sem ausência" (2026-09-08, pedido do cliente: "cinza ficou
   feio... clique aqui para registrar uma ausência") - visual PRÓPRIO de
   convite (borda tracejada na cor de destaque, sem o fundo cinza padrão
   de .perfil-stat que os outros tiles compartilham) - esse aqui precisa
   parecer uma ação disponível, não um dado já preenchido. Some sozinho
   assim que uma ausência é marcada (classe tirada via JS). */
.ausencia-widget-vazia { background: transparent; border: 1.5px dashed color-mix(in srgb, var(--accent) 55%, var(--border)); }
.ausencia-widget-vazia:hover, .ausencia-widget-vazia:focus-within { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 6%, transparent); }
.ausencia-widget-icone { font-size: 1.6rem; line-height: 1; margin-bottom: 0.3rem; }
.ausencia-widget-form { display: flex; flex-direction: column; text-align: left; max-width: 360px; }
/* [hidden] perde pra um display: próprio do elemento sem este override
   explícito (mesmo gotcha de sempre neste app) - sem isso o formulário
   de edição ficava visível JUNTO com a vista o tempo todo, achado real
   do cliente (2026-09-08): "só depois de ser clicada deveria aparecer". */
.ausencia-widget-form[hidden] { display: none !important; }
.ausencia-widget-form input, .ausencia-widget-form textarea {
  width: 100%; font-family: var(--body); font-size: 0.9rem;
  padding: 0.5rem 0.6rem; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--card); color: var(--ink);
}

/* Pill "sem sessão marcada" (Recepção + Agenda, 2026-09-17) - ver
   partials/alerta-agenda-badge.php e lib/alerta-agenda.php. Ícone
   pulsando de leve (mesmo espírito de @keyframes pacienteInativoPulso) -
   só aparece quando tem pelo menos 1 paciente na lista, então quando
   visível TEM que chamar atenção mesmo, é dinheiro/vínculo real em risco. */
.alerta-agenda-pill {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.4rem 0.8rem; border-radius: 999px;
  background: color-mix(in srgb, var(--warn) 14%, var(--card)); border: 1px solid var(--warn);
  color: var(--ink); font-weight: 600; font-size: 0.85rem;
}
.alerta-agenda-pill:hover, .alerta-agenda-pill:focus-visible { text-decoration: none; background: color-mix(in srgb, var(--warn) 24%, var(--card)); }
.alerta-agenda-pill-standalone { margin-bottom: 1.5rem; }
.alerta-agenda-pill-icone { display: inline-block; animation: alertaAgendaPulso 1.6s ease-in-out infinite; }
.alerta-agenda-pill-badge {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--danger); color: #fff; font-size: 0.75rem; font-weight: 800;
  border-radius: 999px; min-width: 1.2rem; height: 1.2rem; padding: 0 0.35rem;
}
@keyframes alertaAgendaPulso {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.2); }
}
@media (prefers-reduced-motion: reduce) {
  .alerta-agenda-pill-icone { animation: none; }
}
@media (max-width: 520px) {
  .alerta-agenda-pill-texto { display: none; }
}
.ausencia-widget-form textarea { resize: vertical; }
.ausencia-editar-dica {
  display: inline-block; margin-top: 0.4rem; font-size: 0.72rem; color: var(--ink-dim);
  opacity: 0; transition: opacity 0.15s ease;
}
.ausencia-widget-vista:hover .ausencia-editar-dica, .ausencia-widget-vista:focus-visible .ausencia-editar-dica { opacity: 1; }

/* Anotações (2026-09-08, pedido do cliente: "área fácil de editar...
   ótimo design, animação, bonita") - card inteiro clicável (não só um
   botão pequeno) pra ficar óbvio que dá pra editar, com uma dica sutil
   no canto que só aparece no hover/foco (mesmo espírito de affordance
   de .pendencia-texto, só que pra um bloco de texto livre em vez de uma
   linha). */
.anotacoes-vista { position: relative; cursor: pointer; border-radius: var(--radius-sm); padding: 0.4rem; margin: -0.4rem; transition: background 0.15s ease; }
.anotacoes-vista:hover, .anotacoes-vista:focus-visible { background: var(--bg-alt); }
.anotacoes-vista p { margin: 0; }
.anotacoes-vazia { color: var(--ink-dim); font-style: italic; }
/* Autoria (2026-09-08, pedido do cliente: "quem foi que digitou e que
   horas/dia, sem virar poluição visual") - fonte bem pequena, cor apagada,
   sem ícone/destaque nenhum - é rodapé de referência, não informação
   principal do card. Sobrescreve o margin:0 de .anotacoes-vista p acima
   só nesta linha, precisa de uma folguinha em cima do texto real. */
.anotacoes-autoria { margin-top: 0.5rem !important; font-size: 0.72rem; color: var(--ink-dim); opacity: 0.75; }
.anotacoes-editar-dica {
  display: inline-block; margin-top: 0.5rem; font-size: 0.78rem; color: var(--ink-dim);
  opacity: 0; transition: opacity 0.15s ease;
}
.anotacoes-vista:hover .anotacoes-editar-dica, .anotacoes-vista:focus-visible .anotacoes-editar-dica { opacity: 1; }
.anotacoes-form textarea {
  width: 100%; font-family: var(--body); font-size: 0.92rem; line-height: 1.5;
  padding: 0.6rem 0.7rem; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--card); color: var(--ink); resize: vertical;
}

/* Flash de "salvo" (2026-09-08, pedido do cliente: "informação
   atualizada de forma animada") - reaproveitado pelas duas caixinhas
   acima (Ausência e Anotações) via assets/paciente-widgets.js's
   piscarSalvo(). Um brilho rápido na cor de sucesso, não fica em loop
   como os selos da Agenda (isso é feedback de UMA ação que já
   terminou, não um alerta contínuo). */
.clinica-flash-salvo { animation: flashSalvo 0.9s ease-out; border-radius: var(--radius-sm); }
@keyframes flashSalvo {
  0% { box-shadow: inset 0 0 0 30px color-mix(in srgb, var(--success) 22%, transparent), 0 0 0 0 color-mix(in srgb, var(--success) 45%, transparent); }
  100% { box-shadow: inset 0 0 0 30px color-mix(in srgb, var(--success) 0%, transparent), 0 0 0 8px color-mix(in srgb, var(--success) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .clinica-flash-salvo { animation: none; }
}

/* Toast de confirmação (ver assets/toast.js) - pedido da auditoria visual
   de 2026-08-04. Canto inferior, empilha por cima de tudo, some sozinho. */
.clinica-toast {
  position: fixed; left: 50%; bottom: 1.5rem; transform: translateX(-50%) translateY(12px);
  background: var(--heading); color: var(--card); font-weight: 600; font-size: 0.9rem;
  padding: 0.75rem 1.3rem; border-radius: 999px; box-shadow: var(--shadow);
  opacity: 0; transition: opacity 0.22s ease, transform 0.22s ease; z-index: 200; pointer-events: none;
}
.clinica-toast.is-open { opacity: 1; transform: translateX(-50%) translateY(0); }
@media (prefers-reduced-motion: reduce) { .clinica-toast { transition: opacity 0.15s ease; } }

/* --- Solicitações (nota fiscal + relatórios) --- */
.nf-status-btn {
  border: none; border-radius: 999px; padding: 0.35rem 0.8rem; font-size: 0.82rem; font-weight: 600; cursor: pointer;
}
.nf-status-solicitada { background: var(--warn); color: #fff; }
.nf-status-emitida { background: var(--success); color: #fff; }
.solicitacoes-relatorios-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 1rem;
}
.solicitacoes-relatorio-card {
  display: flex; flex-direction: column; gap: 0.3rem;
  padding: 1rem; border: 1px solid var(--border); border-radius: var(--radius-sm);
  color: var(--ink); text-decoration: none; transition: border-color 0.15s ease, background 0.15s ease;
}
.solicitacoes-relatorio-card:hover { border-color: var(--primary); background: var(--bg-alt); }
.solicitacoes-relatorio-card strong { color: var(--heading); }
.solicitacoes-relatorio-card span { font-size: 0.82rem; color: var(--ink-dim); }

/* Despesas - "contas a pagar" (2026-08-31) - acabamento visual de
   verdade, pra chegar perto da prévia aprovada em vez de só funcionar.
   Cabeçalho com wrap (2026-08-31, bug real - os 3 botões vazavam da tela
   no celular, sem quebrar linha) - resolvido com flex-wrap aqui em vez de
   inline style, pra não repetir em cada botão. */
.despesas-header { display: flex; justify-content: space-between; align-items: center; gap: 0.8rem; flex-wrap: wrap; margin-bottom: 1.2rem; }
.despesas-header-acoes { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.despesas-header-acoes .btn, .despesas-header-acoes .btn-secondary { font-size: 0.85rem; padding: 0.5rem 0.8rem; white-space: nowrap; }

.despesas-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 0.8rem; margin-bottom: 1.5rem; }
.despesa-kpi { background: var(--card); border-radius: var(--radius); padding: 1rem 1.1rem; border: 1px solid var(--border); }
.despesa-kpi-topo { display: flex; align-items: center; gap: 0.4rem; margin-bottom: 0.5rem; }
.despesa-kpi-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }
.despesa-kpi-label { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-dim); }
.despesa-kpi-valor { font-family: var(--display); font-size: 1.65rem; font-weight: 700; color: var(--heading); line-height: 1.1; }
.despesa-kpi-sub { font-size: 0.78rem; color: var(--ink-dim); margin-top: 0.2rem; }

/* Timeline com linha conectando os pontos (2026-08-31) - mesma leitura
   visual da prévia: cada conta é um ponto colorido numa linha vertical,
   não só uma lista de cards soltos. */
.despesas-timeline { position: relative; display: flex; flex-direction: column; gap: 0; padding-left: 1.6rem; }
.despesas-timeline::before {
  content: ""; position: absolute; left: 5px; top: 10px; bottom: 10px; width: 2px; background: var(--border);
}
.despesa-timeline-item { position: relative; padding: 0.7rem 0; border-bottom: 1px solid var(--border); }
.despesa-timeline-item:last-child { border-bottom: none; }
.despesa-timeline-dot {
  position: absolute; left: -1.6rem; top: 1.15rem; width: 11px; height: 11px; border-radius: 50%;
  border: 2px solid var(--card); box-shadow: 0 0 0 2px currentColor; background: currentColor;
}
.despesa-timeline-linha1 { display: flex; align-items: baseline; justify-content: space-between; gap: 0.8rem; flex-wrap: wrap; }
.despesa-timeline-desc { font-weight: 600; color: var(--heading); }
.despesa-timeline-valor { font-family: var(--display); font-weight: 700; white-space: nowrap; }
.despesa-timeline-linha2 { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.3rem; flex-wrap: wrap; font-size: 0.78rem; color: var(--ink-dim); }
.despesa-status-chip {
  display: inline-flex; align-items: center; border: none; border-radius: 999px; padding: 0.2rem 0.65rem;
  font-size: 0.7rem; font-weight: 700; letter-spacing: 0.02em; cursor: pointer; white-space: nowrap;
}
.despesa-status-chip.status-atrasado { background: color-mix(in srgb, var(--danger) 18%, transparent); color: var(--danger); }
.despesa-status-chip.status-pendente { background: color-mix(in srgb, var(--accent) 20%, transparent); color: var(--accent); }
.despesa-status-chip.status-pago { background: color-mix(in srgb, var(--success) 20%, transparent); color: var(--success); }
.despesa-timeline-editar { color: var(--ink-dim); flex: 0 0 auto; }

.despesas-recorrentes-lista { display: flex; flex-direction: column; }
.despesa-recorrente-row { display: flex; align-items: center; gap: 0.8rem; padding: 0.65rem 0; border-bottom: 1px solid var(--border); }
.despesa-recorrente-row:last-child { border-bottom: none; }
.despesa-recorrente-row.is-inativa { opacity: 0.5; }
.despesa-recorrente-info { flex: 1; min-width: 140px; }
.despesa-recorrente-desc { font-weight: 600; color: var(--heading); }
.despesa-recorrente-meta { font-size: 0.78rem; color: var(--ink-dim); margin-top: 0.15rem; }
.despesa-recorrente-valor { font-family: var(--display); font-weight: 700; white-space: nowrap; }

/* Por categoria - barra de proporção (2026-08-31) - relativa ao maior
   valor do mês (não um orçamento fixo por categoria - essa é uma feature
   futura em aberto, não implementada ainda), só pra dar leitura visual
   rápida de "essa categoria pesa mais que aquela" sem precisar comparar
   números de cabeça. */
.despesa-categoria-item { padding: 0.6rem 0; }
.despesa-categoria-linha { display: flex; justify-content: space-between; align-items: baseline; gap: 0.6rem; margin-bottom: 0.35rem; }
.despesa-categoria-nome { font-weight: 600; color: var(--heading); font-size: 0.9rem; }
.despesa-categoria-valor { font-size: 0.85rem; color: var(--ink-dim); font-variant-numeric: tabular-nums; }
.despesa-categoria-bar-track { height: 6px; border-radius: 999px; background: var(--bg-alt); overflow: hidden; }
.despesa-categoria-bar-fill { height: 100%; border-radius: 999px; background: var(--primary); transition: width 0.6s cubic-bezier(0.22, 1, 0.36, 1); }

/* "Tudo clicável" (2026-08-31, pedido do cliente depois de ver a tela
   funcionando) - KPI/timeline/recorrentes/categoria/lançamentos inteiros
   respondem a toque agora, não só a pilulazinha/lápis/switch. */
.despesa-kpi-clicavel { display: block; text-decoration: none; color: inherit; transition: transform 0.12s ease, box-shadow 0.12s ease; cursor: pointer; }
.despesa-kpi-clicavel:hover, .despesa-kpi-clicavel:active { transform: translateY(-1px); box-shadow: var(--shadow, 0 4px 14px rgba(0,0,0,0.08)); }
.despesa-item-clicavel { cursor: pointer; }
.despesa-item-clicavel:hover { background: var(--bg-alt); }
tr.despesa-item-clicavel:hover { background: var(--bg-alt); }
.despesa-categoria-clicavel { cursor: pointer; border-radius: var(--radius-sm); }
.despesa-categoria-clicavel:hover { background: var(--bg-alt); }
