/* ==========================================================================
   EasyControl Visitor Management System - Stylesheet
   Design: Modern Dark/Glassmorphism Theme with Print Optimization
   ========================================================================== */

:root {
  --bg-primary: #0f172a;
  --bg-secondary: #1e293b;
  --bg-card: rgba(30, 41, 59, 0.7);
  --bg-card-hover: rgba(51, 65, 85, 0.8);
  --accent-primary: #3b82f6;
  --accent-hover: #2563eb;
  --accent-success: #10b981;
  --accent-warning: #f59e0b;
  --accent-danger: #ef4444;
  --text-main: #f8fafc;
  --text-muted: #94a3b8;
  --text-dim: #64748b;
  --border-color: rgba(255, 255, 255, 0.1);
  --shadow-main: 0 10px 25px -5px rgba(0, 0, 0, 0.3), 0 8px 10px -6px rgba(0, 0, 0, 0.3);
  --radius-lg: 16px;
  --radius-md: 10px;
  --radius-sm: 6px;
  --font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

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

body {
  font-family: var(--font-family);
  background-color: #e2e8f0;
  color: var(--text-main);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  line-height: 1.5;
  background-image: none;
}

/* Fundo padrão para todas as páginas: cinza claro + marca d'água da foto dos prédios */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background-image: url("img/predios.jpg");
  background-size: cover;
  background-position: center bottom;
  background-repeat: no-repeat;
  filter: grayscale(1);
  opacity: 0.12;
  pointer-events: none;
}

/* Header & Navigation */
header {
  background: rgba(15, 23, 42, 0.88);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border-color);
  /* 1rem 2rem até 25/08/2026, quando os ladrilhos de módulo saíram do cabeçalho
     e foram para a gaveta lateral. Eles é que davam a altura; sobrou espaço
     morto. De 105 px para ~63 px, e os ~42 px vão para a tela de trabalho —
     o painel da portaria rolava 131 px além da janela em 1366x768. */
  padding: 0.6rem 1.25rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  position: sticky;
  top: 0;
  z-index: 100;
}

.logo-container {
  display: flex;
  align-items: center;
  gap: 12px;
}

.logo-badge {
  background: linear-gradient(135deg, #3b82f6, #1d4ed8);
  color: white;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 1.2rem;
  box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
}

/* Marca Neoporter (N) usada no lugar do badge nos cabeçalhos. */
.logo-mark {
  height: 42px;
  width: auto;
  display: block;
  flex-shrink: 0;
}

.logo-title {
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: -0.02em;
}

.building-subtitle {
  font-size: 0.75rem;
  color: var(--accent-primary);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* ==========================================================================
   Menu de módulos (header) — Portaria, Diretório, Dashboard e Painel Admin.
   ==========================================================================
   O TOTEM não recebe este menu de propósito: ele roda em quiosque no tablet, de
   cara para o visitante, e um link para o painel administrativo ali seria porta
   aberta na recepção. Por isso o totem.html continua sem `.module-nav`.

   O módulo em que a pessoa já está vira um <span>, não um link: destaca onde ela
   está e evita o clique que recarrega a própria página (na portaria isso custaria
   uma recarga inteira do painel ao vivo). */
/* ==========================================================================
   MENU HAMBÚRGUER + GAVETA LATERAL (25/08/2026)

   Substituiu o `.module-nav` horizontal, que era ladrilho de ícone+rótulo no
   cabeçalho. Dois motivos: a barra levava 73 px de altura numa tela que já
   rolava, e o markup dela vivia copiado em 5 HTMLs. Agora a gaveta é montada
   pelo shared.js — ver a seção NAVEGAÇÃO lá, inclusive o porquê de ela ser
   sobreposta e não empurrar o conteúdo.
   ========================================================================== */
/* ==========================================================================
   BARRA LATERAL DE MÓDULOS — fina sempre, larga quando pedida (25/08/2026)

   Substituiu a gaveta que só existia enquanto aberta. Agora a barra vive na
   tela mostrando SÓ os ícones (`--rail-fina`), e o hambúrguer no topo dela a
   expande para `--rail-larga` revelando os rótulos.

   ── Alargar não reflui nada ──────────────────────────────────────────────────
   A barra é `position: fixed`, então expandir passa POR CIMA do conteúdo. Foi a
   condição para aceitar uma barra permanente: o painel da portaria é um grid de
   3 colunas ajustado à altura da janela, e empurrá-lo a cada abertura o
   remontaria inteiro.

   O que o conteúdo paga é só a faixa fina: `body.tem-nav-rail main` reserva
   `--rail-fina` de padding à esquerda, uma vez, sem nunca mudar.

   ── Os rótulos somem por LARGURA, não por display ───────────────────────────
   `.nav-item-txt` fica com `width: 0; overflow: hidden` quando recolhida. Com
   `display: none` o leitor de tela perderia o nome do item, e sobraria só um
   ícone sem etiqueta. Assim o texto continua no DOM e é lido normalmente.
   ========================================================================== */
:root {
  --rail-fina: 60px;
  --rail-larga: 268px;
}

.nav-drawer {
  position: fixed;
  left: 0;
  top: var(--header-h, 68px);
  bottom: 0;
  width: var(--rail-fina);
  z-index: 200;
  display: flex;
  flex-direction: column;
  background: var(--bg-primary);
  border-right: 1px solid var(--border-color);
  overflow: hidden;
  transition: width 0.22s cubic-bezier(0.32, 0.72, 0, 1), box-shadow 0.22s ease;
}
.nav-drawer.is-open {
  width: var(--rail-larga);
  box-shadow: 6px 0 30px -10px rgba(0, 0, 0, 0.6);
}

/* Reserva a faixa da barra fina. Só no <main>: o cabeçalho é sticky e ocupa a
   largura toda, com a barra começando abaixo dele. */
/* ⚠️ `html` no seletor NÃO é enfeite — é o que faz esta regra vencer.
   As páginas definem `body.diretorio main { … padding: 1.5rem 1rem }`, e o
   ABREVIADO reescreve o padding-left inteiro. Como aquelas regras vêm depois
   no arquivo e tinham a MESMA especificidade, o conteúdo do Diretório e do
   Estacionamento ficou embaixo da barra — e assim foi para produção.
   `html body.tem-nav-rail main` sobe para (0,1,3) e ganha de (0,1,2), sem
   precisar de !important e sem depender da ordem do arquivo. */
html body.tem-nav-rail main { padding-left: calc(var(--rail-fina) + 1rem); }

.nav-backdrop {
  position: fixed;
  inset: 0;
  z-index: 190;
  background: rgba(2, 6, 23, 0.55);
  opacity: 0;
  transition: opacity 0.22s ease;
}
.nav-backdrop.is-open { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .nav-backdrop, .nav-drawer, .nav-item-txt { transition: none; }
}

/* O hambúrguer é o topo da barra e acompanha a largura dela. */
.nav-drawer-head {
  flex-shrink: 0;
  padding: 10px;
  border-bottom: 1px solid var(--border-color);
}
.nav-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  color: var(--text-main);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.nav-toggle svg { width: 22px; height: 22px; display: block; }
.nav-toggle:hover { background: var(--bg-card-hover); border-color: var(--accent-primary); }
.nav-toggle:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 2px; }

.nav-drawer-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px;
  overflow-y: auto;
  overflow-x: hidden;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px;
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  color: var(--text-muted);
  text-decoration: none;
  white-space: nowrap;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.nav-item:hover { background: var(--bg-card-hover); color: var(--text-main); border-color: var(--border-color); }
.nav-item:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 2px; }

.nav-item-ico { width: 22px; height: 22px; flex-shrink: 0; color: inherit; }
.nav-item-ico svg { width: 100%; height: 100%; display: block; }

/* Recolhido: largura zero. O texto continua no DOM para o leitor de tela. */
.nav-item-txt {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  width: 0;
  opacity: 0;
  overflow: hidden;
  transition: opacity 0.16s ease;
}
.nav-drawer.is-open .nav-item-txt { width: auto; opacity: 1; }

.nav-item-rotulo { font-weight: 600; font-size: 0.92rem; line-height: 1.25; color: var(--text-main); }
.nav-item-desc {
  font-size: 0.73rem;
  line-height: 1.3;
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
}

.nav-item.is-current {
  background: var(--accent-primary);
  border-color: var(--accent-primary);
  cursor: default;
}
.nav-item.is-current .nav-item-rotulo,
.nav-item.is-current .nav-item-ico { color: #ffffff; }
.nav-item.is-current .nav-item-desc { color: rgba(255, 255, 255, 0.82); }

/* ==========================================================================
   AÇÃO DO CABEÇALHO (hoje só "Médicos", só na portaria)

   ⚠️ Este bloco JÁ FOI APAGADO SEM QUERER uma vez, em 25/08/2026: ele morava
   dentro do trecho `.nav-toggle … .header-status` que foi substituído inteiro
   ao trocar a gaveta pela barra lateral. O botão continuou no DOM e sem estilo
   colapsou para 4x19 px com o SVG em 0x0 — invisível, e assim foi para
   produção. Se for mexer no bloco da navegação, confira que estas regras
   sobreviveram.

   Discreto de propósito: contorno apagado e ícone cinza, acendendo no hover —
   é consulta eventual, não deve competir com o status nem com o "Sair".
   ========================================================================== */
.header-acao {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  padding: 0;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.header-acao svg { width: 21px; height: 21px; display: block; }
.header-acao:hover {
  background: var(--bg-secondary);
  color: var(--text-main);
  border-color: var(--accent-primary);
}
.header-acao:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 2px; }
body.portaria .header-acao { color: #cbd5e1; }
body.portaria .header-acao:hover { color: #ffffff; }

/* Tela estreita: a barra AFINA, mas nunca some.
   A primeira versão a zerava (`width: 0`) para devolver largura ao conteúdo —
   e o hambúrguer mora DENTRO dela, então não sobrava como abrir o menu. Aqui a
   faixa continua clicável e só o quanto ela custa muda. */
@media (max-width: 900px) {
  :root { --rail-fina: 52px; }
  .nav-drawer.is-open { width: min(var(--rail-larga), 82vw); }
  html body.tem-nav-rail main { padding-left: calc(var(--rail-fina) + 0.75rem); }
  .nav-drawer-head { padding: 8px 6px; }
  .nav-toggle { width: 38px; height: 38px; }
  .nav-item { padding: 10px 8px; }
}

.header-status {
  display: flex;
  align-items: center;
  gap: 16px;
}

/* Quem está logado — montado pelo shared.js, existe em todas as páginas.
   Não é decoração: a portaria é posto de turno, e o operador precisa ver de
   relance com qual conta está registrando liberação e baixa de encomenda. */
.header-user {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 4px 12px 4px 4px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-color);
  border-radius: 20px;
  max-width: 240px;
}
.header-user-ini {
  flex-shrink: 0;
  width: 28px; height: 28px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--accent-primary);
  color: #ffffff;
  font-size: 0.72rem; font-weight: 800; letter-spacing: 0.02em;
}
.header-user-txt { display: flex; flex-direction: column; min-width: 0; line-height: 1.2; }
.header-user-nome {
  font-size: 0.82rem; font-weight: 700; color: var(--text-main);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.header-user-papel { font-size: 0.68rem; color: var(--text-muted); }

/* Em tela estreita sobra só a bolinha das iniciais: o cabeçalho já disputa
   espaço com o logo, o status e o "Sair", e o nome é o que menos falta —
   continua no `title` e no leitor de tela. */
@media (max-width: 860px) {
  .header-user { max-width: none; padding: 4px; gap: 0; }
  .header-user-txt { display: none; }
}

.status-indicator {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.85rem;
  padding: 6px 12px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-color);
  border-radius: 20px;
}

.status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background-color: var(--accent-danger);
}

.status-dot.online {
  background-color: var(--accent-success);
  box-shadow: 0 0 8px var(--accent-success);
}

.btn-logout {
  background: transparent;
  border: 1px solid var(--border-color);
  color: var(--text-muted);
  padding: 6px 14px;
  border-radius: var(--radius-md);
  cursor: pointer;
  font-size: 0.85rem;
  transition: all 0.2s ease;
}

.btn-logout:hover {
  background: rgba(239, 68, 68, 0.1);
  color: var(--accent-danger);
  border-color: var(--accent-danger);
}

/* Main Layout */
main {
  flex: 1;
  max-width: 1280px;
  width: 100%;
  margin: 0 auto;
  padding: 2rem;
}

/* Auth Section */
.auth-container {
  max-width: 420px;
  margin: 4rem auto;
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  backdrop-filter: blur(16px);
  border-radius: var(--radius-lg);
  padding: 2.5rem;
  box-shadow: var(--shadow-main);
}

.auth-header {
  text-align: center;
  margin-bottom: 2rem;
}

.auth-header h2 {
  font-size: 1.5rem;
  font-weight: 700;
  margin-bottom: 0.5rem;
}

.auth-header p {
  color: var(--text-muted);
  font-size: 0.9rem;
}

/* Forms */
.form-group {
  margin-bottom: 1.25rem;
}

.form-group label {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: 0.4rem;
}

.form-control {
  width: 100%;
  padding: 0.75rem 1rem;
  background: rgba(15, 23, 42, 0.6);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  color: var(--text-main);
  font-size: 0.95rem;
  font-family: inherit;
  transition: all 0.2s ease;
}

.form-control:focus {
  outline: none;
  border-color: var(--accent-primary);
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2);
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 0.75rem 1.25rem;
  font-size: 0.95rem;
  font-weight: 600;
  border-radius: var(--radius-md);
  border: none;
  cursor: pointer;
  transition: all 0.2s ease;
}

.btn-primary {
  background: linear-gradient(135deg, #3b82f6, #2563eb);
  color: white;
  box-shadow: 0 4px 14px rgba(59, 130, 246, 0.3);
}

.btn-primary:hover {
  background: linear-gradient(135deg, #2563eb, #1d4ed8);
  transform: translateY(-1px);
}

.btn-success {
  background: linear-gradient(135deg, #10b981, #059669);
  color: white;
  box-shadow: 0 4px 14px rgba(16, 185, 129, 0.3);
}

.btn-success:hover {
  background: linear-gradient(135deg, #059669, #047857);
}

.btn-secondary {
  background: var(--bg-secondary);
  color: var(--text-main);
  border: 1px solid var(--border-color);
}

.btn-secondary:hover {
  background: var(--bg-card-hover);
}

/* Tabs System */
.tabs-nav {
  display: flex;
  gap: 8px;
  border-bottom: 1px solid var(--border-color);
  margin-bottom: 2rem;
}

.tab-btn {
  padding: 0.85rem 1.5rem;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  color: var(--text-muted);
  font-weight: 600;
  font-size: 0.95rem;
  cursor: pointer;
  transition: all 0.2s ease;
  display: flex;
  align-items: center;
  gap: 8px;
}

.tab-btn:hover {
  color: var(--text-main);
}

.tab-btn.active {
  color: var(--accent-primary);
  border-bottom-color: var(--accent-primary);
}

.tab-content {
  display: none;
}

.tab-content.active {
  display: block;
  animation: fadeIn 0.3s ease;
}

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Card Containers */
.card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  backdrop-filter: blur(12px);
  border-radius: var(--radius-lg);
  padding: 1.75rem;
  margin-bottom: 2rem;
  box-shadow: var(--shadow-main);
}

.card-title {
  font-size: 1.2rem;
  font-weight: 700;
  margin-bottom: 1.25rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

/* Controls Header (Search + Actions) */
.controls-bar {
  display: flex;
  gap: 16px;
  margin-bottom: 1.5rem;
  flex-wrap: wrap;
}

.search-box {
  flex: 1;
  min-width: 280px;
  position: relative;
}

.search-box input {
  padding-left: 2.75rem;
}

.search-icon {
  position: absolute;
  left: 1rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-dim);
}

/* Table Styling */
.table-responsive {
  overflow-x: auto;
  border-radius: var(--radius-md);
  border: 1px solid var(--border-color);
}

table {
  width: 100%;
  border-collapse: collapse;
  text-align: left;
  font-size: 0.9rem;
}

th {
  background: rgba(15, 23, 42, 0.8);
  color: var(--text-muted);
  font-weight: 600;
  padding: 1rem;
  border-bottom: 1px solid var(--border-color);
  text-transform: uppercase;
  font-size: 0.75rem;
  letter-spacing: 0.05em;
}

td {
  padding: 1rem;
  border-bottom: 1px solid var(--border-color);
  color: var(--text-main);
}

tbody tr {
  transition: background 0.15s ease;
}

tbody tr:hover {
  background: var(--bg-card-hover);
}

/* Badges */
.badge {
  display: inline-flex;
  align-items: center;
  padding: 0.25rem 0.65rem;
  border-radius: 12px;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.badge-visitor {
  background: rgba(59, 130, 246, 0.15);
  color: #60a5fa;
  border: 1px solid rgba(59, 130, 246, 0.3);
}

.badge-active {
  background: rgba(16, 185, 129, 0.15);
  color: #34d399;
  border: 1px solid rgba(16, 185, 129, 0.3);
}

.badge-expired {
  background: rgba(239, 68, 68, 0.15);
  color: #f87171;
  border: 1px solid rgba(239, 68, 68, 0.3);
}

/* Grid Layout for Forms */
.grid-2 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1.25rem;
}

/* Modal System */
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.75);
  backdrop-filter: blur(8px);
  display: flex;
  /* flex-start + margin:auto no card: centraliza quando cabe na tela e, quando não
     cabe, rola a partir do TOPO. Com align-items:center o topo de um modal alto
     fica inacessível — o overflow corta para cima e não há como rolar até lá. */
  align-items: flex-start;
  justify-content: center;
  overflow-y: auto;
  /* Impede o encadeamento do scroll: ao chegar ao fim do modal a roda do mouse
     parava de rolar o modal e passava a rolar a página atrás dele. */
  overscroll-behavior: contain;
  padding: 1.5rem 1rem;
  z-index: 1000;
  opacity: 0;
  visibility: hidden;
  transition: all 0.25s ease;
}

.modal-overlay.active {
  opacity: 1;
  visibility: visible;
}

.modal-card {
  background: #ffffff;
  color: #1e293b;
  width: 90%;
  max-width: 440px;
  border-radius: var(--radius-lg);
  padding: 2rem;
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
  position: relative;
  margin: auto;   /* par do align-items:flex-start do overlay — ver comentário lá */
  transform: scale(0.95);
  transition: transform 0.25s ease;
}

/* Enquanto um modal está aberto a página atrás não rola (o shared.js põe e tira
   a classe). O scrollbar-gutter evita o "pulo" de layout ao sumir a barra. */
body.modal-open {
  overflow: hidden;
  scrollbar-gutter: stable;
}

.modal-overlay.active .modal-card {
  transform: scale(1);
}

.btn-close-modal {
  position: absolute;
  top: 1rem;
  right: 1rem;
  background: transparent;
  border: none;
  font-size: 1.5rem;
  color: #64748b;
  cursor: pointer;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.btn-close-modal:hover {
  background: #f1f5f9;
}

/* Modal de Detalhes da Passagem (Catraca ao Vivo) */
.modal-event-detail {
  max-width: 520px;
  padding: 1.5rem;
  background: #ffffff;
  border-radius: var(--radius-lg);
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.6);
}

.event-detail-photos {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-bottom: 1.25rem;
}

.event-photo-box {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  background: #f1f5f9;
  border-radius: var(--radius-md);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid #e2e8f0;
}

.event-photo-box img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.event-photo-box img[src=""],
.event-photo-box img:not([src]) {
  display: none;
}

.event-photo-fallback {
  font-size: 2.5rem;
  color: #94a3b8;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.event-photo-box img[src]:not([src=""]) + .event-photo-fallback {
  display: none;
}

.event-detail-info {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  font-size: 1.05rem;
  color: #1e293b;
}

.event-info-row {
  line-height: 1.4;
  word-break: break-word;
}

.event-info-row strong {
  font-weight: 700;
  color: #0f172a;
  margin-right: 4px;
}

.event-detail-actions {
  margin-top: 1.25rem;
}

/* Modal de Médicos (Consulta e Gestão em Tela Ampla) */
.modal-doctors {
  max-width: 1200px;
  width: 95vw;
  height: 90vh;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  padding: 1.75rem;
}

.modal-header-flex {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1rem;
}

.doctors-header-info {
  display: flex;
  align-items: center;
  gap: 12px;
}

.doctors-count-badge {
  font-size: 0.85rem;
  background: #e2e8f0;
  color: #334155;
  padding: 2px 10px;
  border-radius: 12px;
  font-weight: 600;
}

.doctors-toolbar {
  background: #f8fafc;
  border: 1px solid #e2e8f0;
  border-radius: var(--radius-md);
  padding: 1rem 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 1rem;
}

.doctors-filters-grid {
  display: grid;
  grid-template-columns: 2fr 1.5fr 1fr 1.5fr auto auto;
  gap: 10px;
  align-items: flex-end;
}

@media (max-width: 900px) {
  .doctors-filters-grid {
    grid-template-columns: 1fr 1fr;
  }
}

.doctors-filter-item {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.doctors-filter-item label,
.doctors-toolbar label {
  font-size: 0.78rem;
  font-weight: 800;
  color: #0f172a !important; /* Cor preta para leitura perfeita no fundo branco */
  text-transform: uppercase;
  letter-spacing: 0.04em;
  display: flex;
  align-items: center;
  gap: 4px;
}

.doctors-filter-item input.form-control,
.doctor-form-wrap input.form-control:not([id*="Phone"]) {
  text-transform: uppercase;
}

.btn-clear-filters {
  white-space: nowrap;
  padding: 8px 14px;
  font-weight: 600;
  height: 38px;
  background: #ffffff;
  border: 1px solid #cbd5e1;
  color: #475569;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: all 0.15s;
}

.btn-clear-filters:hover {
  background: #f1f5f9;
  color: #0f172a;
  border-color: #94a3b8;
}

.btn-add-doctor {
  white-space: nowrap;
  padding: 8px 18px;
  font-weight: 600;
  height: 38px;
}

.doctor-form-wrap {
  background: #f8fafc;
  border: 1px solid #cbd5e1;
  border-radius: var(--radius-md);
  padding: 1.25rem;
  margin-bottom: 1rem;
}

.doctor-form-title {
  font-weight: 700;
  font-size: 1rem;
  color: #0f172a;
  margin-bottom: 0.75rem;
}

.grid-phones {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 10px;
}

.doctors-table-wrap {
  flex: 1;
  overflow-y: auto;
  min-height: 250px;
  border: 1px solid #cbd5e1;
  border-radius: var(--radius-sm);
  margin-bottom: 1rem;
  background: #ffffff;
}

.doctors-table {
  width: 100%;
  border-collapse: collapse;
}

.doctors-table th {
  position: sticky;
  top: 0;
  background: #f8fafc;
  z-index: 2;
  font-size: 0.76rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 8px 10px;
  border-bottom: 2px solid #e2e8f0;
  color: #475569;
}

.doctors-table td {
  padding: 6px 10px;
  border-bottom: 1px solid #f1f5f9;
  font-size: 0.9rem;
  vertical-align: middle;
}

.doctors-table th.col-name { min-width: 180px; }
.doctors-table th.col-specialty { min-width: 150px; }
.doctors-table th.col-room { width: 75px; text-align: center; }
.doctors-table td.col-room { text-align: center; }
.doctors-table th.col-phone { width: 320px; min-width: 270px; }
.doctors-table th.col-company { min-width: 150px; }
.doctors-table th.col-actions { width: 65px; text-align: right; }

.phone-tags-wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
}

.phone-tag {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  background: #f8fafc;
  color: #1e293b;
  padding: 2px 7px;
  border-radius: 4px;
  font-size: 0.82rem;
  font-weight: 500;
  border: 1px solid #cbd5e1;
  white-space: nowrap;
}

.doctors-table tbody tr {
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.doctors-table tbody tr:hover td {
  background: #f1f5f9;
}

.doctor-form-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 1rem;
  padding-top: 0.75rem;
  border-top: 1px solid #e2e8f0;
}

.doctor-form-actions-right {
  display: flex;
  gap: 8px;
}

.btn-danger-outline {
  background: #fff;
  border: 1px solid #fca5a5;
  color: #dc2626;
  padding: 6px 14px;
  border-radius: var(--radius-sm);
  font-weight: 600;
  cursor: pointer;
  transition: all 0.15s;
}

.btn-danger-outline:hover {
  background: #fef2f2;
  border-color: #ef4444;
}

.specialty-badge {
  display: inline-block;
  background: #f0fdf4;
  color: #166534;
  font-weight: 600;
  font-size: 0.8rem;
  padding: 2px 8px;
  border-radius: 6px;
  border: 1px solid #bbf7d0;
}

.room-badge {
  display: inline-block;
  background: #e0f2fe;
  color: #0369a1;
  font-weight: 700;
  font-size: 0.82rem;
  padding: 2px 8px;
  border-radius: 6px;
  border: 1px solid #bae6fd;
}

.btn-icon-action {
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 4px 6px;
  font-size: 1rem;
  border-radius: 4px;
  transition: background 0.15s;
}

.btn-icon-action:hover {
  background: #e2e8f0;
}

.modal-footer-actions {
  margin-top: auto;
}

/* Ticket / Badge Preview (Modal) */
.badge-preview {
  text-align: center;
  padding: 1.5rem 1rem;
  border: 2px dashed #cbd5e1;
  border-radius: var(--radius-md);
  margin: 1.25rem 0;
  background: #fafafa;
}

.badge-preview .building-name {
  font-size: 0.8rem;
  font-weight: 700;
  color: #2563eb;
  text-transform: uppercase;
  letter-spacing: 0.08em;

}

.badge-preview .visitor-name {
  font-size: 1.35rem;
  font-weight: 800;
  color: #0f172a;
  margin: 0.5rem 0 0.2rem 0;
}

.badge-preview .destination {
  font-size: 0.9rem;
  color: #475569;
  font-weight: 600;
  margin-bottom: 1.25rem;
}

.qrcode-box {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 1rem 0;
  padding: 10px;
  background: white;
  border-radius: 8px;

}

.qrcode-box img, .qrcode-box canvas {
  margin: 0 auto;
}

/* Avatar & Facial Thumbnail Styling */
.table-avatar {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--border-color);
  background-color: var(--bg-secondary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
  transition: transform 0.2s ease, border-color 0.2s ease;
}

.table-avatar:hover {
  transform: scale(1.15);
  border-color: var(--accent-primary);
  z-index: 10;
}

.badge-preview .validity {
  font-size: 0.75rem;
  color: #64748b;
  margin-top: 0.75rem;
}

.badge-preview .qrcode-code {
  font-family: monospace;
  font-size: 0.85rem;
  color: #0f172a;
  font-weight: 700;
  letter-spacing: 0.05em;
  margin-top: 0.25rem;
}

/* Alert Boxes */
.alert {
  padding: 0.85rem 1.25rem;
  border-radius: var(--radius-md);
  margin-bottom: 1.25rem;
  font-size: 0.9rem;
  display: none;
}

.alert-danger {
  background: rgba(239, 68, 68, 0.15);
  color: #f87171;
  border: 1px solid rgba(239, 68, 68, 0.3);
}

.alert-success {
  background: rgba(16, 185, 129, 0.15);
  color: #34d399;
  border: 1px solid rgba(16, 185, 129, 0.3);
}

/* ==========================================================================
   Print Styles (Optimized for Thermal Printers 80mm & Badges)
   ========================================================================== */
@media print {
  /* ⚠️ ESCOPADO em body:not(.dashboard). Esta regra e a irmã lá embaixo
     (`header, main { display:none }`) foram escritas quando só o crachá ia para
     o papel, e valiam para TODA página. O resultado é que o botão
     "Imprimir / PDF" do dashboard produzia uma folha em branco: `main` sumia e
     tudo mais ficava invisível. Ao criar outra tela que imprime, escope aqui. */
  body:not(.dashboard) * {
    visibility: hidden;
  }
  
  #printableBadge, #printableBadge * {
    visibility: visible;
  }
  
  #printableBadge {
    position: absolute;
    left: 0;
    top: 0;
    width: 80mm;
    padding: 5mm;
    color: #000;
    background: #fff;
    font-family: sans-serif;
    text-align: center;
  }
  
  .modal-overlay {
    background: none;
    position: static;
  }
  
  .modal-card {
    box-shadow: none;
    padding: 0;
    max-width: 100%;
  }

  body:not(.dashboard) .btn, body:not(.dashboard) .btn-close-modal,
  body:not(.dashboard) header, body:not(.dashboard) .tabs-nav,
  body:not(.dashboard) .card, body:not(.dashboard) .controls-bar {
    display: none !important;
  }

  .badge-preview {
    border: none;
    margin: 0;
    padding: 0;
    background: none;
  }

  .qrcode-box img {
    width: 180px !important;
    height: 180px !important;
  }


  /* A marca d'água é `position: fixed` e se repete em toda página impressa —
     no crachá ela enchia a folha de cinza atrás de um cartão de 8 cm. */
  body::before { display: none !important; }
}

/* ==========================================================================
   Edit User Modal — wide landscape layout with internal scrolling
   ========================================================================== */
.edit-modal-card {
  max-width: 940px;
  width: 96%;
  max-height: 92vh;
  background: var(--bg-secondary);
  color: var(--text-main);
  border: 1px solid var(--border-color);
  padding: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.edit-modal-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 1.1rem 3.25rem 1.1rem 1.5rem;
  border-bottom: 1px solid var(--border-color);
  flex-shrink: 0;
}

.edit-modal-header h3 {
  font-size: 1.15rem;
  color: var(--text-main);
  display: flex;
  align-items: center;
  gap: 8px;
}

.edit-modal-card .btn-close-modal {
  color: var(--text-muted);
}

.edit-modal-card .alert {
  margin: 0.75rem 1.5rem 0;
  flex-shrink: 0;
}

.edit-modal-form {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

.edit-modal-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 1.5rem;
  display: grid;
  grid-template-columns: 210px 1fr;
  gap: 1.5rem;
  align-items: start;
}

.edit-photo-panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 1.25rem 1rem;
  background: rgba(15, 23, 42, 0.4);
  border: 1px dashed var(--border-color);
  border-radius: var(--radius-md);
  text-align: center;
}

.edit-photo-panel img {
  width: 140px;
  height: 140px;
  border-radius: 50%;
  object-fit: cover;
  border: 3px solid var(--accent-primary);
  background: var(--bg-primary);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
}

.edit-photo-panel .btn {
  width: auto;
  padding: 0.5rem 0.9rem;
  font-size: 0.82rem;
  cursor: pointer;
}

.edit-photo-hint {
  font-size: 0.72rem;
  color: var(--text-dim);
  line-height: 1.4;
}

.edit-fields-panel {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem 1.25rem;
  align-content: start;
}

.edit-fields-panel .form-group {
  margin-bottom: 0;
}

.edit-fields-panel .span-2 {
  grid-column: 1 / -1;
}

.quick-validity-row {
  display: flex;
  gap: 6px;
  margin-top: 6px;
  flex-wrap: wrap;
}

.quick-validity {
  background: rgba(59, 130, 246, 0.12);
  color: var(--accent-primary);
  border: 1px solid rgba(59, 130, 246, 0.35);
  border-radius: 999px;
  padding: 3px 10px;
  font-size: 0.72rem;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: all 0.15s ease;
}

.quick-validity:hover {
  background: rgba(59, 130, 246, 0.28);
}

.edit-modal-footer {
  display: flex;
  gap: 10px;
  padding: 1rem 1.5rem;
  border-top: 1px solid var(--border-color);
  background: rgba(15, 23, 42, 0.5);
  flex-shrink: 0;
}

.edit-modal-footer .btn {
  flex: 1;
}

.edit-modal-footer .btn-cancel {
  flex: 0 0 auto;
  width: auto;
  background: transparent;
  color: var(--text-muted);
  border: 1px solid var(--border-color);
  box-shadow: none;
}

.edit-modal-footer .btn-cancel:hover {
  color: var(--text-main);
  background: rgba(255, 255, 255, 0.06);
}

/* Portrait / narrow screens: stack photo above fields, single column */
@media (max-width: 760px) {
  .edit-modal-card {
    max-height: 96vh;
    width: 100%;
    border-radius: var(--radius-md);
  }

  .edit-modal-body {
    grid-template-columns: 1fr;
    padding: 1rem;
  }

  .edit-photo-panel {
    flex-direction: row;
    justify-content: flex-start;
    text-align: left;
  }

  .edit-photo-panel img {
    width: 90px;
    height: 90px;
    flex-shrink: 0;
  }

  .edit-photo-panel > div {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
  }

  .edit-fields-panel {
    grid-template-columns: 1fr;
  }

  .edit-modal-footer {
    flex-wrap: wrap;
  }
}

/* ==========================================================================
   Fullscreen Camera Modal (Totem)
   ========================================================================== */
.cam-modal {
  position: fixed;
  inset: 0;
  height: 100dvh;
  background: #000;
  z-index: 1100;
  display: none;
  align-items: center;
  justify-content: center;
}

.cam-modal.active {
  display: flex;
}

/* 3x4 portrait frame — the capture crops exactly this area, so what the visitor frames
   inside the silhouette is what the facial reader receives. Width is the driving
   dimension: min() keeps the 3:4 box clear of the top bar (~70px) and controls (~110px). */
.cam-frame {
  position: relative;
  aspect-ratio: 3 / 4;
  width: min(92vw, calc((100dvh - 190px) * 0.75));
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.25), 0 25px 50px -12px rgba(0, 0, 0, 0.8);
}

.cam-frame video,
.cam-frame canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.cam-silhouette {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* Mirror only the live preview (selfie convention) — the captured photo stays unmirrored. */
.cam-modal video {
  transform: scaleX(-1);
}

.cam-modal-topbar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 1.25rem;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0.7), transparent);
  color: #fff;
  font-weight: 600;
  z-index: 1;
}

.cam-modal-close {
  background: rgba(0, 0, 0, 0.5);
  border: 1px solid rgba(255, 255, 255, 0.3);
  color: #fff;
  font-size: 1.3rem;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  cursor: pointer;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.cam-modal-controls {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  justify-content: center;
  gap: 12px;
  padding: 1.5rem 1.25rem 2rem;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.7), transparent);
  z-index: 1;
}

.cam-modal-controls .btn {
  width: auto;
  padding: 14px 28px;
  font-size: 1.05rem;
}

/* ==========================================================================
   Combo de busca (empresa) — Totem e Portaria
   ========================================================================== */
.combo { position: relative; }
.combo-list {
  display: none; position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 50;
  max-height: 260px; overflow-y: auto;
  background: var(--bg-secondary); border: 1px solid var(--border-color);
  border-radius: var(--radius-md); box-shadow: var(--shadow-main);
}
.combo-item { padding: 11px 14px; cursor: pointer; font-size: 0.95rem; border-bottom: 1px solid var(--border-color); }
.combo-item:last-child { border-bottom: none; }
.combo-item:hover, .combo-item.active { background: var(--accent-primary); color: #fff; }
.combo-empty { padding: 11px 14px; color: var(--text-dim); font-size: 0.9rem; }

/* Drop-up: no Totem a lista abre PARA CIMA do campo, para o teclado do tablet (que
   sobe por baixo) não cobri-la. Rolagem grande para caber as 92 empresas. */
.combo.drop-up .combo-list { top: auto; bottom: calc(100% + 4px); max-height: 340px; }

/* ==========================================================================
   Totem — formulário legível e encaixe acima do teclado do tablet.

   O totem é usado de pé, por qualquer pessoa que entra no prédio: a letra tem de
   ser grande. Até 14/08/2026 o card inteiro era ENCOLHIDO (transform: scale, até
   55%) para caber acima do teclado do Android — e quem enxerga mal simplesmente
   não conseguia ler o que estava preenchendo.

   Agora NADA é escalado. O espaço vem de duas fontes, nesta ordem:
     1. o cadastro novo foi dividido em telas de poucos campos (dados / destino),
        então o card já nasce baixo o bastante;
     2. com o teclado aberto, a classe .kb-open recolhe FOLGA — cabeçalho, margens,
        respiros — e o JS rola o campo em foco para a área visível.
   O tamanho da fonte nunca entra nessa conta.
   ========================================================================== */
body.totem .form-control { font-size: 1.15rem; padding: 0.85rem 1rem; }
body.totem .form-group label { font-size: 0.95rem; }
body.totem main .btn { font-size: 1.05rem; padding: 0.85rem 1.25rem; }

/* ==========================================================================
   qrtotem — pré-cadastro público, aberto no celular do visitante (D-023).
   Só uma tela por vez (#stepGeo / #stepForm / #stepWait / #stepDone), num
   card centralizado. Herda o resto do styles.css.
   ========================================================================== */
body.qrtotem main {
  display: flex; justify-content: center; align-items: flex-start;
  padding: 1.25rem 1rem 3rem;
}
body.qrtotem .qr-wrap { width: 100%; max-width: 460px; }
body.qrtotem .form-control { font-size: 1.05rem; padding: 0.8rem 0.95rem; }
body.qrtotem .card > .btn { width: 100%; margin-top: 0.25rem; }
.qr-lead { color: var(--text-muted); font-size: 0.92rem; line-height: 1.5; margin: 0.25rem 0 1rem; }
.qr-dim { color: var(--text-dim); font-size: 0.82rem; }
.qr-done-msg { font-size: 1.05rem; line-height: 1.55; }
.qr-foto-linha { display: flex; align-items: center; gap: 12px; }
.qr-foto-thumb {
  width: 54px; height: 72px; object-fit: cover; flex-shrink: 0;
  border-radius: var(--radius-sm); border: 1px solid var(--accent-primary);
}
.qr-check {
  display: flex; align-items: flex-start; gap: 10px; cursor: pointer;
  font-weight: 400; text-transform: none; letter-spacing: normal;
  font-size: 0.88rem; line-height: 1.45;
}
.qr-check input { width: auto; margin-top: 3px; flex-shrink: 0; }
.qr-check a { color: var(--accent-primary); font-weight: 600; }
.qr-spinner {
  width: 34px; height: 34px; margin: 1rem auto;
  border: 3px solid var(--border-color); border-top-color: var(--accent-primary);
  border-radius: 50%; animation: qr-spin 0.8s linear infinite;
}
@keyframes qr-spin { to { transform: rotate(360deg); } }

/* Balão de dica — fundo amarelo, letra preta, para orientar quem está no totem.
   Fica ABAIXO do campo, com a setinha apontando para ele: a lista do combo de
   empresas abre para CIMA (.combo.drop-up), então acima o balão sumiria atrás dela.
   As duas setas sobrepostas (::before um pixel acima do ::after) são o truque para
   a pontinha também ganhar a borda. */
.hint-balloon {
  position: relative;
  margin-top: 12px;
  background: #FDE047;
  color: #000;
  font-size: 1.02rem;
  font-weight: 600;
  line-height: 1.4;
  padding: 12px 15px;
  border-radius: 10px;
  border: 1px solid #CA8A04;
  box-shadow: 0 3px 12px rgba(0, 0, 0, 0.3);
}
.hint-balloon::before,
.hint-balloon::after {
  content: '';
  position: absolute;
  left: 28px;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
}
.hint-balloon::before { top: -11px; border-bottom: 10px solid #CA8A04; }   /* borda */
.hint-balloon::after  { top: -10px; border-bottom: 10px solid #FDE047; }   /* miolo */

/* Progresso do cadastro novo: ● ○ = tela 1 de 2. */
.step-dots { display: flex; justify-content: center; gap: 8px; margin: -0.5rem 0 1.1rem; }
.step-dots span {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--border-color); transition: background 0.2s ease;
}
.step-dots span.on { background: var(--accent-primary); width: 26px; border-radius: 5px; }

/* Teclado aberto: recolhe folga (e só folga) para o campo em foco caber acima dele.
   O padding-bottom generoso é o que permite ao JS rolar o campo para cima — sem ele
   a página não tem para onde rolar quando o conteúdo é mais curto que a tela. */
body.totem.kb-open header { display: none; }
body.totem.kb-open main { padding-top: 6px !important; padding-bottom: 55vh; }
body.totem.kb-open .card { padding: 1rem; margin-bottom: 0; }
body.totem.kb-open .card-title { font-size: 1.05rem; margin-bottom: 0.6rem; }
body.totem.kb-open .step-dots { margin: -0.2rem 0 0.7rem; }
body.totem.kb-open .form-group { margin-bottom: 0.85rem; }

/* ==========================================================================
   Totem — passo de foto em tela cheia
   ========================================================================== */
/* Contagem 3-2-1 grande sobre a moldura da câmera. */
.cam-countdown {
  position: absolute; inset: 0; display: none; align-items: center; justify-content: center;
  font-size: 6rem; font-weight: 800; color: #fff; pointer-events: none; z-index: 2;
  text-shadow: 0 2px 16px rgba(0, 0, 0, 0.85);
}
/* Mensagem na tela de captura (tela cheia). */
.cam-title { font-size: 1.05rem; font-weight: 700; line-height: 1.3; }
.cam-subtitle { font-weight: 500; opacity: 0.9; margin-top: 2px; }

/* Mensagem grande da tela final de sucesso. */
.success-msg {
  font-size: 1.7rem; font-weight: 700; line-height: 1.45; color: var(--text-main);
  margin: 0.5rem auto; max-width: 26ch;
}

/* ==========================================================================
   Dashboard — visão geral (usado na aba "Dashboard" da portaria e em dashboard.html)
   ========================================================================== */

/* Tokens de visualização (paleta categórica validada p/ superfície escura) */
:root {
  --series-1: #3987e5;  /* Funcionários */
  --series-2: #d95926;  /* Visitantes */
  --series-3: #199e70;  /* Prestadores */
  --series-4: #c98500;  /* Moradores */
  --series-5: #d55181;  /* Visitantes de unidade */
  --status-good: #0ca30c;
  --status-critical: #d03b3b;
  --viz-out: #94a3b8;   /* Saídas — mesmo slate do pill "◂ Saída" do feed */
  --viz-grid: rgba(255, 255, 255, 0.08);
  --viz-axis: rgba(255, 255, 255, 0.16);
}

/* Abas (Liberação de Acesso / Dashboard) */
.tab-nav { display: flex; gap: 8px; margin-bottom: 1.5rem; border-bottom: 1px solid var(--border-color); }
.tab-btn {
  background: none; border: none; border-bottom: 2px solid transparent; color: var(--text-muted);
  padding: 10px 18px; font-size: 0.95rem; font-weight: 600; cursor: pointer; font-family: var(--font-family);
  margin-bottom: -1px;
}
.tab-btn:hover { color: var(--text-main); }
.tab-btn.active { color: var(--accent-primary); border-bottom-color: var(--accent-primary); }

/* dashboard.html standalone usa <main class="dashboard-view">; na portaria é só um <div> */
.dashboard-view { width: 100%; padding-bottom: 2rem; }

/* Linha de filtros */
.filter-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 1.25rem; }
.filter-chip {
  background: var(--bg-secondary); border: 1px solid var(--border-color); color: var(--text-muted);
  border-radius: 20px; padding: 7px 18px; font-size: 0.85rem; font-weight: 600; cursor: pointer;
  font-family: var(--font-family);
}
.filter-chip:hover { color: var(--text-main); }
.filter-chip.active { background: var(--accent-primary); border-color: var(--accent-primary); color: #fff; }
.refresh-note { margin-left: auto; color: var(--text-dim); font-size: 0.8rem; }

/* KPIs */
.kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 1rem; margin-bottom: 1.25rem; }
.kpi-tile { background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-lg); padding: 1rem 1.25rem; }
.kpi-label { color: var(--text-muted); font-size: 0.8rem; font-weight: 600; }
.kpi-value { font-size: 2rem; font-weight: 700; letter-spacing: -0.02em; line-height: 1.2; margin-top: 2px; }
.kpi-context { color: var(--text-dim); font-size: 0.75rem; margin-top: 2px; }

/* Tile com DOIS números lado a lado (contagem por módulo). O `1.6rem` é menor que
   o `.kpi-value` de 2rem de propósito: dois números no espaço de um, mantendo a
   altura do tile igual à dos vizinhos para a linha de KPIs não desalinhar. */
.kpi-split { display: flex; gap: 1.5rem; margin-top: 2px; }
.kpi-split-item { display: flex; flex-direction: column; min-width: 0; }
.kpi-split-value { font-size: 1.6rem; font-weight: 700; letter-spacing: -0.02em; line-height: 1.2; }
.kpi-split-label { color: var(--text-muted); font-size: 0.72rem; font-weight: 600; }

/* Grid principal */
.dash-grid { display: grid; grid-template-columns: 2fr 1fr; gap: 1rem; margin-bottom: 1.25rem; }
@media (max-width: 980px) { .dash-grid { grid-template-columns: 1fr; } }
.dash-card { background: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-lg); padding: 1.25rem; }
.dash-card-title { display: flex; align-items: center; justify-content: space-between; gap: 10px; font-weight: 700; margin-bottom: 0.75rem; }
.btn-mini {
  background: var(--bg-secondary); border: 1px solid var(--border-color); color: var(--text-muted);
  border-radius: var(--radius-sm); padding: 5px 12px; font-size: 0.75rem; font-weight: 600; cursor: pointer;
  font-family: var(--font-family);
}
.btn-mini:hover { color: var(--text-main); }

/* Gráfico */
.chart-wrap { position: relative; }
.chart-legend { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 6px; font-size: 0.8rem; color: var(--text-muted); }
.chart-legend .swatch { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 6px; vertical-align: -1px; }
.viz-tooltip {
  position: absolute; pointer-events: none; display: none; z-index: 30;
  background: #0f172a; border: 1px solid var(--border-color); border-radius: var(--radius-sm);
  padding: 8px 10px; font-size: 0.78rem; min-width: 150px; box-shadow: var(--shadow-main);
}
.viz-tooltip .tt-title { font-weight: 700; margin-bottom: 4px; }
.viz-tooltip .tt-row { display: flex; justify-content: space-between; gap: 12px; color: var(--text-muted); }
.viz-tooltip .tt-row b { color: var(--text-main); font-variant-numeric: tabular-nums; }
.chart-empty { color: var(--text-dim); text-align: center; padding: 3rem 0; }

/* Tabelas */
.data-table { width: 100%; border-collapse: collapse; font-size: 0.82rem; }
.data-table th { text-align: left; color: var(--text-dim); font-weight: 600; padding: 6px 8px; border-bottom: 1px solid var(--border-color); }
.data-table td { padding: 6px 8px; border-bottom: 1px solid var(--viz-grid); font-variant-numeric: tabular-nums; }
.data-table td.num, .data-table th.num { text-align: right; }
.table-scroll { overflow-x: auto; max-height: 420px; overflow-y: auto; }

/* Feed ao vivo */
.feed-list { display: flex; flex-direction: column; gap: 10px; max-height: 460px; overflow-y: auto; }
.feed-item { display: flex; align-items: center; gap: 10px; cursor: pointer; user-select: none; transition: background 0.15s; border-radius: var(--radius-sm); padding: 4px 6px; }
.feed-item:hover { background: rgba(255, 255, 255, 0.06); }
.feed-item img { width: 44px; height: 44px; border-radius: var(--radius-sm); object-fit: cover; background: var(--bg-secondary); flex-shrink: 0; }
.feed-name { font-weight: 600; font-size: 0.85rem; line-height: 1.25; }
.feed-meta { color: var(--text-dim); font-size: 0.72rem; }
/* Destino da passagem (sala + empresa). A sala vem primeiro e destacada: é o que a
   portaria procura na lista, e a empresa costuma ser longa demais para a lateral. */
.feed-dest { color: var(--text-muted); font-size: 0.74rem; line-height: 1.3; }
.feed-dest strong { color: var(--accent-primary); font-weight: 700; }
.pill { display: inline-flex; align-items: center; gap: 4px; border-radius: 12px; padding: 2px 9px; font-size: 0.7rem; font-weight: 700; flex-shrink: 0; }
.pill-in  { background: rgba(12, 163, 12, 0.15); color: #4ade80; }
.pill-out { background: rgba(148, 163, 184, 0.15); color: var(--text-muted); }
/* Passagem NEGADA pela catraca (evento com blocked:true). Não conta como entrada
   nem como saída — ver o cabeçalho do painel.js. */
.pill-blocked { background: rgba(239, 68, 68, 0.18); color: #fca5a5; }

/* Lista de resultados da busca por nome */
.name-results { margin-top: 12px; display: flex; flex-direction: column; gap: 6px; max-height: 340px; overflow-y: auto; }
.name-results-title { font-size: 0.78rem; color: var(--text-dim); margin-bottom: 4px; }
.name-result-item {
  display: flex; align-items: center; gap: 12px;
  background: rgba(15, 23, 42, 0.55); border: 1px solid var(--border-color);
  border-radius: var(--radius-sm); padding: 10px 14px;
  cursor: pointer; transition: background 0.15s, border-color 0.15s;
}
.name-result-item:hover { background: var(--bg-card-hover); border-color: var(--accent-primary); }
.name-result-item img { width: 42px; height: 42px; border-radius: var(--radius-sm); object-fit: cover; background: var(--bg-secondary); flex-shrink: 0; }
.name-result-photo-empty { width: 42px; height: 42px; border-radius: var(--radius-sm); background: var(--bg-secondary); flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-size: 1.1rem; color: var(--text-dim); }
.name-result-info { flex: 1; min-width: 0; }
.name-result-name { font-weight: 600; font-size: 0.88rem; line-height: 1.3; color: var(--text-main); }
.name-result-doc { font-size: 0.75rem; color: var(--text-muted); }
.name-result-empty { text-align: center; color: var(--text-dim); font-size: 0.82rem; padding: 1.2rem 0; }

/* ==========================================================================
   Portaria — situação da liberação e passaporte
   ========================================================================== */

/* Painel de situação do passo A: responde "já está liberado?" antes de a
   operadora começar a preencher qualquer coisa. */
.rel-status { border-radius: var(--radius-sm); padding: 12px 16px; margin: 12px 0; border: 1px solid var(--border-color); }
.rel-status:empty { display: none; }
.rel-status-head { font-weight: 700; font-size: 1rem; letter-spacing: 0.01em; }
.rel-status-sub { font-size: 0.82rem; color: var(--text-muted); margin-top: 2px; }

.rel-status-ok      { background: rgba(34, 197, 94, 0.12);  border-color: rgba(34, 197, 94, 0.45); }
.rel-status-ok .rel-status-head { color: #4ade80; }
.rel-status-need    { background: rgba(249, 115, 22, 0.12); border-color: rgba(249, 115, 22, 0.45); }
.rel-status-need .rel-status-head { color: #fdba74; }
.rel-status-loading { background: rgba(148, 163, 184, 0.10); border-color: var(--border-color); }
.rel-status-loading .rel-status-head { color: var(--text-dim); font-weight: 600; }

/* Uma linha por autorização válida: papel · onde · até quando. */
.rel-status-line {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin-top: 8px; padding-top: 8px; border-top: 1px solid rgba(148, 163, 184, 0.18);
  font-size: 0.82rem;
}
.rel-status-role  { font-weight: 600; color: var(--text-main); white-space: nowrap; }
/* A empresa vem com recado de garagem colado (até 133 caracteres) — ela é a
   única parte que pode encolher, por isso é a que recebe a ellipsis. */
.rel-status-unit  { color: var(--text-muted); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rel-status-valid { color: var(--text-dim); white-space: nowrap; }
.rel-status-more  { font-size: 0.78rem; color: var(--text-dim); margin-top: 6px; }

/* Botão que reabre o formulário quando a pessoa já está liberada. */
.btn-toggle-form { width: 100%; margin-bottom: 12px; }

/* ==========================================================================
   +1 — o próximo visitante do mesmo grupo
   --------------------------------------------------------------------------
   O botão é âmbar em vez de azul ou verde de propósito: azul já é "buscar" e
   verde é "liberar", e o +1 não faz nem uma coisa nem outra — ele guarda o
   destino e recomeça. Cor própria evita que o dedo caia nele achando que
   confirma a liberação.
   ========================================================================== */
.rel-found-tools { display: flex; gap: 10px; margin-bottom: 12px; }
.rel-found-tools .btn-toggle-form { margin-bottom: 0; }
.rel-found-tools .btn-plus1 { flex-shrink: 0; width: auto; }

.btn-plus1 {
  width: auto;
  padding: 10px 16px;
  border: 1px solid #f59e0b;
  background: rgba(245, 158, 11, 0.20);
  color: #fbbf24;
  font-weight: 800;
  letter-spacing: 0.01em;
  white-space: nowrap;
}
.btn-plus1:hover { background: rgba(245, 158, 11, 0.32); border-color: #fbbf24; }
.btn-plus1.is-forte { background: #f59e0b; color: #1f1300; border-color: #f59e0b; }
.btn-plus1.is-forte:hover { background: #fbbf24; border-color: #fbbf24; }

/* Fita do destino herdado: aparece no topo do passo que o +1 abriu, para o
   operador ver de onde vieram a sala e o nome já preenchidos. */
.plus1-destino {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px;
  padding: 10px 14px;
  margin: 12px 0;
  border: 1px solid #f59e0b;
  border-left-width: 4px;
  border-radius: var(--radius-sm);
  background: rgba(245, 158, 11, 0.10);
}
.plus1-destino.is-fita { margin-top: 0; }
.plus1-rot {
  font-size: 0.68rem; font-weight: 800; letter-spacing: 0.06em;
  text-transform: uppercase; color: #f59e0b;
}
.plus1-empresa { font-weight: 700; }
.plus1-visitado { font-size: 0.85rem; color: var(--text-muted); }
.plus1-validade { font-size: 0.8rem; color: var(--text-dim); }
.plus1-hint { font-size: 0.78rem; color: var(--text-dim); margin-top: 6px; line-height: 1.5; }

/* Atalho da tela principal — só existe depois da primeira liberação da fila. */
.plus1-chip {
  display: flex; align-items: center; gap: 10px;
  margin-top: 10px;
  padding: 8px 8px 8px 14px;
  border: 1px solid var(--border-color);
  border-left: 4px solid #f59e0b;
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
}
.plus1-chip-txt { flex: 1; min-width: 0; font-size: 0.82rem; color: var(--text-muted); }
.plus1-chip-txt b { color: var(--text-main); }
.plus1-chip-x {
  flex-shrink: 0;
  border: 0; background: transparent;
  color: var(--text-dim); font-size: 1.3rem; line-height: 1;
  padding: 0 6px; cursor: pointer;
}
.plus1-chip-x:hover { color: var(--text-main); }
@media (max-width: 620px) {
  .plus1-chip { flex-wrap: wrap; }
  .plus1-chip-txt { flex-basis: 100%; }
}

/* Botão PASSAPORTE, abaixo da busca por CPF/nome. */
.btn-passport { width: 100%; margin-top: 12px; }

/* O código no campo readonly do cadastro: alfanumérico, precisa ser lido letra
   a letra sem confundir caractere parecido. */
.form-control.doc-passport {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 1.15rem; font-weight: 700; letter-spacing: 0.18em;
}

/* Destaque do código no passo de sucesso — é a única chance de anotá-lo. */
.rel-passport {
  margin: 16px auto; max-width: 420px; padding: 16px;
  background: rgba(59, 130, 246, 0.12); border: 1px solid rgba(59, 130, 246, 0.45);
  border-radius: var(--radius-sm); text-align: center;
}
.rel-passport-label { font-size: 0.8rem; color: var(--text-muted); margin-bottom: 8px; }
.rel-passport-code {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 2rem; font-weight: 700; letter-spacing: 0.22em;
  color: var(--text-main); word-break: break-all;
}
.rel-passport-hint { font-size: 0.76rem; color: var(--text-dim); margin-top: 8px; }

/* ==========================================================================
   Módulo Diretório (diretorio.html) — empresas e colaboradores
   ==========================================================================
   Tudo escopado em body.diretorio: o styles.css é compartilhado com totem,
   portaria, admin e dashboard, e nenhum deles pode ser afetado por estas regras. */

body.diretorio main { max-width: 1280px; margin: 0 auto; padding: 1.5rem 1rem; }

/* Duas colunas: navegação (empresas → colaboradores → resultados) à esquerda,
   credenciais de visita à direita. Abaixo de 1080px vira uma coluna só, e a de
   credenciais desce para o fim — a navegação é o uso mais frequente. */
body.diretorio .dir-columns {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 1rem; align-items: start;
}
body.diretorio .dir-col { min-width: 0; }
@media (max-width: 1080px) {
  body.diretorio .dir-columns { grid-template-columns: minmax(0, 1fr); }
}

/* Contagem ao lado do título do cartão ("92", "12 de 92"). */
body.diretorio .dir-count {
  margin-left: auto; font-size: 0.78rem; font-weight: 500; color: var(--text-dim);
}

body.diretorio .dir-back { width: auto; padding: 7px 14px; margin-bottom: 12px; font-size: 0.82rem; }
body.diretorio .dir-unit { font-size: 0.78rem; color: var(--text-muted); margin: -4px 0 12px; }

body.diretorio .dir-list {
  margin-top: 12px; display: flex; flex-direction: column; gap: 6px;
  max-height: 62vh; overflow-y: auto;
}

/* Mesma linguagem visual de .name-result-item, que já resolve lista clicável. */
body.diretorio .dir-row {
  display: flex; align-items: center; gap: 12px;
  background: rgba(15, 23, 42, 0.55); border: 1px solid var(--border-color);
  border-radius: var(--radius-sm); padding: 10px 14px;
}
body.diretorio .dir-company,
body.diretorio .dir-hit { cursor: pointer; transition: background 0.15s, border-color 0.15s; }
body.diretorio .dir-company:hover,
body.diretorio .dir-hit:hover { background: var(--bg-card-hover); border-color: var(--accent-primary); }

body.diretorio .dir-row-main { flex: 1; min-width: 0; }
body.diretorio .dir-row-title {
  font-weight: 600; font-size: 0.88rem; line-height: 1.3; color: var(--text-main);
}
/* O nome da empresa costuma vir com recado de garagem colado (até 133 caracteres),
   então é este trecho que recebe a ellipsis — nunca a contagem. */
body.diretorio .dir-row-sub {
  font-size: 0.75rem; color: var(--text-muted); margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

body.diretorio .dir-count-badge {
  flex-shrink: 0; font-size: 0.74rem; color: var(--text-dim); white-space: nowrap;
}

/* Pessoa localizada pela busca de CPF, dentro da lista da empresa dela. */
body.diretorio .dir-row-hit {
  background: rgba(59, 130, 246, 0.16); border-color: rgba(59, 130, 246, 0.55);
}

body.diretorio .dir-empty {
  text-align: center; color: var(--text-dim); font-size: 0.82rem; padding: 1.2rem 0;
}

/* --------------------------------------------------------------------------
   Credenciais de visita (coluna direita) — cada linha é UMA autorização, com
   as ações que só existem aqui: editar (recria) e apagar.
   -------------------------------------------------------------------------- */
body.diretorio .cred-group {
  font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-dim); margin: 10px 2px 2px;
}
body.diretorio .cred-group:first-child { margin-top: 0; }

body.diretorio .cred-note {
  font-size: 0.72rem; color: var(--text-dim); line-height: 1.4; margin: 2px 2px 6px;
}

body.diretorio .cred-row { flex-direction: column; align-items: stretch; gap: 10px; }
body.diretorio .cred-head { display: flex; align-items: baseline; gap: 8px; }
body.diretorio .cred-name { font-weight: 600; font-size: 0.88rem; color: var(--text-main); }

/* Papel da credencial. Visitante é o caso comum; colaborador aparece em roxo
   porque apagar o acesso de um colaborador é outra conversa. */
body.diretorio .cred-tag {
  flex-shrink: 0; font-size: 0.68rem; font-weight: 600; letter-spacing: 0.04em;
  text-transform: uppercase; padding: 2px 7px; border-radius: 999px;
  background: rgba(59, 130, 246, 0.18); color: #93c5fd; border: 1px solid rgba(59, 130, 246, 0.4);
}
body.diretorio .cred-tag.tag-none {
  background: rgba(148, 163, 184, 0.14); color: var(--text-muted); border-color: var(--border-color);
}
body.diretorio .cred-tag.tag-employee {
  background: rgba(168, 85, 247, 0.16); color: #d8b4fe; border-color: rgba(168, 85, 247, 0.4);
}
body.diretorio .cred-line { font-size: 0.76rem; color: var(--text-muted); line-height: 1.5; }
body.diretorio .cred-line strong { color: var(--text-main); font-weight: 600; }
body.diretorio .cred-actions { display: flex; gap: 8px; }
body.diretorio .cred-actions .btn {
  width: auto; flex: 0 0 auto; padding: 6px 14px; font-size: 0.76rem;
}

body.diretorio .btn-danger { background: #b91c1c; color: #fff; border: 1px solid #b91c1c; }
body.diretorio .btn-danger:hover:not(:disabled) { background: #991b1b; border-color: #991b1b; }

/* Modal da credencial: mesmo tratamento escuro do modal de cadastro, porém estreito. */
body.diretorio .modal-card.modal-cred {
  background: var(--bg-card); color: var(--text-main);
  max-width: 560px; max-height: 92vh; overflow-y: auto;
  border: 1px solid var(--border-color); padding: 1.6rem;
}
body.diretorio .modal-cred .btn-close-modal { color: var(--text-muted); }
body.diretorio .modal-cred .btn-close-modal:hover { background: var(--bg-secondary); color: var(--text-main); }

body.diretorio .cred-person {
  background: rgba(15, 23, 42, 0.55); border: 1px solid var(--border-color);
  border-radius: var(--radius-sm); padding: 10px 14px; margin-bottom: 1rem;
  font-size: 0.8rem; color: var(--text-muted); line-height: 1.5;
}
body.diretorio .cred-person strong { color: var(--text-main); font-size: 0.9rem; }

body.diretorio .cred-danger {
  background: rgba(185, 28, 28, 0.12); border: 1px solid rgba(185, 28, 28, 0.45);
  border-radius: var(--radius-sm); padding: 14px 16px;
}
body.diretorio .cred-danger-title { font-weight: 600; color: #fca5a5; margin-bottom: 8px; }
body.diretorio .cred-danger-body { font-size: 0.84rem; color: var(--text-main); line-height: 1.55; }
body.diretorio .cred-danger-note {
  font-size: 0.74rem; color: var(--text-muted); margin-top: 10px; line-height: 1.45;
}

/* --------------------------------------------------------------------------
   Cadastro de pessoa (modal) — segue o formulário do próprio EasyControl:
   foto e cartão à esquerda, dados à direita, veículos numa seção própria.
   Tudo escopado em body.diretorio: nenhuma outra página tem este modal.
   -------------------------------------------------------------------------- */
body.diretorio .dir-new {
  width: auto; padding: 8px 16px; font-size: 0.8rem; margin-left: 12px; flex-shrink: 0;
}

body.diretorio .modal-card.modal-user {
  background: var(--bg-card); color: var(--text-main);
  max-width: 1000px; max-height: 92vh; overflow-y: auto;
  border: 1px solid var(--border-color); padding: 1.75rem;
}
body.diretorio .modal-user .btn-close-modal { color: var(--text-muted); }
body.diretorio .modal-user .btn-close-modal:hover { background: var(--bg-secondary); color: var(--text-main); }

/* Duas colunas; abaixo de 860px a coluna da foto vira uma faixa no topo. */
body.diretorio .user-grid { display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: 1.5rem; align-items: start; }
body.diretorio .user-aside { border-right: 1px solid var(--border-color); padding-right: 1.5rem; }
body.diretorio .user-main { min-width: 0; }
@media (max-width: 860px) {
  body.diretorio .user-grid { grid-template-columns: minmax(0, 1fr); }
  body.diretorio .user-aside { border-right: none; border-bottom: 1px solid var(--border-color); padding-right: 0; padding-bottom: 1rem; }
}

/* Moldura 3:4 — a mesma proporção em que a foto é salva (600x800). */
body.diretorio .user-photo {
  width: 150px; aspect-ratio: 3 / 4; margin: 0 auto;
  border: 2px dashed var(--border-color); border-radius: var(--radius-md);
  background: var(--bg-secondary); display: flex; align-items: center; justify-content: center;
  font-size: 3rem; color: var(--text-dim); overflow: hidden;
}
body.diretorio .user-photo.has-photo { border-style: solid; border-color: var(--accent-primary); }
body.diretorio .user-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
body.diretorio .user-photo-actions { display: flex; gap: 8px; justify-content: center; margin: 10px 0 6px; }
body.diretorio .btn-photo {
  background: var(--bg-secondary); border: 1px solid var(--border-color); color: var(--text-main);
  border-radius: var(--radius-sm); padding: 7px 12px; font-size: 1rem; cursor: pointer; line-height: 1;
}
body.diretorio .btn-photo:hover { border-color: var(--accent-primary); }
body.diretorio .btn-photo-danger:hover { border-color: var(--accent-danger, #ef4444); color: #fca5a5; }

body.diretorio .field-hint { font-size: 0.72rem; color: var(--text-dim); margin-top: 4px; line-height: 1.35; }
body.diretorio .user-aside .field-hint { margin-bottom: 14px; }
/* "Válido até" fica desligado enquanto "Permanente" está marcado — sem este
   apagamento o campo parece editável e o operador tenta digitar nele. */
body.diretorio .modal-user .form-control:disabled { opacity: 0.45; cursor: not-allowed; }
body.diretorio .field-hint.hint-warn { color: var(--accent-warning, #c98500); }
body.diretorio .field-hint.hint-error { color: #f87171; }
body.diretorio .field-hint.hint-ok { color: #4ade80; }

body.diretorio .check-line {
  display: flex; align-items: center; gap: 8px; font-size: 0.85rem; color: var(--text-muted);
  cursor: pointer; margin-bottom: 1rem;
}
body.diretorio .check-line input { width: 16px; height: 16px; accent-color: var(--accent-primary); cursor: pointer; }
body.diretorio .check-hint { color: var(--text-dim); font-size: 0.78rem; }

/* No modal o mínimo por coluna é menor que o .grid-2 global (280px), senão o
   formulário desmonta em coluna única e a janela fica alta demais. */
body.diretorio .modal-user .grid-2 { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1rem; }
body.diretorio .grid-3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1rem; }
body.diretorio .grid-4 { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1rem; }

/* Grupos de acesso: caixas em forma de chip, para caberem lado a lado. */
body.diretorio .chip-checks { display: flex; flex-wrap: wrap; gap: 8px; }
body.diretorio .chip-check {
  display: inline-flex; align-items: center; gap: 7px; cursor: pointer;
  background: var(--bg-secondary); border: 1px solid var(--border-color);
  border-radius: 20px; padding: 7px 14px; font-size: 0.82rem; color: var(--text-muted);
}
body.diretorio .chip-check input { width: 15px; height: 15px; accent-color: var(--accent-primary); cursor: pointer; }
body.diretorio .chip-check.checked { border-color: var(--accent-primary); color: var(--text-main); }

body.diretorio .form-section { border-top: 1px solid var(--border-color); margin-top: 0.5rem; padding-top: 1rem; }
body.diretorio .form-section-title { font-weight: 700; font-size: 0.95rem; margin-bottom: 0.75rem; }

/* Linha de entrada de veículo: 3 + 3 + botão, encolhendo para 2 e 1 coluna. */
body.diretorio .veh-form { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
body.diretorio .veh-form .btn { width: 100%; padding: 10px 12px; }
@media (max-width: 720px) { body.diretorio .veh-form { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
body.diretorio .veh-list { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; }
body.diretorio .veh-item {
  display: flex; align-items: center; gap: 10px; font-size: 0.82rem;
  background: rgba(15, 23, 42, 0.55); border: 1px solid var(--border-color);
  border-radius: var(--radius-sm); padding: 8px 12px;
}
body.diretorio .veh-item-main { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
body.diretorio .veh-item .plate-mono { color: var(--accent-primary); }

/* Veículos */
.veh-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 1rem; }
@media (max-width: 980px) { .veh-grid { grid-template-columns: 1fr; } }
.plate-mono { font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace; font-weight: 700; letter-spacing: 0.05em; }
.veh-inside-list { display: flex; flex-direction: column; gap: 8px; max-height: 320px; overflow-y: auto; }
.veh-inside-item { display: flex; align-items: center; gap: 10px; background: rgba(15, 23, 42, 0.4); border-radius: var(--radius-sm); padding: 8px 10px; }
.veh-hero { font-size: 2.4rem; font-weight: 700; letter-spacing: -0.02em; }
.btn-icon-del { background: none; border: none; color: var(--text-dim); cursor: pointer; font-size: 0.95rem; padding: 2px 6px; }
.btn-icon-del:hover { color: var(--accent-danger); }
.btn-icon-edit { background: none; border: none; color: var(--text-dim); cursor: pointer; font-size: 0.9rem; padding: 2px 6px; }
.btn-icon-edit:hover { color: var(--accent-primary); }

/* Lista de veículos da ficha do colaborador */
.veh-list { display: flex; flex-direction: column; gap: 6px; margin-top: 0.5rem; }
.veh-item {
  display: flex; align-items: center; gap: 10px;
  background: rgba(15, 23, 42, 0.4);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  padding: 7px 10px;
}
.veh-item .veh-item-main { flex: 1; color: var(--text-muted); font-size: 0.85rem; }
.veh-item-editing { border-color: var(--accent-primary); background: rgba(59, 130, 246, 0.12); }
.btn-ghost {
  background: none;
  border: 1px solid var(--border-color);
  color: var(--text-muted);
}
.btn-ghost:hover { color: var(--text-main); border-color: var(--accent-primary); }
.veh-form-row { display: flex; gap: 10px; flex-wrap: wrap; }
.veh-form-row .form-group { flex: 1; min-width: 140px; margin-bottom: 0.75rem; }
.veh-found-info { font-size: 0.8rem; color: var(--text-muted); margin: -0.25rem 0 0.75rem; min-height: 1.1em; }

/* Dispositivos */
.dev-summary { color: var(--text-muted); font-size: 0.85rem; font-weight: 500; }

/* ==========================================================================
   Painel da portaria — tela única
   Coluna principal (KPIs + liberação + veículos) e uma lateral fixa com o
   movimento das catracas ao vivo. Abaixo de 1200px a lateral desce para o fim.
   ========================================================================== */
.painel {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 400px;
  gap: 1.25rem;
  align-items: start;
  padding-bottom: 0.5rem;
}
.painel-main { min-width: 0; }

/* Os cinco tiles ficam SEMPRE na mesma fileira (pedido de 25/08/2026).
   Com `auto-fit` o quinto — "Veículos no pátio" — descia para uma segunda linha
   assim que a janela apertava, e a fileira de KPIs virava duas. `repeat(5, 1fr)`
   fixo tira essa decisão do navegador; a quebra volta a existir só no empilhamento
   de telas estreitas, lá embaixo nas media queries.
   Em 1366 px a coluna principal tem ~930 px, então cada tile fica com ~173 px —
   daí o aperto de padding e corpo, para o texto não quebrar em três linhas. */
.painel-kpis { margin-bottom: 0.35rem; grid-template-columns: repeat(5, minmax(0, 1fr)); }
.painel-kpis .kpi-tile { padding: 0.8rem 0.9rem; }
.painel-kpis .kpi-value { font-size: 1.75rem; }
.painel-kpis .kpi-split { gap: 1rem; }
/* Carimbo de atualização. Vive na barra superior desde 25/08/2026 (era uma
   linha própria embaixo dos KPIs). `white-space: nowrap` porque "⚠ falha ao
   atualizar — mostrando últimos dados" é bem mais longo que a hora e faria a
   barra inteira crescer de altura no pior momento possível. */
.header-stamp {
  color: var(--text-dim);
  font-size: 0.75rem;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.header-stamp.stamp-warn { color: var(--accent-warning, #f59e0b); font-weight: 600; }
@media (max-width: 900px) { .header-stamp { display: none; } }

.painel-cols {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  gap: 1.25rem;
  align-items: start;
}
/* O respiro entre os cards da coluna era 1,25rem. Com o card de encomendas
   entrando embaixo da liberação de acesso, a coluna 1 passou a medir 420 px num
   espaço de 411 — e como as duas colunas dividem a mesma faixa do grid, os 9 px
   de estouro empurravam o card do estacionamento para baixo da base da lateral.
   0,8rem devolve a folga e realinha as bases. */
.painel-col { min-width: 0; display: flex; flex-direction: column; gap: 0.8rem; }
.painel-col .card, .painel-col .dash-card { margin: 0; max-width: none; }

/* Título de card dentro do painel: 1,2rem com 1,25rem de respiro embaixo é a
   medida das telas largas (Diretório, Visitantes). Aqui a coluna tem ~450 px e
   a altura é disputada — encolhe e cola mais no conteúdo. */
.painel-col .card-title { font-size: 1.08rem; margin-bottom: 0.9rem; }

.kpi-value-inline { font-size: 1.5rem; font-weight: 700; letter-spacing: -0.02em; }

/* Totais do gráfico espelhado de entradas × saídas. Cada número usa a cor da sua
   metade do gráfico, o que dispensa uma legenda separada num card estreito. */
.chart-totals { display: flex; align-items: baseline; gap: 10px; flex-shrink: 0; }
.chart-total { color: var(--text-dim); font-size: 0.72rem; font-weight: 600; white-space: nowrap; }
.chart-total b { font-size: 1.25rem; font-weight: 700; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; margin-right: 3px; }
.chart-total-in b { color: var(--series-2); }
.chart-total-out b { color: var(--viz-out); }
.chart-hint { color: var(--text-dim); font-size: 0.75rem; margin: -0.35rem 0 0.5rem; }

.painel-details { margin-top: 0.9rem; border-top: 1px solid var(--border-color); padding-top: 0.6rem; }
.painel-details > summary { cursor: pointer; font-size: 0.82rem; color: var(--text-muted); }
.painel-details > summary::marker { color: var(--text-dim); }
.painel-details .table-scroll { margin-top: 0.6rem; max-height: 240px; }

/* Lateral ao vivo: acompanha a rolagem e rola por dentro, nunca a página toda.
   Desde 25/08/2026 ela segura DOIS feeds (catraca + estacionamento), então a
   altura de cada um deixou de ser "o que sobrar da tela" e passou a ser contada
   em cards — ver .feed-list logo abaixo. */
.painel-aside { position: sticky; top: 1rem; min-width: 0; display: flex; flex-direction: column; gap: 1rem; }
.painel-aside .feed-card { padding: 1rem; }

/* ALTURA FIXA DE 5 CARDS (pedido da portaria em 25/08/2026).
   Era `calc(100vh - 190px)`: a lista esticava com o monitor e ocupava a lateral
   inteira, o que não deixava espaço para o feed de veículos embaixo. Agora a
   altura sai da conta de cards, então é igual em qualquer tela e o que passa de
   5 vai para a rolagem. `max-height` (e não `height`) para a lista não deixar um
   buraco quando ainda há menos de 5 passagens no dia. */
/* Medidos no Chrome contra a página real, não estimados: o card da catraca tem
   3 linhas (nome, destino, origem+hora) ao lado da foto de 44 px, e a linha do
   veículo tem 3 linhas sem foto. Chutar aqui é o que faz "5 cards" virar 4,5. */
.painel-aside {
  --feed-row: 58px;
  --feed-gap: 12px;
}
.painel-aside .feed-list {
  max-height: calc(5 * var(--feed-row) + 4 * var(--feed-gap));
  gap: var(--feed-gap);
}
.painel-aside .feed-item { gap: 9px; }
.painel-aside .feed-meta,
.painel-aside .feed-dest { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.feed-photo-skeleton {
  width: 44px; height: 44px; border-radius: var(--radius-sm);
  background: var(--bg-secondary); flex-shrink: 0;
}
.live-dot::before {
  content: ''; display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent-success, #22c55e); margin-right: 6px; vertical-align: 1px;
  animation: live-pulse 2s ease-in-out infinite;
}
@keyframes live-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }

/* ==========================================================================
   TELA ÚNICA — o painel ocupa o que sobra da janela, e nem um pixel a mais

   Até aqui a altura vinha do CONTEÚDO e a gente aparava card por card até caber.
   Isso inverte: o `.painel` passa a valer exatamente a janela menos o cabeçalho
   e o respiro do <main>, e quem se ajusta são as listas de dentro. O resultado é
   que "Pedestre ao vivo" cresce até o rodapé e "Estacionamento hoje" termina na
   mesma linha de base — sem número mágico e sem barra de rolagem.

   `--header-h` vem do shared.js (ResizeObserver no <header>), porque a altura da
   barra muda: ela quebra de linha em janela estreita e o carimbo troca a hora
   pela mensagem de falha, que é mais longa.

   ⚠️ `min-height: 0` em cada nível não é enfeite. Item de flex/grid tem
   `min-height: auto`, que se recusa a encolher abaixo do conteúdo — sem isso a
   lista transborda o card em vez de ganhar a própria rolagem, e a página volta
   a rolar exatamente como antes.

   Só vale em tela larga E alta o bastante: abaixo disso o painel volta a crescer
   com o conteúdo, que é o comportamento certo para tablet e janela pequena.
   ========================================================================== */
@media (min-width: 1151px) and (min-height: 620px) {
  .painel {
    height: calc(100vh - var(--header-h, 68px) - 4rem);
    align-items: stretch;
  }

  .painel-main { display: flex; flex-direction: column; min-height: 0; }
  .painel-cols { flex: 1; min-height: 0; align-items: stretch; }

  /* A coluna da busca fica na altura natural: esticar o card de liberação só
     lhe daria um fundo vazio. Quem acompanha a lateral é a coluna do pátio.

     ⚠️ `max-height: 100%` não é enfeite — é a trava que mantém as duas bases
     alinhadas. As colunas dividem a MESMA faixa do grid: se a coluna 1 crescer
     além do espaço disponível, ela estica a faixa e leva o card do
     estacionamento junto, para baixo da base da lateral. Foi o que aconteceu
     quando o card de encomendas entrou aqui embaixo da liberação de acesso.
     Com o teto, conteúdo demais rola dentro da própria coluna e a faixa não se
     mexe — o alinhamento para de depender de quanto card cabe. */
  .painel-col:first-child { align-self: start; max-height: 100%; overflow-y: auto; }

  .painel-col:last-child { min-height: 0; }
  .painel-col:last-child .dash-card {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }
  /* A lista de veículos come a sobra do card e rola por dentro. */
  .painel-col:last-child .veic-list { flex: 1; min-height: 0; max-height: none; }

  .painel-aside { height: 100%; min-height: 0; }
  .painel-aside .feed-card {
    height: 100%;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }
  /* Some com o teto de 5 cards: aqui a conta é a janela, não a contagem. */
  .painel-aside .feed-list { flex: 1; min-height: 0; max-height: none; }
}

/* 1366x768 é o monitor típico da portaria: as duas colunas + lateral precisam
   sobreviver nessa largura, senão a "tela única" vira uma página rolável. */
@media (max-width: 1500px) {
  .painel { grid-template-columns: minmax(0, 1fr) 352px; gap: 1rem; }
  .painel-cols { gap: 1rem; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); }
  .painel-col { gap: 0.8rem; }
  .kpi-value { font-size: 1.7rem; }
  .painel-aside .feed-card { padding: 0.85rem; }
}

@media (max-width: 1150px) {
  .painel { grid-template-columns: minmax(0, 1fr); }
  .painel-aside { position: static; }
  .painel-aside .feed-list { max-height: 420px; }
}
@media (max-width: 820px) {
  .painel-cols { grid-template-columns: minmax(0, 1fr); }
}

/* Os 5 KPIs só quebram quando 5 colunas realmente não cabem mais: a 152 px cada
   o limite é ~830 px de coluna principal. Daí para baixo é tablet/celular, onde
   uma fileira só nunca foi o objetivo. */
@media (max-width: 880px) {
  .painel-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .painel-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media print {
  /* Só o crachá vai para o papel. `visibility: hidden` (regra global) esconde o
     resto mas mantém o espaço ocupado — numa tela longa como o painel da portaria
     isso gerava várias páginas em branco antes do crachá. Aqui o conteúdo sai do
     fluxo de vez. O crachá vive fora do <main>, tanto aqui quanto no index.html. */
  /* ⚠️ body:not(.dashboard): o relatório do dashboard também vai para o papel
     e precisa do <main>. Ver a nota no primeiro bloco @media print. */
  body:not(.dashboard) header, body:not(.dashboard) main { display: none !important; }
  body { background: #fff !important; }
  /* O crachá é posicionado em 0,0 pela regra global; sem isto o max-height/overflow
     do modal o recortaria. */
  /* !important porque a regra normal de mesma especificidade vem depois no arquivo
     — sem isso o max-height/overflow continuaria valendo e cortaria o crachá. */
  .modal-card.modal-release {
    max-height: none !important; overflow: visible !important;
    background: none !important; border: none !important; padding: 0 !important;
  }
}

/* ==========================================================================
   Modal de liberação de acesso (portaria) — mesmo fluxo do totem em janela.
   O cartão do modal segue a superfície escura do sistema (os campos de
   formulário são estilizados para ela); só o crachá continua claro, porque é
   o que vai para a impressora.
   ========================================================================== */
.modal-card.modal-release {
  background: var(--bg-card);
  color: var(--text-main);
  max-width: 620px;
  max-height: 92vh;
  overflow-y: auto;
  border: 1px solid var(--border-color);
  padding: 1.75rem;
}
.modal-release .btn-close-modal { color: var(--text-muted); }
.modal-release .btn-close-modal:hover { background: var(--bg-secondary); color: var(--text-main); }
.modal-release .card-title { margin-bottom: 1.1rem; }
/* O .grid-2 global pede 280px por coluna e não caberia em duas colunas dentro do
   modal (564px úteis) — aqui o mínimo é menor para o formulário não virar uma
   coluna só, o que deixaria a janela alta demais. */
.modal-release .grid-2 { grid-template-columns: repeat(auto-fit, minmax(228px, 1fr)); gap: 1rem; }

/* Cabeçalho do passo "cadastro encontrado" */
.rel-person { display: flex; gap: 1rem; align-items: center; margin-bottom: 1.1rem; }
.rel-person img {
  width: 84px; height: 84px; flex-shrink: 0;
  border-radius: var(--radius-md); object-fit: cover; background: var(--bg-secondary);
}
.rel-name { font-size: 1.15rem; font-weight: 700; line-height: 1.25; }
.rel-doc { color: var(--text-muted); font-size: 0.9rem; }
.rel-note { color: var(--accent-warning, #c98500); font-size: 0.82rem; margin-top: 4px; }

.rel-actions { display: flex; gap: 12px; margin-top: 1.25rem; }
.rel-actions .btn { flex: 1; }
.rel-actions .btn-success, .rel-actions .btn-primary { flex: 2; }
/* O +1 é um desvio do fluxo, não uma alternativa de mesmo peso à confirmação:
   ocupa o que o texto precisa e devolve a largura para o botão que conclui. */
.rel-actions .btn-plus1 { flex: 0 0 auto; }

/* A câmera da portaria virou o mesmo modal em tela cheia do totem (.cam-modal),
   então o #camBox embutido saiu daqui junto com o markup.
   ⚠️ A regra `#camVideo, #camCanvas { max-width: 300px; display: none }` que
   existia neste ponto era do box antigo, mas por ser seletor de ID vencia
   `.cam-frame video` e ESTRANGULAVA o vídeo do totem em 300 px dentro de uma
   moldura de 736 px no tablet — o rosto nunca casava com a silhueta. Removida:
   agora vale só `.cam-frame video/canvas` (100% da moldura, object-fit: cover),
   para o totem e para a portaria. O canvas continua começando escondido pelo
   `style="display:none"` inline nos dois HTMLs. */

/* Escolha da foto no formulário: miniatura + botão que abre o modal da câmera. */
/* SEM FACIAL (LGPD) — só no cadastro por passaporte. Fica ACIMA das fontes de
   foto, não ao lado: é uma decisão sobre o cadastro inteiro, não uma terceira
   maneira de tirar retrato. Ligado, ganha borda âmbar porque muda o que a pessoa
   vai receber na mão (o crachá vira obrigatório). */
.sem-facial {
  display: flex; align-items: flex-start; gap: 9px; cursor: pointer;
  padding: 8px 11px; margin-bottom: 10px;
  border: 1px solid var(--border-color); border-radius: var(--radius-sm);
  background: var(--bg-secondary); transition: border-color .15s, background .15s;
}
.sem-facial:hover { border-color: var(--accent-warning); }
.sem-facial.is-on { border-color: var(--accent-warning); background: rgba(251, 191, 36, 0.1); }
.sem-facial input { margin-top: 2px; flex-shrink: 0; accent-color: var(--accent-warning); }
.sem-facial-txt { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.sem-facial-rot { font-size: 0.84rem; font-weight: 600; }
.sem-facial.is-on .sem-facial-rot { color: var(--accent-warning); }
.sem-facial-sub { font-size: 0.72rem; color: var(--text-dim); line-height: 1.35; }

/* A imagem do QR vem pronta do EasyControl (data-URI PNG) no cadastro sem
   facial; no fluxo normal quem preenche a caixa é o qrcode.min.js, com <canvas>. */
.qrcode-box img { display: block; width: 200px; height: 200px; image-rendering: pixelated; }

.photo-picker { display: flex; align-items: center; gap: 12px; }
.photo-picker .btn { width: auto; padding: 9px 16px; white-space: nowrap; }
.photo-thumb {
  width: 54px; height: 72px; flex-shrink: 0;
  border-radius: var(--radius-sm); border: 1px solid var(--border-color);
  background: var(--bg-secondary); overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.5rem; color: var(--text-dim);
}
.photo-thumb.has-photo { border-color: var(--accent-primary); }
.photo-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Passo final */
.rel-success-head { text-align: center; }
.rel-success-emoji { font-size: 2.6rem; line-height: 1; }
.rel-success-title { font-size: 1.25rem; font-weight: 700; margin-top: 0.25rem; }
.rel-success-sub { color: var(--text-muted); font-size: 0.9rem; margin-top: 2px; }
.modal-release #syncStatusBox {
  padding: 0.7rem; border-radius: var(--radius-sm);
  background: var(--bg-secondary); font-size: 0.85rem; color: var(--text-muted);
  text-align: center; min-height: 1em;
}
.rel-success-validity { color: var(--text-dim); font-size: 0.82rem; margin-top: 4px; margin-bottom: 1.1rem; }
.rel-countdown { color: var(--text-dim); font-size: 0.8rem; text-align: center; margin-top: 0.9rem; }

/* ==========================================================================
   Totem — tela de descanso / abertura (paisagem)

   Sobreposição clara, com a paleta azul da marca (amostrada da própria logo:
   #002050 / #0060F0 / #00A0F0). Vive fora do tema escuro do restante do sistema,
   por isso todas as cores são declaradas aqui dentro.

   Tudo é dimensionado em `em` sobre um `font-size` em vw: a tela inteira escala
   junto com a largura do totem, sem rolagem, seja 1280×800 ou 1920×1080.
   ========================================================================== */
.idle {
  --nv: #0b2350;          /* azul-marinho da marca */
  --bl: #0a5ff0;          /* azul vivo */
  --cy: #00a0f0;          /* azul claro */
  --ink: #0b2350;
  --muted: #5b6b8a;
  --surface: #ffffff;

  position: fixed;
  inset: 0;
  z-index: 900;
  display: grid;
  grid-template-columns: 37% 1fr;
  gap: 2.2em;
  align-items: stretch;
  padding: 2.2em 2.6em;
  background:
    radial-gradient(120% 90% at 8% 0%, #e8efff 0%, rgba(232, 239, 255, 0) 60%),
    radial-gradient(90% 80% at 100% 100%, #e6f4ff 0%, rgba(230, 244, 255, 0) 55%),
    #f4f7fd;
  color: var(--ink);
  font-size: clamp(11px, min(1.6vw, 2.5vh), 27px);
  line-height: 1.35;
  cursor: pointer;
  overflow: hidden;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

/* Coluna da marca ------------------------------------------------------- */
.idle-left { display: flex; flex-direction: column; align-items: flex-start; justify-content: center; min-width: 0; height: 100%; }
.idle-brand { display: flex; align-items: center; gap: 0.7em; margin-bottom: 1.5em; }
.idle-mark { width: 3.4em; height: auto; flex-shrink: 0; }
.idle-brand-name {
  font-size: 2.1em; font-weight: 800; letter-spacing: -0.02em; line-height: 1;
  background: linear-gradient(92deg, var(--nv), var(--bl) 60%, var(--cy));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.idle-brand-sub {
  font-size: 0.7em; font-weight: 700; letter-spacing: 0.09em;
  color: var(--muted); margin-top: 0.35em;
}
.idle-headline {
  font-size: 2.25em; font-weight: 700; line-height: 1.1; letter-spacing: -0.02em; margin: 0;
}
.idle-headline strong {
  display: block; font-weight: 800; font-size: 1.2em; white-space: nowrap;
  background: linear-gradient(92deg, var(--nv), var(--bl) 55%, var(--cy));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.idle-rule { width: 3.4em; height: 0.22em; border-radius: 1em; background: var(--bl); margin: 0.8em 0 0.9em; }
.idle-sub { font-size: 1.05em; color: var(--muted); margin: 0; font-weight: 500; }
.idle-art { width: 10em; height: auto; color: var(--nv); margin-top: 1.8em; opacity: 0.92; }

/* Coluna dos passos ----------------------------------------------------- */
.idle-right { display: flex; flex-direction: column; justify-content: center; gap: 1.5em; min-width: 0; height: 100%; }

.idle-steps { display: flex; align-items: stretch; gap: 0.7em; }
.idle-step {
  position: relative; flex: 1; min-width: 0;
  background: var(--surface); border-radius: 1.1em;
  padding: 1.5em 1em 1.2em; text-align: center;
  box-shadow: 0 0.5em 1.6em rgba(11, 35, 80, 0.09);
}
.idle-num {
  position: absolute; top: -0.85em; left: 50%; transform: translateX(-50%);
  width: 1.9em; height: 1.9em; border-radius: 50%;
  background: linear-gradient(140deg, var(--nv), var(--bl));
  color: #fff; font-weight: 800; font-size: 0.95em;
  display: flex; align-items: center; justify-content: center;
}
.idle-step > svg { width: 3.1em; height: 3.1em; color: var(--bl); display: block; margin: 0.2em auto 0.7em; }
.idle-step-title { font-weight: 700; font-size: 1.05em; color: var(--nv); }
.idle-step-text { font-size: 0.85em; color: var(--muted); margin-top: 0.25em; }
.idle-arrow { align-self: center; color: var(--bl); font-size: 1.9em; font-weight: 700; opacity: 0.55; }

/* Chamada para ação ----------------------------------------------------- */
.idle-cta {
  display: flex; align-items: center; gap: 1.1em;
  background: linear-gradient(100deg, #071a3d, var(--nv) 42%, var(--bl));
  color: #fff; border-radius: 1.1em; padding: 1.1em 1.6em;
  box-shadow: 0 0.9em 2em rgba(10, 95, 240, 0.28);
}
.idle-cta-icon {
  flex-shrink: 0; width: 3.4em; height: 3.4em; border-radius: 50%;
  background: rgba(255, 255, 255, 0.14);
  display: flex; align-items: center; justify-content: center;
  animation: idle-pulse 2.4s ease-in-out infinite;
}
.idle-cta-icon svg { width: 2em; height: 2em; color: #fff; }
.idle-cta-title { font-size: 1.5em; font-weight: 700; letter-spacing: -0.01em; }
.idle-cta-sub { font-size: 0.95em; opacity: 0.8; }
@keyframes idle-pulse {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.35); }
  70% { transform: scale(1.06); box-shadow: 0 0 0 0.9em rgba(255, 255, 255, 0); }
}

/* Selo de segurança ----------------------------------------------------- */
.idle-safe {
  display: flex; align-items: center; gap: 1em;
  background: var(--surface); border-radius: 1.1em; padding: 0.9em 1.3em;
  box-shadow: 0 0.5em 1.6em rgba(11, 35, 80, 0.07);
}
.idle-safe-icon { flex-shrink: 0; width: 2.6em; height: 2.6em; color: var(--bl); }
.idle-safe-icon svg { width: 100%; height: 100%; }
.idle-safe-text { flex: 1; min-width: 0; font-size: 0.88em; color: var(--muted); }
.idle-safe-text strong { display: block; font-size: 1.12em; color: var(--nv); }
.idle-safe-art { width: 7.5em; height: auto; color: var(--cy); flex-shrink: 0; opacity: 0.75; }

/* Contatos -------------------------------------------------------------- */
.idle-contacts { display: flex; gap: 2.4em; justify-content: center; }
.idle-contact { display: flex; align-items: center; gap: 0.7em; }
.idle-contact svg { width: 2.2em; height: 2.2em; color: var(--bl); flex-shrink: 0; }
.idle-contact-wa svg { color: #25d366; }
.idle-contact span { display: block; font-size: 0.85em; color: var(--muted); }
.idle-contact b { font-size: 1.25em; color: var(--nv); letter-spacing: -0.01em; }

/* Telas altas (tablet em retrato): vira uma coluna só, sem perder nada. */
@media (max-aspect-ratio: 1/1) {
  .idle { grid-template-columns: 1fr; align-content: center; gap: 1.4em; padding: 2em 1.6em; font-size: clamp(11px, 2.1vw, 20px); }
  .idle-left { align-items: center; text-align: center; }
  .idle-art { display: none; }
  .idle-safe-art { display: none; }
}

/* ==========================================================================
   Página Portaria — Textos brancos e alto contraste dentro de todos os cards
   ========================================================================== */
body.portaria {
  --text-muted: #e2e8f0;
  --text-dim: #cbd5e1;
}

body.portaria .card,
body.portaria .dash-card,
body.portaria .kpi-tile,
body.portaria .auth-container,
body.portaria .feed-card,
body.portaria .painel-aside {
  color: #ffffff;
}

/* Títulos e cabeçalhos */
body.portaria .card .card-title,
body.portaria .dash-card .dash-card-title,
body.portaria .auth-header h2,
body.portaria .auth-header p {
  color: #ffffff !important;
}

/* Indicadores / KPIs */
body.portaria .kpi-tile .kpi-label,
body.portaria .kpi-tile .kpi-value,
body.portaria .kpi-tile .kpi-context,
body.portaria .kpi-tile .kpi-split-value,
body.portaria .kpi-tile .kpi-split-label {
  color: #ffffff !important;
}

body.portaria .kpi-tile .kpi-context {
  opacity: 0.9;
}

/* Formulários e labels */
body.portaria .card label,
body.portaria .card .form-group label,
body.portaria .auth-container label,
body.portaria .auth-container .form-group label {
  color: #ffffff !important;
  font-weight: 600;
}

body.portaria .card .form-control::placeholder,
body.portaria .auth-container .form-control::placeholder {
  color: #94a3b8;
}

/* Card do Gráfico de Visitantes */
body.portaria .dash-card .chart-hint {
  color: #ffffff !important;
  opacity: 0.88;
}

body.portaria .dash-card .chart-totals,
body.portaria .dash-card .chart-total,
body.portaria .dash-card .chart-empty {
  color: #ffffff !important;
}

body.portaria #chartUnique svg text {
  fill: #ffffff !important;
  font-weight: 500;
}

body.portaria #chartUnique svg line {
  stroke: rgba(255, 255, 255, 0.2) !important;
}

/* Feed da Catraca ao Vivo */
body.portaria .feed-card .dev-summary {
  color: #ffffff !important;
  opacity: 0.9;
}

body.portaria .feed-card .feed-name {
  color: #ffffff !important;
  font-weight: 700;
}

body.portaria .feed-card .feed-dest {
  color: #ffffff !important;
}

body.portaria .feed-card .feed-dest strong {
  color: #60a5fa !important; /* Destaque da sala em azul claro vibrante */
  font-weight: 700;
}

body.portaria .feed-card .feed-meta {
  color: #cbd5e1 !important; /* Cinza bem claro / esbranquiçado de alta legibilidade */
}

/* Estacionamento ao vivo — mesmo tratamento de contraste do feed da catraca */
body.portaria .veic-placa { color: #ffffff !important; font-weight: 700; }
body.portaria .veic-dono  { color: #ffffff !important; }
body.portaria .veic-meta  { color: #cbd5e1 !important; }
body.portaria .estac-num-label { color: #e2e8f0 !important; }

/* O gráfico de fluxo desenha os rótulos com var(--text-dim); em body.portaria
   isso já é #cbd5e1, mas o eixo zero precisa aparecer mais que a grade. */
body.portaria #chartFlow svg text { fill: #ffffff !important; font-weight: 500; }

/* Lista de resultados da busca */
body.portaria .name-results-title,
body.portaria .name-result-name,
body.portaria .name-result-doc,
body.portaria .name-result-empty {
  color: #ffffff !important;
}

/* Carimbo de atualização abaixo dos KPIs (fica sobre o fundo claro da página) */
body.portaria .painel-stamp {
  color: #334155 !important; /* Tom escuro para excelente contraste com o fundo claro */
  font-weight: 600;
}

body.portaria .painel-stamp.stamp-warn {
  color: #b45309 !important;
  font-weight: 700;
}

/* ==========================================================================
   Diretório e Gestão de Visitantes — Estilos de Toolbar e Tabelas
   ========================================================================== */
body.diretorio .card,
body.visitantes .card {
  color: #ffffff;
}

body.diretorio .card label:not(.doctors-toolbar label):not(.doctors-filter-item label),
body.visitantes .card label:not(.doctors-toolbar label):not(.doctors-filter-item label) {
  color: #ffffff !important;
}

body.diretorio .doctors-toolbar label,
body.visitantes .doctors-toolbar label,
body.diretorio .doctors-filter-item label,
body.visitantes .doctors-filter-item label {
  color: #0f172a !important;
}

.dir-main-card,
.vis-main-card {
  max-width: 1200px;
  margin: 1.5rem auto;
}

/* Botões de Ação na Tabela */
.btn-table-action {
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid var(--border-color);
  color: #ffffff;
  padding: 4px 8px;
  border-radius: var(--radius-sm);
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.15s ease;
  margin-left: 4px;
}

.btn-table-action:hover {
  background: var(--accent-primary);
  border-color: var(--accent-primary);
  color: #ffffff;
  transform: translateY(-1px);
}

.btn-table-action.btn-del-emp:hover {
  background: var(--accent-danger);
  border-color: var(--accent-danger);
}

/* Tabela de Colaboradores e Visitantes */
.dir-table th,
.vis-table th {
  background: #f8fafc;
  color: #334155;
  font-weight: 700;
}

.dir-table td,
.vis-table td {
  color: #1e293b;
  font-size: 0.88rem;
}

.dir-table tbody tr:hover td,
.vis-table tbody tr:hover td {
  background: #e2e8f0;
}

.nav-manager-link {
  border: 1px dashed rgba(59, 130, 246, 0.5);
  border-radius: var(--radius-sm);
}

/* ==========================================================================
   Ficha Simplificada de Consulta Rápida (Operador)
   ========================================================================== */
.modal-quick-view {
  max-width: 500px;
  width: 92%;
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 1.5rem;
  box-shadow: var(--shadow-lg);
}

.quick-view-card {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.quick-view-header {
  display: flex;
  align-items: center;
  gap: 1rem;
  background: rgba(15, 23, 42, 0.6);
  padding: 1rem;
  border-radius: var(--radius-md);
  border: 1px solid var(--border-color);
}

.quick-view-photo {
  width: 76px;
  height: 96px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.08);
  border: 2px solid rgba(255, 255, 255, 0.15);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2rem;
  flex-shrink: 0;
  overflow: hidden;
}

.quick-view-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.quick-view-info {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.quick-view-name {
  font-size: 1.15rem;
  font-weight: 700;
  color: #ffffff;
  white-space: normal;
  word-break: break-word;
}

.quick-view-company {
  font-size: 0.92rem;
  color: #93c5fd;
  font-weight: 600;
}

.quick-view-room {
  font-size: 0.85rem;
  color: #cbd5e1;
}

.quick-view-details {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.quick-detail-item {
  background: rgba(15, 23, 42, 0.4);
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(255, 255, 255, 0.06);
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.quick-detail-label {
  font-size: 0.72rem;
  font-weight: 700;
  color: #94a3b8;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.quick-detail-value {
  font-size: 0.88rem;
  color: #ffffff;
  font-weight: 600;
  word-break: break-word;
}

.quick-view-hint {
  font-size: 0.75rem;
  color: #94a3b8;
  text-align: center;
}

.quick-view-footer {
  margin-top: 0.5rem;
}





/* ==========================================================================
   Medidor de latência do EasyControl (cabeçalho da portaria)
   Discreto de propósito: só existe para o porteiro saber, quando a tela demora,
   se o problema é o servidor ou a máquina dele. Verde/âmbar/vermelho pela faixa
   de resposta; cinza quando não deu para medir.
   ========================================================================== */
.latency {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 0.72rem;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  padding: 2px 8px;
  border: 1px solid var(--border-color);
  border-radius: 10px;
  cursor: default;
  white-space: nowrap;
}
.latency-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--text-dim);
  flex-shrink: 0;
}
.latency.is-good  .latency-dot { background: var(--accent-success); }
.latency.is-slow  .latency-dot { background: var(--accent-warning); }
.latency.is-bad   .latency-dot { background: var(--accent-danger); }
.latency.is-down  .latency-dot { background: var(--accent-danger); }
.latency.is-good  { color: var(--text-muted); }
.latency.is-slow  { color: var(--accent-warning); border-color: rgba(245, 158, 11, 0.35); }
.latency.is-bad,
.latency.is-down  { color: var(--accent-danger); border-color: rgba(239, 68, 68, 0.35); }

/* ==========================================================================
   Totem 2 — a escolha do atendimento
   --------------------------------------------------------------------------
   Esta tela aparece no instante seguinte ao toque na tela de descanso, então
   herda o mundo DELA e não o dos cartões escuros do formulário: superfície
   branca, tinta #0b2350, azul #0a5ff0, sombra azulada baixa. É a mesma paleta
   declarada em .idle, repetida aqui porque aquelas variáveis vivem no escopo
   daquele bloco.

   O público inclui idosos, e isso governa as medidas:
     · o CARTÃO INTEIRO é o alvo — mais de 500x400 px, contra os 44x44 da WCAG;
     · rótulo em ~2,1rem e apoio em ~1,3rem, bem acima do corpo comum;
     · tinta escura sobre branco, que é a combinação de maior contraste possível
       e a que menos sofre com perda de sensibilidade — o inverso do cartão
       escuro, onde o texto de apoio empacava em 4,9:1;
     · folga larga entre os dois, para o toque impreciso não pegar o vizinho;
     · o toque muda fundo E borda ao mesmo tempo, porque realce sutil não é
       percebido por quem enxerga pouco.

   Tudo escopado em body.totem2 — o totem 1 divide este arquivo e não muda.
   ========================================================================== */
body.totem2 .choice-stage {
  --nv: #0b2350;
  --bl: #0a5ff0;
  --ink: #0b2350;
  --muted: #5b6b8a;

  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  width: min(1180px, 94vw);
  margin: 0 auto;
  padding: 1.75rem 0 1.5rem;
}

body.totem2 .choice-headline {
  font-size: clamp(2.1rem, 4.6vw, 3.3rem);
  font-weight: 800;
  line-height: 1.08;
  letter-spacing: -0.03em;
  margin: 0 0 2rem;
  color: var(--ink);          /* 14:1 sobre o fundo claro da página */
}
body.totem2 .choice-headline strong {
  font-weight: 800;
  /* Uma parada mais escura que o --bl do idle: sobre o fundo da página o azul
     vivo dá 4,4:1, que passa como texto grande mas é justo demais para quem
     enxerga pouco. Este dá 5,6:1 e ainda lê como o mesmo azul. */
  color: #0a4fd0;
}

body.totem2 .choice-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2rem;
  width: 100%;
}

body.totem2 .choice-card {
  --tint: var(--bl);          /* ícone e acentos */
  --tint-ink: #0a4fd0;        /* variante que aguenta ser texto sobre branco */

  position: relative;
  display: grid;
  grid-template-rows: auto auto auto;
  align-content: center;
  justify-items: center;
  gap: 1.35rem;

  min-height: 360px;
  padding: 2.75rem 1.75rem;

  cursor: pointer;
  text-align: center;
  font-family: inherit;
  color: var(--ink);
  background: #ffffff;
  border: 2px solid transparent;
  border-radius: 1.4rem;
  box-shadow: 0 0.6em 1.8em rgba(11, 35, 80, 0.11);

  transition: transform 180ms cubic-bezier(0.16, 1, 0.3, 1),
              border-color 180ms ease, box-shadow 180ms ease, background 120ms ease;
}
body.totem2 .choice-card.is-parking {
  --tint: #f59e0b;
  --tint-ink: #b45309;        /* âmbar escuro: 4,9:1 sobre branco */
}

body.totem2 .choice-card:hover,
body.totem2 .choice-card:focus-visible {
  border-color: var(--tint);
  box-shadow: 0 1em 2.4em rgba(11, 35, 80, 0.17);
  transform: translateY(-4px);
  outline: none;
}
/* Toque: fundo tingido + borda cheia, para não passar despercebido. */
body.totem2 .choice-card:active {
  transform: scale(0.975);
  border-color: var(--tint-ink);
  background: color-mix(in srgb, var(--tint) 12%, #ffffff);
  box-shadow: 0 0.3em 1em rgba(11, 35, 80, 0.14);
}

body.totem2 .choice-art {
  display: grid;
  place-items: center;
  width: 152px;
  height: 152px;
  border-radius: 50%;
  color: var(--tint);
  background: color-mix(in srgb, var(--tint) 12%, #ffffff);
  flex-shrink: 0;
}
body.totem2 .choice-art svg { width: 92px; height: 92px; }

body.totem2 .choice-title {
  font-size: clamp(1.6rem, 3vw, 2.1rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: var(--ink);
  /* Duas linhas reservadas: sem isso o cartão de título curto sobe o ícone e os
     dois deixam de alinhar lado a lado. */
  min-height: 2.3em;
  display: flex;
  align-items: center;
}
body.totem2 .choice-text {
  font-size: clamp(1.1rem, 1.7vw, 1.3rem);
  line-height: 1.4;
  font-weight: 500;
  color: var(--muted);        /* 5,6:1 sobre branco */
}

body.totem2 .choice-help {
  margin: 2rem 0 0;
  font-size: 1.15rem;
  font-weight: 600;
  color: #475569;             /* 7,4:1 sobre o fundo da página */
}

/* Entrada: um único momento autoral, os dois cartões subindo escalonados. */
@keyframes choice-rise {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: translateY(0); }
}
body.totem2 .choice-card { animation: choice-rise 480ms cubic-bezier(0.16, 1, 0.3, 1) backwards; }
body.totem2 .choice-card.is-company { animation-delay: 60ms; }
body.totem2 .choice-card.is-parking { animation-delay: 150ms; }

@media (prefers-reduced-motion: reduce) {
  body.totem2 .choice-card { animation: none; }
  body.totem2 .choice-card:hover, body.totem2 .choice-card:focus-visible { transform: none; }
}

/* Retrato ou tela baixa: um cartão sobre o outro, ainda grandes, sem rolagem. */
@media (max-width: 780px), (orientation: portrait) {
  body.totem2 .choice-grid { grid-template-columns: 1fr; gap: 1.25rem; }
  body.totem2 .choice-card { min-height: 0; padding: 1.75rem 1.5rem; gap: 1.1rem; }
  body.totem2 .choice-art { width: 116px; height: 116px; }
  body.totem2 .choice-art svg { width: 70px; height: 70px; }
  body.totem2 .choice-title { min-height: 0; }
  body.totem2 .choice-headline { margin-bottom: 1.5rem; }
  body.totem2 .choice-help { margin-top: 1.25rem; }
}
@media (max-height: 640px) {
  body.totem2 .choice-card { min-height: 0; padding: 1.5rem; gap: 0.9rem; }
  body.totem2 .choice-art { width: 104px; height: 104px; }
  body.totem2 .choice-art svg { width: 62px; height: 62px; }
  body.totem2 .choice-title { min-height: 0; }
}

/* Chrome < 111 não tem color-mix: cai para valores sólidos equivalentes. */
@supports not (color: color-mix(in srgb, red 50%, blue)) {
  body.totem2 .choice-art { background: #e7effe; }
  body.totem2 .is-parking .choice-art { background: #fdf1dc; }
  body.totem2 .choice-card:active { background: #e7effe; }
  body.totem2 .is-parking.choice-card:active { background: #fdf1dc; }
}

.choice-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  align-self: center;
  margin: 0 auto 0.75rem;
  padding: 4px 12px;
  border-radius: 12px;
  font-size: 0.85rem;
  font-weight: 600;
  background: rgba(59, 130, 246, 0.15);
  border: 1px solid rgba(59, 130, 246, 0.35);
  color: var(--accent-primary);
}

/* --------------------------------------------------------------------------
   Totem 2 — o fluxo (CPF, nome, destino) fica IDÊNTICO ao do totem 1.
   Só a tela de escolha, acima, tem escala própria: ela é a decisão inicial e
   aparece logo depois do descanso, onde o alvo grande resolve. Daqui para a
   frente as duas máquinas são a mesma tela, e assim continuam.

   A única exceção é de COR, não de tamanho: o label herda --text-muted, que
   sobre o cartão translúcido do totem cai para 2,4:1 — ilegível para quem
   enxerga pouco. A correção não muda medida nenhuma.
   -------------------------------------------------------------------------- */
body.totem2 .form-group label { color: #f1f5f9; }
body.totem2 .form-control::placeholder { color: #a9b6c9; opacity: 1; }

/* ==========================================================================
   PEDIDOS DE LIBERAÇÃO — fila do totem 2 no canto da portaria (pedidos.js)

   Cards empilhados no canto inferior direito, POR CIMA da tela de trabalho: o
   porteiro está atendendo outra pessoa quando o pedido chega e não pode ter de
   procurar por ele. Ficam abaixo dos modais (z-index 1000+) de propósito — com o
   modal de liberação aberto, quem manda é o que está sendo preenchido ali.

   `column-reverse` é o que faz a FILA: o mais antigo (o primeiro da fila) fica
   embaixo, colado no canto, e cada novo pedido se empilha acima dele.
   ========================================================================== */
.pedidos-dock {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 950;
  display: flex;
  flex-direction: column-reverse;
  align-items: flex-end;
  gap: 10px;
  max-height: calc(100vh - 36px);
  /* Fila alta numa janela baixa: rola dentro do dock (o `column-reverse` já deixa a
     rolagem parada no mais antigo) em vez de os cards de cima saírem da tela. */
  overflow-y: auto;
  overflow-x: hidden;
  padding: 2px;
  pointer-events: none;      /* o dock não bloqueia a tela; só os cards clicam */
}

.pedidos-dock > * { pointer-events: auto; }

.pedido-card {
  width: 340px;
  max-width: calc(100vw - 36px);
  background: rgba(15, 23, 42, 0.94);
  border: 1px solid var(--border-color);
  border-left: 4px solid var(--accent-primary);
  border-radius: var(--radius-md);
  box-shadow: 0 18px 40px -12px rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(10px);
  padding: 0.85rem 0.9rem;
  color: #fff;
  animation: pedidoEntra 0.28s cubic-bezier(0.2, 0.8, 0.3, 1);
  transition: opacity 0.2s ease, transform 0.2s ease, border-color 0.2s ease;
}

@keyframes pedidoEntra {
  from { opacity: 0; transform: translateX(28px) scale(0.97); }
  to   { opacity: 1; transform: none; }
}

.pedido-card.is-leaving { opacity: 0; transform: translateX(28px); }
.pedido-card.is-decidindo { opacity: 0.75; }
.pedido-card.is-aprovado { border-left-color: var(--accent-success); box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.45); }
.pedido-card.is-recusado { border-left-color: var(--accent-danger); box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.45); }

/* Mais de um minuto com alguém parado no totem esperando: o card esquenta. */
.pedido-card.is-atrasado { border-left-color: var(--accent-warning); }
.pedido-card.is-atrasado .pedido-espera { color: var(--accent-warning); }

.pedido-topo {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 0.6rem;
}

.pedido-flag {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: 3px 8px;
  border-radius: 999px;
  white-space: nowrap;
}
.pedido-flag.is-new     { background: rgba(59, 130, 246, 0.2);  color: #93c5fd; }
.pedido-flag.is-found   { background: rgba(20, 184, 166, 0.2);  color: #5eead4; }
.pedido-flag.is-qrtotem { background: rgba(217, 119, 6, 0.22);  color: #fcd34d; }

.pedido-espera { font-size: 0.72rem; color: #cbd5e1; white-space: nowrap; }
.pedido-espera b { font-variant-numeric: tabular-nums; }

.pedido-corpo { display: flex; gap: 0.7rem; align-items: flex-start; }

.pedido-foto {
  width: 66px;
  height: 88px;
  flex: 0 0 auto;
  object-fit: cover;
  border-radius: var(--radius-sm);
  background: #1e293b;
  border: 1px solid var(--border-color);
}

.pedido-foto-vazia {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.8rem;
  color: #64748b;
}

.pedido-dados { min-width: 0; }
.pedido-nome {
  font-size: 0.98rem;
  font-weight: 700;
  line-height: 1.25;
  margin: 0 0 2px;
  /* Nome longo não pode esticar o card nem empurrar os botões para fora. */
  overflow-wrap: anywhere;
}
.pedido-cpf { font-size: 0.78rem; color: #cbd5e1; margin: 0 0 4px; font-variant-numeric: tabular-nums; }
.pedido-destino { font-size: 0.82rem; color: #e2e8f0; margin: 0; overflow-wrap: anywhere; }

.pedido-acoes { display: flex; gap: 8px; margin-top: 0.75rem; }
/* `display: flex` na classe vence o [hidden] do navegador — sem isto a linha
   "Recusar/Liberar" continuava na tela por baixo da confirmação da recusa. */
.pedido-acoes[hidden] { display: none; }
.pedido-btn { flex: 1; padding: 0.6rem 0.5rem; font-size: 0.9rem; font-weight: 700; }

/* A recusa só existe dentro do card, então herda o vermelho aqui em vez de
   depender do .btn-danger, que é escopado a outra página. */
.pedido-btn-recusar {
  background: #b91c1c;
  color: #fff;
  border: 1px solid #b91c1c;
}
.pedido-btn-recusar:hover { background: #991b1b; }

.pedido-confirma { margin-top: 0.75rem; }
.pedido-motivo-label { display: block; font-size: 0.75rem; color: #fca5a5; margin-bottom: 4px; }
.pedido-motivo { font-size: 0.85rem; padding: 0.5rem 0.6rem; }
.pedido-confirma .pedido-acoes { margin-top: 0.5rem; }

.pedido-erro { margin-top: 0.5rem; font-size: 0.78rem; color: #fca5a5; }

.pedidos-overflow {
  order: 1;                  /* sempre acima dos cards (ver column-reverse) */
  background: rgba(15, 23, 42, 0.94);
  border: 1px solid var(--border-color);
  border-radius: 999px;
  padding: 4px 12px;
  font-size: 0.75rem;
  font-weight: 700;
  color: #cbd5e1;
}

@media (max-width: 640px) {
  .pedidos-dock { right: 10px; bottom: 10px; left: 10px; align-items: stretch; }
  .pedido-card { width: auto; }
}

/* ==========================================================================
   TOTEM 2 — tela de espera pela liberação da portaria (totem2.js)

   O visitante fica parado aqui enquanto o porteiro decide, então a tela precisa
   PARECER viva: o pulso e o contador de espera existem para que ninguém ache que
   o totem travou e saia andando no meio do próprio cadastro.
   ========================================================================== */
.wait-card { text-align: center; padding: 2.25rem 1.5rem; }

.wait-badge {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 4px 12px;
  border-radius: 999px;
  background: rgba(59, 130, 246, 0.18);
  color: #93c5fd;
  margin-bottom: 1.25rem;
}

.wait-pulse { display: flex; justify-content: center; gap: 10px; margin-bottom: 1.25rem; }
.wait-pulse span {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--accent-primary);
  animation: waitPulse 1.2s ease-in-out infinite;
}
.wait-pulse span:nth-child(2) { animation-delay: 0.18s; }
.wait-pulse span:nth-child(3) { animation-delay: 0.36s; }

@keyframes waitPulse {
  0%, 100% { opacity: 0.25; transform: scale(0.8); }
  50%      { opacity: 1;    transform: scale(1.15); }
}

.wait-title { font-size: 1.35rem; font-weight: 800; margin-bottom: 0.75rem; }
.wait-name { font-size: 1.1rem; font-weight: 700; margin: 0 0 0.2rem; }
.wait-dest { font-size: 0.95rem; color: var(--text-muted); margin: 0 0 1rem; }
/* white-space: quando existe motivo escrito pela portaria, ele vem em outra linha. */
.wait-hint { font-size: 0.95rem; color: var(--text-muted); white-space: pre-line; margin: 0; }
.wait-clock { font-size: 0.85rem; color: var(--text-muted); margin: 1rem 0 0; }
.wait-clock span { font-variant-numeric: tabular-nums; }

/* Aprovado: o mesmo cartão vira confirmação enquanto o cadastro se conclui. */
.wait-card.is-approved .wait-badge { background: rgba(16, 185, 129, 0.18); color: #6ee7b7; }
.wait-card.is-approved .wait-pulse span { background: var(--accent-success); }

/* ==========================================================================
   CORES POR ORIGEM DO ACESSO — feed "Catraca ao vivo" (painel.js)

   Cinco caminhos levam alguém à catraca, e a portaria precisa reconhecer qual foi
   sem parar para ler. Cada card recebe a cor da sua origem no fundo, na barra da
   esquerda e no rótulo — três sinais da mesma cor, para funcionar tanto de perto
   quanto de relance na tela do balcão.

   Escolha das matizes (superfície escura, `--bg-card`):
     • Colaborador é a maioria absoluta das passagens, então fica no CINZA-AZULADO
       neutro: colorir o normal apagaria o que é exceção.
     • As outras quatro são matizes bem afastadas entre si — violeta, âmbar, ciano
       e rosa — para continuarem distinguíveis também em daltonismo.
     • O rosa do totem 2 evita o verde de propósito: verde já é "▸ Entrada" na
       pílula à direita do mesmo card, e duas coisas diferentes na mesma cor dentro
       do mesmo card é exatamente o que a cor deveria evitar.

   A cor NUNCA vai sozinha — o nome da origem vai escrito no card e a legenda fica
   em cima da lista. Cor é o atalho, não a informação.
   ========================================================================== */
/* A faixa era de 3 px e sumia no monitor da portaria, visto de pé e de longe.
   Passou a 9 px em 25/08/2026, junto com a lateral indo de 330 px para 400 px —
   os 70 px extras pagam a faixa mais larga sem espremer nome e destino. O fundo
   subiu junto (0,13 → 0,18) porque a faixa larga pedia um corpo à altura. */
.feed-item {
  border-left: 9px solid transparent;
  padding-left: 10px;
}

.feed-origem { font-weight: 700; }

.feed-item.origem-colaborador { background: rgba(148, 163, 184, 0.17); border-left-color: #94a3b8; }
.feed-item.origem-convite     { background: rgba(167, 139, 250, 0.19); border-left-color: #a78bfa; }
.feed-item.origem-portaria    { background: rgba(251, 191, 36, 0.18);  border-left-color: #fbbf24; }
.feed-item.origem-totem       { background: rgba(34, 211, 238, 0.18);  border-left-color: #22d3ee; }
.feed-item.origem-totem2      { background: rgba(244, 114, 182, 0.19); border-left-color: #f472b6; }

.feed-item.origem-colaborador .feed-origem { color: #cbd5e1; }
.feed-item.origem-convite     .feed-origem { color: #c4b5fd; }
.feed-item.origem-portaria    .feed-origem { color: #fcd34d; }
.feed-item.origem-totem       .feed-origem { color: #67e8f9; }
.feed-item.origem-totem2      .feed-origem { color: #f9a8d4; }

/* O hover continua existindo por cima da cor da origem (o card é clicável). */
.feed-item.origem-colaborador:hover { background: rgba(148, 163, 184, 0.22); }
.feed-item.origem-convite:hover     { background: rgba(167, 139, 250, 0.24); }
.feed-item.origem-portaria:hover    { background: rgba(251, 191, 36, 0.23); }
.feed-item.origem-totem:hover       { background: rgba(34, 211, 238, 0.23); }
.feed-item.origem-totem2:hover      { background: rgba(244, 114, 182, 0.24); }

/* Legenda — a lateral é estreita, então os itens quebram em linha sozinhos. */
.feed-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  margin-bottom: 10px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border-color);
}

.feed-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--text-muted);
  white-space: nowrap;
}

.feed-legend-item::before {
  content: "";
  width: 9px;
  height: 9px;
  border-radius: 3px;
  background: currentColor;
}

.feed-legend-item.origem-colaborador::before { background: #94a3b8; }
.feed-legend-item.origem-convite::before     { background: #a78bfa; }
.feed-legend-item.origem-portaria::before    { background: #fbbf24; }
.feed-legend-item.origem-totem::before       { background: #22d3ee; }
.feed-legend-item.origem-totem2::before      { background: #f472b6; }

/* ==========================================================================
   ESTACIONAMENTO AO VIVO — segundo feed da lateral (25/08/2026)

   As duas antenas veiculares (`ANTENA VEICULAR ENTRADA` / `SAIDA`) começaram a
   publicar em `VehicleAccessEvent/filtered` em 19/08/2026 — antes disso a rota
   devolvia zero e o pátio era um log local preenchido à mão.

   ⚠️ O painel só conta TAG CADASTRADA (decisão de 25/08: estamos em fase de
   implementação). Das 101 TAGs que as antenas leem, 2 batem com o `rfId` do
   EasyControl; as outras 99 chegam com `blocked: true`, placa e nome vazios e
   são DESCARTADAS. Enquanto o cadastro não avança, este feed é ralo de
   propósito — ver o cabeçalho do painel.js.

   Sem foto: estes eventos não trazem imagem (`photoB64License` é sempre null,
   é leitura de TAG e não de placa). A linha é mais baixa que a da catraca, o
   que é justamente o que faz os dois feeds caberem em 768 px de altura.
   ========================================================================== */
.veic-list {
  display: flex;
  flex-direction: column;
  /* A lista mudou da lateral para dentro do card "Estacionamento hoje" em
     25/08/2026, então os tokens de altura vivem aqui e não mais no
     `.painel-aside`. 42 px é a linha medida no navegador, com 2 linhas de texto. */
  --veic-row: 42px;
  --veic-gap: 8px;
  gap: var(--veic-gap);
  max-height: calc(4 * var(--veic-row) + 3 * var(--veic-gap));
  overflow-y: auto;
}

/* ORÇAMENTO DE ALTURA — o monitor da portaria é 1366x768 e a meta é a tela
   inteira SEM ROLAGEM. Abaixo de 900 px de altura a lista cai para 3 linhas.

   ⚠️ Estas duas regras precisam vir DEPOIS da regra base acima. Elas moravam na
   seção do painel, centenas de linhas antes, e como têm a mesma especificidade
   quem vencia era a base — a media query não fazia nada. */
@media (max-height: 900px) {
  .veic-list { max-height: calc(3 * var(--veic-row) + 2 * var(--veic-gap)); }
}
@media (max-width: 1150px) {
  .veic-list { max-height: 320px; }
}
.veic-item {
  display: flex;
  align-items: center;
  gap: 9px;
  border-left: 9px solid transparent;
  border-radius: var(--radius-sm);
  padding: 5px 6px 5px 10px;
  user-select: none;
}
/* Duas linhas, não três: placa e dono dividem a primeira. A altura da linha é o
   que decide quantos veículos cabem embaixo da catraca em 768 px — a três linhas
   só cabiam 2 veículos, a duas cabem 3. */
.veic-linha1 {
  display: flex;
  align-items: baseline;
  gap: 7px;
  min-width: 0;
}
.veic-placa {
  font-weight: 700;
  font-size: 0.86rem;
  line-height: 1.2;
  letter-spacing: 0.03em;
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.veic-meta { color: var(--text-dim); font-size: 0.72rem; line-height: 1.3; }
.veic-dono {
  color: var(--text-muted);
  font-size: 0.74rem;
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

/* Mesmas cores de origem da catraca: o carro herda o perfil do dono, então um
   colaborador chegando de carro tem a mesma faixa que teria na catraca. */
.veic-item.origem-colaborador { background: rgba(148, 163, 184, 0.17); border-left-color: #94a3b8; }
.veic-item.origem-convite     { background: rgba(167, 139, 250, 0.19); border-left-color: #a78bfa; }
.veic-item.origem-portaria    { background: rgba(251, 191, 36, 0.18);  border-left-color: #fbbf24; }
.veic-item.origem-totem       { background: rgba(34, 211, 238, 0.18);  border-left-color: #22d3ee; }
.veic-item.origem-totem2      { background: rgba(244, 114, 182, 0.19); border-left-color: #f472b6; }

/* Pílulas de direção: verde/cinza como no feed da catraca, mas com a seta
   apontando para o pátio, não para o prédio. */
.pill-veic-in  { background: rgba(12, 163, 12, 0.15); color: #4ade80; }
.pill-veic-out { background: rgba(148, 163, 184, 0.15); color: var(--text-muted); }

/* ==========================================================================
   CARD "ESTACIONAMENTO HOJE" — coluna da esquerda do painel
   ========================================================================== */
.estac-nums {
  display: flex;
  gap: 1.5rem;
  margin: 0.35rem 0 0;
  flex-wrap: wrap;
}
.estac-num { display: flex; flex-direction: column; min-width: 0; }
.estac-num-value {
  font-size: 1.6rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
}
.estac-num-label { color: var(--text-muted); font-size: 0.72rem; font-weight: 600; }
.estac-num.is-in  .estac-num-value { color: #4ade80; }
.estac-num.is-out .estac-num-value { color: var(--text-muted); }

/* Faixa que separa o resumo do dia do vaivém ao vivo, dentro do mesmo card. */
.estac-live {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 0.8rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--border-color);
  margin-bottom: 0.6rem;
}
.estac-live-titulo { font-weight: 700; font-size: 0.84rem; }

/* ==========================================================================
   GESTÃO DE VISITANTES — lista em lotes e detalhes por linha (visitantes.js)

   A listagem tem 5.533 cadastros e a API só entrega foto/CPF/liberação um a um
   (~115 KB por foto). A tela então cresce na rolagem e cada linha se completa
   quando chega perto do campo de visão — daí os estados "carregando" e
   "pendente" abaixo: eles são o normal desta tela, não uma falha.
   ========================================================================== */
.vis-nota {
  font-size: 0.78rem;
  color: var(--text-muted);
  margin: -0.5rem 0 1rem;
  line-height: 1.5;
}

.vis-today-badge {
  background: rgba(59, 130, 246, 0.18);
  color: #93c5fd;
  border-color: rgba(59, 130, 246, 0.35);
}

.vis-foto {
  display: inline-flex;
  width: 36px;
  height: 36px;
  border-radius: 6px;
  object-fit: cover;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.08);
  vertical-align: middle;
}

.vis-foto-vazia { color: var(--text-muted); }

/* Enquanto a foto daquela linha não chegou: um retângulo pulsando no lugar dela,
   para a coluna não "pular" quando a imagem entrar. */
.vis-foto-carregando { animation: visPulso 1.2s ease-in-out infinite; }

@keyframes visPulso {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 0.8; }
}

.vis-pendente { color: var(--text-dim); }
.vis-mais { color: var(--text-dim); font-size: 0.78rem; }

/* Linha-sentinela: é ela que avisa que a rolagem chegou ao fim do lote. */
.vis-sentinel td {
  text-align: center;
  padding: 1.1rem;
  color: var(--text-dim);
  font-size: 0.8rem;
}

/* A tabela de visitantes é clara (`.vis-table td` é #1e293b): o CPF herda essa cor
   em vez do cinza-claro que vinha de quando a coluna era sempre "—". */
.vis-doc { font-variant-numeric: tabular-nums; white-space: nowrap; }
.vis-table .vis-pendente,
.vis-table .vis-mais { color: #94a3b8; }
.vis-table .vis-foto-vazia { background: #e2e8f0; color: #64748b; }
.vis-table .vis-foto-carregando { background: #e2e8f0; }

/* Linha-sentinela do diretório de colaboradores — mesma da lista de visitantes:
   é ela que avisa que a rolagem chegou ao fim do lote (ver PAGINA_DIR). */
.dir-sentinel td {
  text-align: center;
  padding: 1.1rem;
  color: var(--text-dim);
  font-size: 0.8rem;
}

/* O CPF vinha com cor fixa clara, ilegível na tabela clara do diretório. */
.dir-doc { font-variant-numeric: tabular-nums; white-space: nowrap; }
.dir-table .dir-sentinel td { color: #94a3b8; }

/* Aviso do modo consulta (operador na Gestão de Visitantes): nome e CPF mascarados
   e cadastro somente leitura. Fica mais forte que a nota comum ao lado. */
.vis-aviso-consulta {
  background: rgba(59, 130, 246, 0.12);
  border: 1px solid rgba(59, 130, 246, 0.3);
  border-radius: var(--radius-sm);
  padding: 0.6rem 0.8rem;
  color: #dbeafe;
  margin: 0 0 0.75rem;
}

/* ==========================================================================
   PÁGINA ESTACIONAMENTO (estacionamento.html)

   Pátio e movimentação lidos das antenas veiculares. Tudo escopado em
   body.estacionamento — o styles.css é compartilhado com totem, portaria e
   diretório. Ver o cabeçalho do estacionamento.js para o porquê de as tabelas
   nascerem vazias enquanto o cadastro de TAGs não avança.
   ========================================================================== */
body.estacionamento main { max-width: 1400px; margin: 0 auto; padding: 1.5rem 1rem; }

body.estacionamento .estac-kpis { margin-bottom: 1rem; }

/* As duas tabelas lado a lado: pátio à esquerda (o que a portaria consulta),
   movimentação à direita (o que ela confere). Empilham antes de espremer. */
.estac-cols {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 1.25rem;
  align-items: start;
}
@media (max-width: 1100px) {
  .estac-cols { grid-template-columns: minmax(0, 1fr); }
}
.estac-cols .card { margin: 0; max-width: none; }
.estac-cols .table-scroll { max-height: 60vh; }

.estac-toolbar { margin-bottom: 1.25rem; max-width: none; }
.estac-filtros {
  display: grid;
  grid-template-columns: 170px minmax(0, 1fr) 200px auto;
  gap: 12px;
  align-items: end;
}
@media (max-width: 900px) {
  .estac-filtros { grid-template-columns: 1fr 1fr; }
}
.estac-filtro { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.estac-filtro label {
  font-size: 0.76rem;
  font-weight: 700;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  display: flex;
  align-items: center;
  gap: 5px;
}
.estac-recarregar { width: auto; padding: 10px 18px; white-space: nowrap; }

/* A ressalva das TAGs órfãs fica entre os KPIs e as tabelas de propósito: é o
   que impede alguém de ler "3 no pátio" como "o pátio tem 3 carros". Fundo
   próprio porque `.alert-warning` não existe no styles.css — só danger e success. */
.estac-ressalva {
  display: block;
  margin-bottom: 1.25rem;
  padding: 0.85rem 1.1rem;
  border-radius: var(--radius-md);
  border: 1px solid rgba(245, 158, 11, 0.35);
  border-left: 4px solid var(--accent-warning, #f59e0b);
  background: rgba(245, 158, 11, 0.12);
  font-size: 0.84rem;
  line-height: 1.55;
}
.estac-ressalva code {
  background: rgba(0, 0, 0, 0.25);
  border-radius: 4px;
  padding: 1px 5px;
  font-size: 0.94em;
}

/* Placa e TAG são códigos: fonte tabular, para a coluna alinhar e o olho comparar. */
.estac-placa { letter-spacing: 0.04em; font-variant-numeric: tabular-nums; }
.estac-tag {
  font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  font-size: 0.94em;
  color: var(--text-muted);
}

.estac-orfas { margin-top: 1.25rem; }
.estac-orfas > summary {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 10px;
  list-style-position: outside;
}
.estac-orfas > summary::marker { color: var(--text-dim); }
.estac-orfas-hint {
  color: var(--text-muted);
  font-size: 0.82rem;
  line-height: 1.55;
  margin: 0.9rem 0 1rem;
  max-width: 70ch;
}
.estac-orfas-hint code {
  background: var(--bg-secondary);
  border-radius: 4px;
  padding: 1px 5px;
  font-size: 0.94em;
}

.estac-stamp {
  color: var(--text-dim);
  font-size: 0.75rem;
  text-align: right;
  margin: 1rem 0 0;
}
.estac-stamp.stamp-warn { color: var(--accent-warning, #f59e0b); }

/* Contraste alto dentro dos cards, como em body.portaria: o fundo é a foto do
   prédio e o cinza padrão do tema some por cima dela. */
body.estacionamento {
  --text-muted: #e2e8f0;
  --text-dim: #cbd5e1;
}
body.estacionamento .card,
body.estacionamento .kpi-tile,
body.estacionamento .auth-container { color: #ffffff; }
body.estacionamento .data-table th { color: #cbd5e1; }
body.estacionamento .estac-tag { color: #cbd5e1; }
body.estacionamento .kpi-label { color: #e2e8f0; }
body.estacionamento .estac-filtro label { color: #e2e8f0; }
body.estacionamento .estac-ressalva { color: #ffffff; }
/* O negrito fica BRANCO, não âmbar: a faixa já é âmbar, e âmbar sobre âmbar era
   justamente a frase mais importante da página virando a menos legível. */
body.estacionamento .estac-ressalva strong { color: #ffffff; }
body.estacionamento .form-control::placeholder { color: #94a3b8; }
body.estacionamento .estac-orfas-hint { color: #e2e8f0; }
body.estacionamento .estac-stamp { color: #cbd5e1; }

/* ==========================================================================
   DUAS FONTES DE FOTO NO MODAL DA CÂMERA (25/08/2026)

   A webcam do PC continua sendo o padrão; a leitora facial de cadastro entra
   como segunda fonte. Ver o cabeçalho de openCameraModal no portaria.js para o
   porquê de a facial não ter auto-captura.
   ========================================================================== */
.cam-fontes {
  display: inline-flex;
  gap: 4px;
  padding: 3px;
  border-radius: var(--radius-md);
  background: rgba(255, 255, 255, 0.08);
}
.cam-fonte {
  border: 0;
  background: transparent;
  color: rgba(255, 255, 255, 0.72);
  font-size: 0.82rem;
  font-weight: 600;
  font-family: inherit;
  padding: 6px 12px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s, color 0.15s;
}
.cam-fonte:hover { color: #fff; background: rgba(255, 255, 255, 0.1); }
.cam-fonte.is-active { background: var(--accent-primary); color: #fff; }
.cam-fonte:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* A prévia da leitora ocupa a mesma moldura do <video>. `object-fit: cover`
   porque a leitora entrega 368x640 (retrato estreito) e a moldura é 3:4 —
   sem isso a imagem apareceria deitada dentro de duas tarjas pretas. */
.cam-facial {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  background: #0b1220;
}

/* Botão da leitora ao lado do "Tirar foto", no formulário de cadastro. */
.btn-facial { width: auto; }

/* ==========================================================================
   ESCOLHA DA FONTE DA FOTO — dois alvos iguais (25/08/2026)

   Eram dois `.btn-secondary` em fila, um deles com o rótulo comprido
   "🛡️ Leitora facial" espremido. Como as duas fontes valem o mesmo (a webcam
   não é "a principal"), viraram dois cartões de mesmo tamanho, com ícone
   desenhado — emoji renderiza diferente em cada máquina e não aceita a cor do
   estado — e uma linha de apoio que diz DE ONDE vem cada imagem, que é a
   dúvida real de quem está no balcão.
   ========================================================================== */
/* EMPILHADOS, não lado a lado. A "Foto Facial" mora numa das duas colunas do
   `.grid-2` do modal e ainda divide espaço com a miniatura: sobravam ~100 px por
   botão, e os subtítulos truncavam em "deste …" e "câmer…". Em coluna cada um
   fica com a largura toda e o texto cabe inteiro. */
.foto-fontes {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
  flex: 1;
  min-width: 0;
}
.foto-fonte {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
  padding: 9px 11px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  color: var(--text-main);
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, transform 0.1s;
}
.foto-fonte:hover { background: var(--bg-card-hover); border-color: var(--accent-primary); }
.foto-fonte:active { transform: translateY(1px); }
.foto-fonte:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 2px; }
.foto-fonte-ico { width: 22px; height: 22px; flex-shrink: 0; color: var(--accent-primary); }
.foto-fonte-ico svg { width: 100%; height: 100%; display: block; }
.foto-fonte-txt { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.foto-fonte-rot { font-size: 0.86rem; font-weight: 600; line-height: 1.2; }
.foto-fonte-sub {
  font-size: 0.7rem;
  line-height: 1.25;
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
body.portaria .foto-fonte-rot { color: #ffffff; }
body.portaria .foto-fonte-sub { color: #cbd5e1; }

/* ==========================================================================
   SILHUETA QUE RESPONDE + CONTAGEM (25/08/2026)

   A silhueta já existia como moldura tracejada estática. Agora ela ACENDE em
   verde quando o detector confirma rosto bem enquadrado, e a contagem começa.
   O retorno importa mais na leitora facial, onde o visitante está longe do
   monitor: o operador precisa saber, de relance, se já pode pedir para a pessoa
   ficar parada. Ver handleCountdown no portaria.js.
   ========================================================================== */
.cam-silhouette ellipse[stroke] {
  transition: stroke 0.18s ease, stroke-width 0.18s ease;
}
.cam-silhouette.is-framed ellipse[stroke] {
  stroke: #4ade80;
  stroke-width: 3.5;
  stroke-dasharray: none;
}
/* A máscara ao redor NÃO muda de cor: tingir a moldura inteira de verde tirava
   a leitura da imagem justo quando a portaria precisa conferir o rosto. O anel
   aceso e o número já dizem que o enquadramento foi aceito. */

/* Guia do modo 'etiqueta' — mesma mecânica da silhueta, retângulo no lugar da
   elipse. Some/aparece por style.display no camera.js/portaria.js. */
.cam-guia-etiqueta {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.cam-guia-etiqueta rect[stroke] {
  transition: stroke 0.18s ease, stroke-width 0.18s ease;
}
.cam-guia-etiqueta.is-framed rect[stroke] {
  stroke: #4ade80;
  stroke-width: 3.5;
  stroke-dasharray: none;
}
/* Etiqueta é texto: a prévia não pode ser espelhada como numa selfie. */
.cam-modal.modo-etiqueta video { transform: none; }
@media (prefers-reduced-motion: reduce) {
  .cam-guia-etiqueta rect[stroke] { transition: none; }
}

/* A contagem herda o verde do enquadramento confirmado: o número aparecendo
   já é a confirmação de que o rosto foi aceito. */
.cam-countdown {
  color: #4ade80;
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.9), 0 0 34px rgba(74, 222, 128, 0.45);
  animation: cam-pulso 1s ease-in-out infinite;
}
@keyframes cam-pulso {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.09); }
}
@media (prefers-reduced-motion: reduce) {
  .cam-countdown { animation: none; }
  .cam-silhouette ellipse[stroke] { transition: none; }
}

/* ==========================================================================
   ENCOMENDAS (encomendas.html) — protocolo de recebimento e retirada

   Tudo escopado em body.encomendas, como as outras páginas. O balcão é a tela
   mais apressada do sistema: origem em botão (não em select), destinatário por
   busca, foto em dois cliques.
   ========================================================================== */
body.encomendas main { max-width: 1500px; margin: 0 auto; padding: 1.5rem 1rem; }
body.encomendas { --text-muted: #e2e8f0; --text-dim: #cbd5e1; }
body.encomendas .card,
body.encomendas .kpi-tile,
body.encomendas .auth-container { color: #ffffff; }
body.encomendas .data-table th { color: #cbd5e1; }
body.encomendas label { color: #e2e8f0; }

.enc-kpis { margin-bottom: 1rem; }
.enc-cols {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: 1.25rem;
  align-items: start;
}
@media (max-width: 1100px) { .enc-cols { grid-template-columns: minmax(0, 1fr); } }
.enc-cols .card { margin: 0; max-width: none; }
.enc-dica { font-weight: 400; font-size: 0.78rem; color: var(--text-dim); }

/* Volumes: os dois botões existem porque cada volume acrescenta um slot de
   etiqueta logo abaixo, e o balcão mexe nesse número com o pacote na mão. */
.enc-volumes { display: flex; align-items: stretch; gap: 6px; }
.enc-volumes .form-control { text-align: center; }
.enc-vol-btn {
  flex-shrink: 0; width: 40px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  background: var(--bg-secondary);
  color: var(--text-main);
  font-family: inherit; font-size: 1.15rem; font-weight: 700; line-height: 1;
  cursor: pointer;
}
.enc-vol-btn:hover { border-color: var(--accent-primary); }
.enc-vol-btn:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 2px; }

/* Origem em botões, não em <select>: são 8 opções fixas e o balcão escolhe uma
   por pacote — abrir uma lista para isso custa um clique a mais em cada
   encomenda de um lote de quinze. */
.enc-origens { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.enc-origem {
  display: inline-flex; align-items: center; gap: 7px;
  border: 1px solid var(--border-color);
  background: var(--bg-secondary);
  color: var(--text-main);
  font-family: inherit;
  font-size: 0.82rem;
  font-weight: 600;
  padding: 5px 11px 5px 5px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}

/* Selo da marca: quadrado colorido com o símbolo por dentro. A borda branca
   existe para o selo não sumir dentro do botão SELECIONADO, que fica pintado
   da mesma cor — sem ela, a Shopee escolhida virava um retângulo laranja liso.
   Fundo e cor do símbolo vêm em `style=`, do ORIGENS no encomendas-form.js. */
.enc-origem-logo {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; flex-shrink: 0;
  border: 2px solid #ffffff;
  border-radius: 7px;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.18);
}
.enc-origem-logo svg { width: 17px; height: 17px; display: block; }
.enc-origem-logo.is-mini {
  width: 17px; height: 17px; border-width: 1px; border-radius: 5px;
  margin-right: 5px; vertical-align: -3px; box-shadow: none;
}
.enc-origem-logo.is-mini svg { width: 12px; height: 12px; }
.enc-origem-logo.is-grande { width: 34px; height: 34px; border-radius: 9px; }

/* Uma pastilha por etiqueta na lista de pendentes — clicável com o dedo. */
.enc-etiq-link {
  display: inline-block; min-width: 20px; margin-left: 4px;
  padding: 1px 6px; border-radius: 5px;
  border: 1px solid var(--border-color);
  text-align: center; text-decoration: none; font-weight: 700;
}
.enc-etiq-link:hover { border-color: var(--accent-primary); background: var(--bg-card-hover); }
.enc-origem-logo.is-grande svg { width: 22px; height: 22px; }
.enc-origem:hover { border-color: var(--cor); }
.enc-origem.is-on {
  background: var(--cor);
  border-color: var(--cor);
  color: var(--texto, #ffffff);
}
.enc-origem:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 2px; }

/* Busca de destinatário */
.enc-hits {
  margin-top: 6px;
  max-height: 240px;
  overflow-y: auto;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
}
.enc-hit {
  display: flex; flex-direction: column; gap: 1px;
  width: 100%; text-align: left;
  padding: 8px 12px;
  border: 0; border-bottom: 1px solid var(--border-color);
  background: transparent; color: var(--text-main);
  font-family: inherit; cursor: pointer;
}
.enc-hit:last-child { border-bottom: 0; }
.enc-hit:hover { background: var(--bg-card-hover); }
.enc-hit-nome { font-weight: 600; font-size: 0.88rem; }
.enc-hit-sub { font-size: 0.75rem; color: var(--text-dim); }

.enc-selecionado {
  margin-top: 8px;
  padding: 10px 12px;
  border: 1px solid var(--accent-primary);
  border-radius: var(--radius-md);
  background: rgba(59, 130, 246, 0.1);
}
.enc-sel-linha { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.enc-sel-nome { font-weight: 700; }
.enc-sel-sub { font-size: 0.78rem; color: var(--text-dim); }
.enc-sel-fone { font-size: 0.8rem; margin-top: 3px; }
.enc-fone-ok { color: #4ade80; font-weight: 600; }
.enc-fone-sem { color: var(--accent-warning, #fbbf24); }
.enc-fone-buscando { color: var(--text-dim); font-style: italic; }
.enc-sel-trocar { width: auto; padding: 6px 12px; font-size: 0.78rem; flex-shrink: 0; }

/* Slots de foto */
/* Os slots deixaram de ser dois fixos (etiqueta + entregador) e passaram a ser
   um por volume mais o entregador — `auto-fill` acomoda de 2 a 13 sem quebrar
   o modal, que já tem teto de altura. */
.enc-fotos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  gap: 10px; margin-top: 4px;
}
@media (max-width: 620px) { .enc-fotos { grid-template-columns: 1fr; } }
.enc-foto-slot {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  border: 1px dashed var(--border-color);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  color: var(--text-main);
  font-family: inherit; text-align: left; cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}
.enc-foto-slot:hover { border-color: var(--accent-primary); background: var(--bg-card-hover); }
/* Slot obrigatório ainda vazio, DEPOIS de uma tentativa de registrar. A cor
   sozinha não conta a história: quem lê o aviso no topo já sabe o que falta, e
   isto só aponta em qual dos quadradinhos. */
.enc-foto-slot.is-faltando {
  border-color: #ef4444;
  border-style: solid;
  background: rgba(239, 68, 68, 0.10);
}
.enc-foto-slot.is-faltando .enc-foto-thumb { background: rgba(239, 68, 68, 0.16); }
.enc-foto-slot:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 2px; }
.enc-foto-thumb {
  width: 42px; height: 56px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.3rem;
  border-radius: var(--radius-sm);
  background: var(--bg-primary);
  overflow: hidden;
}
.enc-foto-thumb.tem-foto { border: 1px solid var(--accent-primary); }
.enc-foto-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.enc-foto-txt { display: flex; flex-direction: column; min-width: 0; }
.enc-foto-txt b { font-size: 0.85rem; }
.enc-foto-txt span { font-size: 0.72rem; color: var(--text-dim); }

/* ── Leitura da etiqueta (OCR) ──────────────────────────────────────────────
   Botão largo e separado dos slots 🏷️: é o atalho que preenche o formulário,
   não mais uma foto. Só aparece quando o servidor tem o Tesseract. */
.enc-ocr-btn {
  display: flex; align-items: center; gap: 12px; width: 100%;
  margin: 2px 0 14px;
  padding: 11px 14px;
  border: 1px solid var(--accent-primary);
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--accent-primary) 10%, transparent);
  color: var(--text-main);
  font-family: inherit; text-align: left; cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
/* `display: flex/block` na classe vence o [hidden] do navegador — mesma
   armadilha do `.pedido-acoes` mais acima. */
.enc-ocr-btn[hidden], .enc-ocr-resultado[hidden] { display: none; }
.enc-ocr-btn:hover { background: color-mix(in srgb, var(--accent-primary) 18%, transparent); }
.enc-ocr-btn:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 2px; }
.enc-ocr-btn:disabled { opacity: 0.6; cursor: progress; }
.enc-ocr-icone { font-size: 1.35rem; flex-shrink: 0; }
.enc-ocr-texto { display: flex; flex-direction: column; min-width: 0; }
.enc-ocr-texto b { font-size: 0.9rem; }
.enc-ocr-texto span { font-size: 0.74rem; color: var(--text-dim); }

.enc-ocr-resultado {
  margin: -6px 0 14px;
  padding: 10px 12px;
  border: 1px solid #f59e0b;
  border-radius: var(--radius-md);
  background: rgba(245, 158, 11, 0.10);
  font-size: 0.82rem;
}
.enc-ocr-resultado.is-lendo { border-color: var(--accent-primary); background: color-mix(in srgb, var(--accent-primary) 8%, transparent); }
.enc-ocr-resultado.is-aviso { border-color: var(--border-color); background: var(--bg-secondary); }
.enc-ocr-status { color: var(--text-main); }
.enc-ocr-titulo { font-weight: 600; margin-bottom: 6px; color: var(--text-main); }
.enc-ocr-linha { display: flex; justify-content: space-between; gap: 12px; padding: 2px 0; }
.enc-ocr-linha span { color: var(--text-dim); text-transform: capitalize; }
.enc-ocr-linha b { color: var(--text-main); text-align: right; word-break: break-word; }
.enc-ocr-cru { margin-top: 8px; }
.enc-ocr-cru summary { cursor: pointer; color: var(--text-dim); font-size: 0.76rem; }
.enc-ocr-cru pre {
  margin: 6px 0 0; padding: 8px; max-height: 160px; overflow: auto;
  background: var(--bg-primary); border-radius: var(--radius-sm);
  font-size: 0.72rem; white-space: pre-wrap; word-break: break-word;
}
/* Campo preenchido pelo OCR — some ao primeiro toque (marcarOcr). */
.enc-ocr-preenchido,
.enc-ocr-preenchido .form-control {
  border-color: #f59e0b !important;
  box-shadow: 0 0 0 2px rgba(245, 158, 11, 0.20);
}

/* Lista de pendentes */
.enc-lista { display: flex; flex-direction: column; gap: 8px; max-height: 62vh; overflow-y: auto; }
.enc-item {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--border-color);
  border-left: 5px solid var(--accent-primary);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
}
/* Encalhada acende: é o pacote que a recepção precisa cobrar, não o mais novo. */
.enc-item.is-encalhada { border-left-color: var(--accent-warning, #f59e0b); background: rgba(245, 158, 11, 0.09); }
.enc-item-cod {
  font-family: ui-monospace, 'SF Mono', Menlo, monospace;
  font-size: 1.05rem; font-weight: 700; letter-spacing: 0.06em;
  flex-shrink: 0; color: var(--accent-primary);
}
.enc-item.is-encalhada .enc-item-cod { color: var(--accent-warning, #fbbf24); }
.enc-item-corpo { flex: 1; min-width: 0; }
.enc-item-nome { font-weight: 600; font-size: 0.9rem; }
.enc-item-sub { font-size: 0.76rem; color: var(--text-muted); }
.enc-item-meta { font-size: 0.72rem; color: var(--text-dim); margin-top: 2px; }
.enc-item-acoes { display: flex; gap: 6px; flex-shrink: 0; }
.enc-mini { width: auto; padding: 7px 12px; font-size: 0.8rem; }
.enc-terceiro {
  font-size: 0.68rem; background: rgba(245,158,11,.2);
  color: var(--accent-warning, #fbbf24); border-radius: 10px; padding: 1px 7px;
}
/* Os dois botões do topo da lista (ler QR e receber) em uma linha só; em tela
   estreita eles empilham em vez de espremer o rótulo. */
.enc-acoes-topo { display: flex; gap: 8px; flex-wrap: wrap; }

/* ==========================================================================
   Retirada — etiquetas à vista, quem entrega e quem retira
   ========================================================================== */
.retira-bloco { margin: 1rem 0; }
.retira-rot {
  font-size: 0.7rem; font-weight: 800; letter-spacing: 0.07em;
  text-transform: uppercase; color: #64748b; margin-bottom: 6px;
}
.retira-operador {
  font-weight: 700; font-size: 0.92rem; color: #0f172a;
  padding: 8px 12px; border-radius: var(--radius-sm);
  background: #f1f5f9; border: 1px solid #e2e8f0;
}

/* Miniaturas grandes o bastante para ler o destinatário na etiqueta sem abrir:
   é a conferência que o operador faz com o pacote na mão. */
.retira-etiquetas { display: flex; flex-wrap: wrap; gap: 8px; }
.retira-etiq {
  position: relative; display: block;
  width: 76px; height: 100px;
  border-radius: var(--radius-sm); overflow: hidden;
  border: 1px solid #cbd5e1; background: #e2e8f0;
}
.retira-etiq:hover { border-color: var(--accent-primary); }
.retira-etiq img { width: 100%; height: 100%; object-fit: cover; display: block; }
.retira-etiq-n {
  position: absolute; left: 4px; top: 4px;
  min-width: 18px; padding: 1px 5px;
  border-radius: 9px; background: rgba(15, 23, 42, 0.82);
  color: #fff; font-size: 0.68rem; font-weight: 800; text-align: center;
}

/* Quem está retirando — resolvido pelo CPF, nunca digitado à toa. */
.retira-quem {
  margin-top: 8px; padding: 10px 12px;
  border-radius: var(--radius-sm);
  border-left: 4px solid #cbd5e1;
  background: #f8fafc; color: #334155;
  font-size: 0.82rem; line-height: 1.45;
}
.retira-quem.is-buscando { font-style: italic; color: #64748b; }
.retira-quem.is-proprio { border-left-color: #10b981; background: #ecfdf5; color: #065f46; }
.retira-quem.is-terceiro { border-left-color: #f59e0b; background: #fffbeb; color: #92400e; }
.retira-quem.is-erro { border-left-color: #ef4444; background: #fef2f2; color: #991b1b; }
.retira-quem-nome { font-size: 1rem; font-weight: 800; margin-bottom: 2px; }
.retira-quem-tag { font-size: 0.8rem; }

/* ==========================================================================
   Detalhe da encomenda — todos os dados e todas as fotos numa tela só
   ========================================================================== */
/* Alto por natureza (fatos + linha do tempo + grade de fotos): rola dentro do
   card em vez de estourar a tela de 768 px. */
.modal-detalhe { max-width: 640px; max-height: 92vh; overflow-y: auto; }
.det-topo {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding-bottom: 14px; margin-bottom: 14px;
  border-bottom: 1px solid #e2e8f0;
}
.det-cod {
  font-family: ui-monospace, 'SF Mono', Menlo, monospace;
  font-size: 1.5rem; font-weight: 800; letter-spacing: 0.12em;
  color: #1d4ed8; flex-shrink: 0;
}
.det-topo-txt { flex: 1; min-width: 140px; }
.det-nome { font-weight: 700; font-size: 1.02rem; color: #0f172a; }
.det-sub { font-size: 0.82rem; color: #475569; }
.det-status {
  flex-shrink: 0; padding: 4px 12px; border-radius: 999px;
  font-size: 0.72rem; font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase;
  background: #e2e8f0; color: #334155;
}
.det-status.is-entregue { background: #d1fae5; color: #065f46; }
.det-status.is-aguardando { background: #fef3c7; color: #92400e; }
.det-status.is-cancelada { background: #fee2e2; color: #991b1b; }

/* Duas colunas em tela cheia, uma no celular — sem <table>, porque cada linha
   é um par rótulo/valor e não uma grade de dados comparáveis. */
.det-corpo { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 20px; }
@media (max-width: 560px) { .det-corpo { grid-template-columns: 1fr; } }
.det-fato dt {
  font-size: 0.68rem; font-weight: 800; letter-spacing: 0.06em;
  text-transform: uppercase; color: #64748b; margin-bottom: 2px;
}
.det-fato dd {
  margin: 0; font-size: 0.88rem; color: #0f172a; line-height: 1.45;
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px;
}

.det-fotos { margin-top: 1.25rem; }
.det-rot {
  font-size: 0.7rem; font-weight: 800; letter-spacing: 0.07em;
  text-transform: uppercase; color: #64748b; margin-bottom: 8px;
}
.det-grade { display: grid; grid-template-columns: repeat(auto-fill, minmax(116px, 1fr)); gap: 10px; }
.det-foto {
  display: block; text-decoration: none;
  border: 1px solid #cbd5e1; border-radius: var(--radius-sm); overflow: hidden;
  background: #f1f5f9;
}
.det-foto:hover { border-color: var(--accent-primary); }
.det-foto img { width: 100%; aspect-ratio: 3 / 4; object-fit: cover; display: block; }
.det-foto {
  padding: 0; font-family: inherit; cursor: pointer; text-align: center;
  width: 100%;
}
.det-foto span {
  display: block; padding: 5px 6px;
  font-size: 0.7rem; font-weight: 700; color: #334155;
  overflow: hidden; text-overflow: ellipsis;
}
/* O subtítulo é linha PRÓPRIA: em linha ele colava no rótulo ("Etiqueta 1volume
   1 de 4") e estourava a largura da miniatura. */
.det-foto span em {
  display: block; margin-top: 1px;
  font-size: 0.64rem; font-weight: 500; font-style: normal; color: #64748b;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Contagem de etiqueta menor que a de volumes: não é decoração, é a única
   forma de perceber que faltou fotografar depois que o pacote já saiu. */
.det-rot.is-alerta { color: #b45309; }
.det-sem-foto { font-size: 0.82rem; color: #64748b; line-height: 1.5; }

/* ==========================================================================
   LINHA DO TEMPO da encomenda (encomendas-timeline.js)

   Vive dentro de modais claros (.modal-detalhe, .modal-retira) — cores fixas,
   como o resto do bloco .det-*. Dois modos: 'completo' (detalhe, tudo à vista
   ou no ▾) e 'compacto' (entrega, uma linha + ▾).
   ========================================================================== */
.det-timeline { margin-bottom: 1.25rem; }
.retira-timeline { margin: 0.6rem 0; }
.retira-timeline:empty { display: none; }

.tl-lista { list-style: none; margin: 0; padding: 0; }
.tl-item {
  display: flex; gap: 10px;
  padding: 7px 0;
  border-bottom: 1px solid #eef2f7;
}
.tl-item:last-child { border-bottom: 0; }
.tl-ponto {
  flex-shrink: 0; width: 24px; height: 24px;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.9rem;
  background: #f1f5f9; border-radius: 50%;
}
.tl-corpo { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.tl-linha1 { font-size: 0.86rem; color: #0f172a; }
.tl-linha2 { font-size: 0.74rem; color: #64748b; }
.tl-quem { color: #334155; font-weight: 600; }
.tl-det { color: #475569; }
.tl-retirada .tl-ponto { background: #dcfce7; }
.tl-vazia { font-size: 0.8rem; color: #64748b; padding: 4px 0; }

/* O "ver anteriores" — botão discreto, largura da coluna. */
.tl-mais {
  display: inline-flex; align-items: center; gap: 6px;
  margin: 6px 0 2px; padding: 4px 2px;
  border: 0; background: transparent;
  font-family: inherit; font-size: 0.78rem; font-weight: 600;
  color: var(--accent-primary, #2563eb); cursor: pointer;
}
.tl-mais:hover { text-decoration: underline; }
.tl-seta { transition: transform 0.15s; font-size: 0.7rem; }
.tl-mais.is-aberto .tl-seta { transform: rotate(180deg); }
.tl-anteriores { border-top: 1px solid #eef2f7; margin-top: 2px; }

/* Modo compacto (modal de entrega): UMA linha com o evento mais recente + ▾.
   O modal de entrega já é alto — o resumo não pode custar altura. */
.tl-resumo {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 0; border: 0; background: transparent;
  font-family: inherit; font-size: 0.82rem; color: #0f172a; text-align: left;
}
button.tl-resumo { cursor: pointer; }
.tl-resumo .tl-ponto { width: 22px; height: 22px; font-size: 0.82rem; }
.tl-resumo-txt { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tl-resumo .tl-seta { margin-left: auto; flex-shrink: 0; color: var(--accent-primary, #2563eb); }
.tl-compacto.tl-bloco > .tl-mais.is-aberto .tl-seta { transform: rotate(180deg); }
.tl-compacto .tl-anteriores {
  border-top: 1px solid #e2e8f0; margin-top: 6px; padding-top: 2px;
}
.tl-compacto .tl-item { padding: 5px 0; }

/* Rede de segurança: com a linha do tempo aberta, ou muitos volumes, o modal de
   entrega pode passar da tela — deixa rolar em vez de cortar o botão de
   confirmar. Até ~2 volumes com a tira fechada não chega a rolar. */
.modal-retira { max-height: 96vh; overflow-y: auto; }

/* ---------- Visualizador de foto ---------- */
.foto-lupa { align-items: center; justify-content: center; background: rgba(2, 6, 23, .9); }
.foto-lupa.active { display: flex; }
.foto-lupa-quadro { margin: 0; max-width: min(88vw, 620px); text-align: center; }
.foto-lupa-quadro img {
  display: block; max-width: 100%; max-height: 76vh;
  border-radius: 10px; background: #0f172a;
  box-shadow: 0 24px 60px rgba(0, 0, 0, .55);
}
.foto-lupa-quadro figcaption {
  margin-top: 12px; color: #e2e8f0; font-size: 0.86rem; font-weight: 600;
}
.foto-lupa-x { position: fixed; top: 18px; right: 22px; color: #e2e8f0; z-index: 2; }
.foto-lupa-nav {
  flex-shrink: 0;
  width: 54px; height: 54px; margin: 0 10px;
  border: 0; border-radius: 50%;
  background: rgba(255, 255, 255, .12); color: #fff;
  font-size: 2rem; line-height: 1; cursor: pointer;
}
.foto-lupa-nav:hover { background: rgba(255, 255, 255, .24); }
@media (max-width: 620px) {
  .foto-lupa-nav { position: fixed; bottom: 22px; margin: 0; }
  .foto-lupa-nav.is-ant { left: 22px; }
  .foto-lupa-nav.is-prox { right: 22px; }
}

/* Linha do histórico: só é clicável se parecer clicável. */
.enc-hist-linha { cursor: pointer; }
.enc-hist-linha:hover { background: var(--bg-card-hover); }
.enc-hist-linha:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: -2px; }
.enc-hist-ver { color: var(--accent-primary); font-weight: 700; white-space: nowrap; }
.enc-acoes-topo .btn { width: auto; }

.enc-historico { margin-top: 1.25rem; }
.enc-historico > summary { cursor: pointer; display: flex; align-items: center; gap: 10px; }

/* ---------- Modal do protocolo ---------- */
.modal-proto { max-width: 420px; text-align: center; }
.proto-codigo {
  font-family: ui-monospace, 'SF Mono', Menlo, monospace;
  font-size: 3rem; font-weight: 800; letter-spacing: 0.16em;
  color: var(--accent-primary); margin: 0.5rem 0;
}
.proto-qr { display: flex; justify-content: center; margin: 0.5rem 0 1rem; }
.proto-qr img, .proto-qr canvas { border: 8px solid #fff; border-radius: 6px; display: block; }
/* ⚠️ CORES FIXAS, não `var(--text-muted)`.
   Este cartão é BRANCO e abre em DUAS páginas de tema escuro: a portaria
   (`--text-muted: #e2e8f0`) e a de encomendas (`#e2e8f0` também). O token existe
   para texto sobre card escuro — aqui ele virava branco sobre branco, e a
   origem, a sala e o telefone do aviso ficavam ilegíveis. O `body.encomendas
   .modal-card` já revertia os tokens, mas só naquela página; na portaria, onde
   o mesmo modal também abre, ninguém revertia.
   O protocolo é o que o operador lê em voz alta para o entregador e confere
   antes de mandar o WhatsApp: contraste aqui não é estética. */
.proto-dest-origem {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  margin-bottom: 8px;
  font-size: 0.85rem; font-weight: 700; color: #334155;
}
.proto-dest-nome { font-weight: 700; font-size: 1.05rem; color: #0f172a; }
.proto-dest-sub { color: #475569; font-size: 0.85rem; font-weight: 500; }
.proto-dest-pos { color: #475569; font-size: 0.82rem; margin-top: 4px; }
.proto-dest-pos b { color: #0f172a; }
.proto-aviso { font-size: 0.86rem; color: #334155; margin: 0.9rem 0; line-height: 1.5; }
.proto-aviso b { color: #0f172a; }
/* Aviso de segurança na tela — o mesmo que vai desenhado no cartão. Fica aqui
   para o operador saber o que está mandando, e poder ler em voz alta se o
   colaborador estiver no balcão. Cor fixa: ver a nota do `.proto-dest-*`. */
.proto-seguranca {
  text-align: left;
  margin: 0.9rem 0;
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  border-left: 4px solid #f59e0b;
  background: #fffbeb;
}
.proto-seg-tit { font-size: 0.78rem; font-weight: 800; color: #92400e; margin-bottom: 4px; }
.proto-seg-txt { font-size: 0.79rem; line-height: 1.5; color: #78350f; }

/* Retorno do envio: o que o operador precisa fazer em seguida (colar a imagem,
   anexar o arquivo) — sem isto ele não saberia que a imagem foi preparada. */
.proto-status {
  text-align: left;
  margin-bottom: 0.9rem;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  font-size: 0.82rem; line-height: 1.5;
  background: #f1f5f9; color: #334155;
}
.proto-status.is-ok { background: #ecfdf5; color: #065f46; }
.proto-status.is-alerta { background: #fffbeb; color: #92400e; }
.proto-status a { font-weight: 700; color: #1d4ed8; }

.proto-acoes { display: flex; flex-direction: column; gap: 8px; }
.proto-acoes .btn { width: 100%; }

/* ---------- Modal de retirada ---------- */
.modal-retira { max-width: 620px; }
.retira-enc {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 14px; margin-bottom: 1rem;
  border: 1px solid var(--border-color); border-radius: var(--radius-md);
  background: var(--bg-secondary);
}
.retira-cod {
  font-family: ui-monospace, 'SF Mono', Menlo, monospace;
  font-size: 1.5rem; font-weight: 800; letter-spacing: 0.08em;
  color: var(--accent-primary); flex-shrink: 0;
}
.retira-nome { font-weight: 700; }
.retira-sub { font-size: 0.78rem; color: var(--text-dim); }
.retira-pos { font-size: 0.82rem; margin-top: 4px; }
.retira-terceiro {
  display: flex; align-items: center; gap: 9px;
  margin: 0.25rem 0 1rem; font-size: 0.85rem; cursor: pointer;
}
.retira-terceiro input { width: 17px; height: 17px; accent-color: var(--accent-primary); }

/* ---------- Modal do leitor de QR ---------- */
.modal-scan { max-width: 460px; text-align: center; }
.scan-frame {
  position: relative; margin: 0.75rem auto 0;
  width: 100%; max-width: 340px; aspect-ratio: 4/3;
  border-radius: var(--radius-md); overflow: hidden; background: #0b1220;
}
.scan-frame video { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Alvo só visual: o jsQR lê o quadro inteiro, a moldura é para a pessoa mirar. */
.scan-alvo {
  position: absolute; inset: 18%;
  border: 3px solid rgba(74, 222, 128, 0.9);
  border-radius: 10px; pointer-events: none;
}
.scan-msg { font-size: 0.85rem; color: var(--text-muted); margin: 0.75rem 0 0; min-height: 1.3em; }
.scan-msg.is-erro { color: var(--accent-danger, #f87171); font-weight: 600; }
.scan-ou { font-size: 0.75rem; color: var(--text-dim); margin: 0.9rem 0 0.5rem; text-transform: uppercase; letter-spacing: 0.08em; }
.scan-manual { display: flex; gap: 8px; }
.scan-manual .form-control {
  font-family: ui-monospace, monospace; font-size: 1.5rem; text-align: center;
  letter-spacing: 0.28em; font-weight: 700;
}
.scan-manual .btn { width: auto; padding: 10px 20px; flex-shrink: 0; }

/* Atalho de entrega de encomenda no painel da portaria. */
/* Código, câmera e "Entregar" numa linha só. O card fica na coluna estreita do
   painel, então quem cede espaço é o CAMPO (`flex: 1` com `min-width: 0`, sem o
   qual o input recusa encolher abaixo do tamanho do conteúdo e joga os botões
   para a linha de baixo) — os dois botões têm largura de conteúdo e não
   encolhem. Nada de `flex-wrap`: quebrar aqui é justamente o que se quer evitar. */
.port-enc { display: flex; gap: 8px; align-items: stretch; }
.port-enc .form-control {
  flex: 1; min-width: 0;
  font-family: ui-monospace, monospace; font-size: 1.25rem; text-align: center;
  letter-spacing: 0.22em; font-weight: 700;
  padding-left: 8px; padding-right: 8px;
}
.port-enc .btn { width: auto; padding: 9px 14px; flex-shrink: 0; }

/* Botão só de ícone: quadrado, do tamanho do campo ao lado. */
.port-enc-qr {
  display: flex; align-items: center; justify-content: center;
  width: 46px; padding: 0;
}
.port-enc-qr svg { width: 22px; height: 22px; display: block; }
.port-enc-msg { font-size: 0.8rem; line-height: 1.5; margin-top: 8px; min-height: 1.2em; color: var(--text-muted); }
.port-enc-msg.is-erro { color: var(--accent-danger, #f87171); }
.port-enc-msg.is-ok { color: var(--text-main); }
.port-enc-msg a { color: var(--accent-primary); font-weight: 600; }

/* O "N aguardando" do cabeçalho do card é um LINK para a página de encomendas.
   Herda a cor do título (em `body.portaria` o `.dash-card-title` é branco) em vez
   do azul de link do navegador, que sobre o card escuro fica ilegível.
   O padding negativo dá alvo de clique sem empurrar o título. */
.enc-link {
  display: inline-flex; align-items: center; gap: 6px;
  color: inherit; text-decoration: none;
  padding: 2px 6px; margin: -2px -6px; border-radius: var(--radius-sm);
  transition: background-color 0.15s ease;
}
.enc-link:hover { background: rgba(148, 163, 184, 0.18); text-decoration: underline; }
.enc-link:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 1px; }
.enc-link-ico { width: 13px; height: 13px; flex-shrink: 0; opacity: 0.75; }
.enc-link:hover .enc-link-ico { opacity: 1; }

/* Encomenda parada há +7 dias. O `.dev-summary` nunca teve o estado de alerta
   que o `painel.js` liga desde 25/08/2026 — o aviso existia no DOM e não
   aparecia na tela. Vence o `color` do `.enc-link` por especificidade. */
.dev-summary.stamp-warn { color: var(--accent-warning, #f59e0b); font-weight: 600; }

/* ⚠️ Os modais têm fundo BRANCO (`.modal-card`), mas as páginas de tema escuro
   redefinem --text-muted/--text-dim para tons CLAROS, que servem aos cards
   escuros delas. Dentro do modal isso vira branco sobre branco — foi
   exatamente o que aconteceu com o destinatário e o aviso do telefone.
   Aqui os tokens voltam aos tons escuros, só dentro do modal.

   Os dois modais de encomenda entram nesta lista SEM depender do `body`:
   eles nascem do `encomendas-form.js`, que é carregado também na PORTARIA —
   e lá o `body.encomendas` não existe para salvá-los. Regra por página não
   serve a um componente que viaja entre páginas. */
.modal-enc-form,
.modal-proto,
.modal-detalhe,
.modal-retira,
body.encomendas .modal-card {
  --text-muted: #475569;
  --text-dim: #64748b;
  --text-main: #1e293b;
  --border-color: #e2e8f0;
  --bg-secondary: #f1f5f9;
  --bg-primary: #f8fafc;
  --bg-card-hover: #e2e8f0;
}
body.encomendas .modal-card label { color: #334155; }
body.encomendas .modal-card .card-title { color: #0f172a; }
body.encomendas .modal-card .enc-foto-txt b { color: #1e293b; }
body.encomendas .modal-card .retira-nome { color: #0f172a; }
body.encomendas .modal-card .scan-msg { color: #475569; }
body.encomendas .modal-card .scan-ou { color: #64748b; }
/* A moldura do leitor continua escura: é vídeo, não texto. */
body.encomendas .modal-scan .scan-frame { background: #0b1220; }

/* Lista em largura cheia — o formulário saiu desta página para o modal. */
.enc-lista-wrap .card { margin: 0; max-width: none; }
.enc-lista-wrap .enc-lista { max-height: 58vh; }
.enc-receber-topo { width: auto; padding: 9px 18px; flex-shrink: 0; }

/* Modal de recebimento: largo e em duas colunas. A portaria roda em 768 px de
   altura e o balcão precisa ver TODOS os campos numa tela só, sem rolar com o
   entregador no balcão. "De onde veio" e o botão de registrar pegam a largura
   toda; o miolo (destinatário/sala/obs à esquerda, entregador/volumes/fotos à
   direita) se divide. Abaixo de 880 px volta a uma coluna e o
   `max-height: 88vh; overflow-y: auto` mais abaixo assume. */
.modal-enc-form { max-width: 980px; }
.enc-form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 1.75rem;
  align-items: start;
}
.enc-form-col { min-width: 0; }
.modal-enc-form .enc-volumes { max-width: 190px; }
@media (max-width: 880px) {
  .enc-form-grid { grid-template-columns: 1fr; }
}
body.portaria .modal-enc-form,
body.encomendas .modal-enc-form {
  --text-muted: #475569; --text-dim: #64748b; --text-main: #1e293b;
  --border-color: #e2e8f0; --bg-secondary: #f1f5f9;
  --bg-primary: #f8fafc; --bg-card-hover: #e2e8f0;
}
body.portaria .modal-enc-form label,
body.encomendas .modal-enc-form label { color: #334155; }
body.portaria .modal-enc-form .card-title,
body.encomendas .modal-enc-form .card-title { color: #0f172a; }
body.portaria .modal-enc-form .enc-foto-txt b { color: #1e293b; }
body.portaria .modal-enc-form .enc-hit-nome { color: #0f172a; }
body.portaria .modal-enc-form .enc-sel-nome { color: #0f172a; }

/* O "Receber" fica embaixo da busca, ocupando a largura do card. */
.port-enc-receber { width: 100%; margin-top: 6px; }

/* ==========================================================================
   MODAL DE RECEBIMENTO — ajustes que os tokens não alcançam

   ⚠️ `.form-control` tem `background: rgba(15,23,42,.6)` CRAVADO, não um token.
   Redefinir --bg-secondary no modal não muda nada: os campos continuavam
   azul-escuros sobre o card branco. Por isso o fundo é reescrito aqui.

   E o `.grid-2` global pede `minmax(280px, 1fr)`: dentro de uma COLUNA do modal
   (metade de ~900 px, menos padding) duas sub-colunas não cabem nesse mínimo e
   ele quebrava tudo em uma só — daí o minmax menor, como o `.modal-release` já
   fazia. Sala | Onde guardou fica lado a lado.
   ========================================================================== */
.modal-enc-form .grid-2 { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1rem; }

/* ⚠️ `.form-control` traz `background: rgba(15,23,42,.6)` FIXO — azul-noite, para
   os campos sobre os cards escuros das páginas. Num `.modal-card` BRANCO isso dá
   um campo escuro no meio da folha clara: era o CPF da retirada e o código do
   leitor de QR, dois campos que o operador precisa conferir enquanto digita.
   A cor não vem de token, então reverter os tokens (mais acima) não alcança —
   tem de ser regra própria, e vale para todos os modais claros de uma vez. */
.modal-enc-form .form-control,
.modal-retira .form-control,
.modal-detalhe .form-control,
.modal-scan .form-control,
.modal-proto .form-control {
  background: #ffffff;
  border-color: #cbd5e1;
  color: #0f172a;
}
.modal-enc-form .form-control::placeholder,
.modal-retira .form-control::placeholder,
.modal-scan .form-control::placeholder { color: #94a3b8; }
.modal-enc-form .form-control:focus,
.modal-retira .form-control:focus,
.modal-scan .form-control:focus { border-color: var(--accent-primary); }

/* Rótulos e título dos modais claros — mesma razão do bloco acima. */
.modal-retira label, .modal-detalhe label, .modal-scan label { color: #334155; }
.modal-retira .card-title, .modal-scan .card-title { color: #0f172a; }

/* Rede de segurança: em uma coluna (tela < 880 px ou muitos volumes) o
   formulário volta a ser alto e sem teto o botão de registrar sairia da tela.
   Em duas colunas, no monitor da portaria, não chega a rolar. */
.modal-enc-form { max-height: 92vh; overflow-y: auto; }

/* Os botões de origem e os cartões de foto herdavam o cinza-escuro do tema. */
.modal-enc-form .enc-origem { background: #f1f5f9; border-color: #cbd5e1; color: #334155; }
.modal-enc-form .enc-origem:hover { background: #e2e8f0; }
/* ⚠️ O estado SELECIONADO precisa desta linha para existir aqui dentro.
   `.enc-origem.is-on` (0,2,0) e `.modal-enc-form .enc-origem` (0,2,0) empatam
   em especificidade, e a segunda vem depois no arquivo — o clique marcava
   `is-on`, mas o fundo continuava cinza e parecia que a origem não deixava
   selecionar. Com `.modal-enc-form .enc-origem.is-on` (0,3,0) a cor volta. */
.modal-enc-form .enc-origem.is-on {
  background: var(--cor);
  border-color: var(--cor);
  color: var(--texto, #ffffff);
}
.modal-enc-form .enc-vol-btn { background: #f1f5f9; border-color: #cbd5e1; color: #334155; }
.modal-enc-form .enc-vol-btn:hover { background: #e2e8f0; }

/* Fotos dentro do modal: mais densas e mais baixas que na lista — elas moram
   numa coluna de ~440 px, e são o que faz o formulário crescer quando chegam
   muitos volumes. Assim 1 a 4 volumes não rolam; 6 fica no limite e o
   `max-height: 88vh` assume. */
.modal-enc-form .enc-fotos { grid-template-columns: repeat(auto-fill, minmax(138px, 1fr)); gap: 8px; }
.modal-enc-form .enc-foto-slot { background: #f8fafc; border-color: #cbd5e1; padding: 6px 8px; gap: 8px; }
.modal-enc-form .enc-foto-slot:hover { background: #eef2f7; }
.modal-enc-form .enc-foto-thumb { width: 34px; height: 44px; background: #e2e8f0; }
.modal-enc-form .enc-hits { background: #ffffff; border-color: #cbd5e1; }
.modal-enc-form .enc-hit { color: #0f172a; border-color: #e2e8f0; }
.modal-enc-form .enc-hit:hover { background: #f1f5f9; }
.modal-enc-form .enc-hit-sub { color: #64748b; }
.modal-enc-form .enc-selecionado { background: #eff6ff; }
.modal-enc-form .enc-dica { color: #64748b; }

/* ==========================================================================
   DASHBOARD ADMINISTRATIVO (dashboard.html)

   Lê só o espelho local (dashboard_db.py). O gate de administrador é do
   server.py — esta folha só desenha.
   ========================================================================== */
body.dashboard main { max-width: 1560px; margin: 0 auto; padding: 1.25rem 1rem; }
body.dashboard { --text-muted: #e2e8f0; --text-dim: #cbd5e1; }
body.dashboard .card, body.dashboard .dash-card, body.dashboard .kpi-tile,
body.dashboard .auth-container { color: #ffffff; }
body.dashboard .data-table th { color: #cbd5e1; }
body.dashboard label { color: #e2e8f0; }

.dash-h2 { font-weight: 700; font-size: 1.05rem; }
.dash-sub { font-size: 0.75rem; color: var(--text-dim); line-height: 1.4; }
/* ⚠️ Este bloco precisa da MESMA superfície escura dos cards. O fundo da
   página é a foto clara do prédio, e `body.dashboard` clareia --text-dim para
   ler bem DENTRO dos cards — nu sobre a foto, o subtítulo sumia por completo e
   o rótulo "escala" ficava ilegível. */
.dash-secao-titulo {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 12px;
  margin-bottom: 0.85rem;
  background: var(--bg-card); border: 1px solid var(--border-color);
  border-radius: var(--radius-lg); padding: 0.7rem 1rem;
}
.dash-escala { display: flex; align-items: center; gap: 8px; }
.dash-escala label { font-size: 0.75rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.05em; }
.dash-escala .form-control { width: 96px; padding: 0.4rem 0.6rem; text-align: center; font-variant-numeric: tabular-nums; }

/* Cadeado da tela de login — o dashboard não é "mais uma tela". */
.dash-cadeado {
  width: 52px; height: 52px; border-radius: 14px; margin-bottom: 1rem;
  background: rgba(239, 68, 68, 0.12); border: 1px solid rgba(239, 68, 68, 0.35);
  display: flex; align-items: center; justify-content: center; color: #f87171;
}
.dash-cadeado svg { width: 26px; height: 26px; }
.dash-aviso-login {
  margin-top: 1.25rem; padding-top: 1rem; border-top: 1px solid var(--border-color);
  font-size: 0.76rem; color: var(--text-dim); line-height: 1.5;
}
.dash-admin {
  display: inline-flex; align-items: center; gap: 7px; font-size: 0.8rem; font-weight: 600;
  padding: 6px 12px; border-radius: 20px; white-space: nowrap;
  background: rgba(239, 68, 68, 0.12); border: 1px solid rgba(239, 68, 68, 0.35); color: #fca5a5;
}
.dash-admin svg { width: 14px; height: 14px; }

.dash-abas { display: flex; gap: 6px; margin-bottom: 1.1rem; }
.dash-aba {
  border: 1px solid var(--border-color); background: var(--bg-secondary); color: var(--text-muted);
  font-family: inherit; font-size: 0.88rem; font-weight: 600; padding: 9px 18px;
  border-radius: var(--radius-md); cursor: pointer; transition: background 0.15s, color 0.15s;
}
.dash-aba:hover { background: var(--bg-card-hover); color: var(--text-main); }
.dash-aba.is-on { background: var(--accent-primary); border-color: var(--accent-primary); color: #fff; }
.dash-aba:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 2px; }

/* Medidores */
.medidores { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1rem; margin-bottom: 1.1rem; }
@media (max-width: 1150px) { .medidores { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.medidor { padding: 1rem 1.25rem 0.85rem; }
.medidor-rot { display: flex; align-items: center; gap: 8px; color: var(--text-muted); font-size: 0.8rem; font-weight: 600; }
.medidor-rot i { width: 9px; height: 9px; border-radius: 2px; flex-shrink: 0; }
.medidor-pe { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-top: -6px; }
.medidor-valor { font-size: 2rem; font-weight: 700; letter-spacing: -0.02em; line-height: 1.1; font-variant-numeric: tabular-nums; }
.medidor-pct { font-size: 0.75rem; color: var(--text-dim); font-variant-numeric: tabular-nums; }

.dash-cols { display: grid; grid-template-columns: minmax(0, 1.62fr) minmax(0, 1fr); gap: 1.1rem; align-items: start; margin-bottom: 1.1rem; }
.dash-cols-rel { display: grid; grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr); gap: 1.1rem; align-items: start; margin-bottom: 1.1rem; }
@media (max-width: 1150px) { .dash-cols, .dash-cols-rel { grid-template-columns: minmax(0, 1fr); } }
.dash-col-lado { display: flex; flex-direction: column; gap: 1.1rem; }

.dash-periodo { display: flex; gap: 4px; padding: 3px; background: rgba(15, 23, 42, 0.6); border-radius: 8px; }
.dash-periodo-btn {
  border: 0; background: transparent; color: var(--text-muted); font-family: inherit;
  font-size: 0.78rem; font-weight: 600; padding: 5px 12px; border-radius: 6px; cursor: pointer;
}
.dash-periodo-btn.is-on { background: var(--accent-primary); color: #fff; }
.dash-legenda { display: flex; gap: 18px; margin-top: 10px; font-size: 0.78rem; color: var(--text-muted); }
.dash-legenda span { display: inline-flex; align-items: center; gap: 6px; }
.dash-legenda i { width: 10px; height: 10px; border-radius: 2px; }

.dash-grande { font-size: 3.25rem; font-weight: 800; letter-spacing: -0.03em; line-height: 1; margin-top: 0.5rem; font-variant-numeric: tabular-nums; }
.dash-duplo { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 1rem; }
.dash-mini { background: rgba(15, 23, 42, 0.6); border: 1px solid var(--border-color); border-radius: var(--radius-md); padding: 10px 12px; }
.dash-mini-valor { font-size: 1.5rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.dash-mini-rot { font-size: 0.72rem; color: var(--text-muted); font-weight: 600; }

.dash-barras { display: flex; flex-direction: column; gap: 11px; margin-top: 0.75rem; }
.dash-barra-topo { display: flex; justify-content: space-between; align-items: baseline; font-size: 0.8rem; margin-bottom: 4px; font-weight: 600; }
.dash-barra-topo span:last-child { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.dash-barra-trilho { height: 7px; border-radius: 4px; background: var(--viz-grid); overflow: hidden; }
.dash-barra-trilho div { height: 100%; border-radius: 4px; }

/* Filtros */
.dash-filtros-card { margin: 0 0 1.1rem; max-width: none; }
.dash-filtros-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1rem; }
@media (max-width: 900px) { .dash-filtros-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.dash-filtros-chips { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.4rem; margin-top: 0.25rem; }
@media (max-width: 900px) { .dash-filtros-chips { grid-template-columns: minmax(0, 1fr); } }
.dash-rot { display: block; font-size: 0.74rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 7px; }
.dash-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.dash-chip {
  display: inline-flex; align-items: center; gap: 7px;
  border: 1px solid var(--border-color); background: rgba(15, 23, 42, 0.6); color: var(--text-dim);
  font-family: inherit; font-size: 0.8rem; font-weight: 600; padding: 7px 13px;
  border-radius: var(--radius-sm); cursor: pointer; transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.dash-chip i { width: 8px; height: 8px; border-radius: 2px; flex-shrink: 0; }
.dash-chip:hover { border-color: var(--accent-primary); }
.dash-chip.is-on { background: rgba(59, 130, 246, 0.16); border-color: var(--accent-primary); color: var(--text-main); }
.dash-chip:focus-visible { outline: 2px solid var(--accent-primary); outline-offset: 2px; }

.dash-exportar { display: flex; gap: 8px; }
.dash-exportar .btn { width: auto; padding: 8px 16px; font-size: 0.85rem; white-space: nowrap; }
.dash-paginacao { display: flex; gap: 8px; }
.dash-paginacao .btn { width: auto; padding: 7px 14px; font-size: 0.8rem; }
.dash-paginacao .btn:disabled { opacity: 0.4; cursor: not-allowed; }

.dash-empresas { display: flex; flex-direction: column; gap: 10px; margin-top: 0.75rem; }
.dash-empresa { display: flex; align-items: center; gap: 12px; }
/* ⚠️ nowrap + ellipsis: uma empresa que ocupa várias salas vem como
   "1502/1503/1504/1505" e, sem isto, quebrava em quatro linhas e esticava
   a barra inteira. A sala completa fica no title. */
.dash-empresa-sala { width: 52px; flex-shrink: 0; text-align: right; font-size: 0.76rem; color: var(--text-dim); font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dash-empresa-nome { width: 210px; flex-shrink: 0; font-size: 0.82rem; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dash-empresa-trilho { flex-grow: 1; height: 22px; background: rgba(255, 255, 255, 0.06); border-radius: 5px; overflow: hidden; }
.dash-empresa-trilho div { height: 100%; border-radius: 5px; background: var(--accent-primary); }
.dash-empresa-valor { width: 48px; flex-shrink: 0; text-align: right; font-weight: 700; font-size: 0.86rem; font-variant-numeric: tabular-nums; }

.dash-print-recorte { display: none; }

/* CPF das pessoas isentas de máscara — segunda linha da célula, discreta. */
.dash-cpf-aberto { display: block; font-weight: 400; font-size: 0.74rem;
  color: var(--text-dim); font-variant-numeric: tabular-nums; margin-top: 1px; }

.dash-tag { font-size: 0.74rem; font-weight: 700; padding: 3px 9px; border-radius: 10px; white-space: nowrap; }
.dash-tag.is-colab { background: rgba(59, 130, 246, 0.16); color: #93c5fd; }
.dash-tag.is-visit { background: rgba(167, 139, 250, 0.18); color: #c4b5fd; }

/* Impressão: só o relatório vai para o papel. */
@media print {
  body.dashboard header, body.dashboard .dash-abas, body.dashboard #painelTempoReal,
  body.dashboard .dash-exportar, body.dashboard .dash-paginacao, body.dashboard .nav-drawer,
  body.dashboard .nav-backdrop { display: none !important; }
  body.dashboard main { padding-left: 0 !important; max-width: none; }
  body.dashboard .table-scroll { max-height: none !important; overflow: visible !important; }

  /* ⚠️ Sem isto o relatório sai BRANCO NO BRANCO: a tela é clara sobre fundo
     escuro e o navegador não imprime cor de fundo por padrão, então só restava
     o texto claro sobre o papel. Impressão tem paleta própria. */
  body.dashboard, body.dashboard .card, body.dashboard .dash-card {
    background: #fff !important; color: #111 !important;
    border-color: #d4d4d4 !important; box-shadow: none !important;
  }
  body.dashboard .dash-sub, body.dashboard .dash-rot,
  body.dashboard .data-table td, body.dashboard .data-table th,
  body.dashboard .dash-empresa-nome, body.dashboard .dash-empresa-sala,
  body.dashboard .dash-empresa-valor, body.dashboard .kpi-label { color: #333 !important; }
  body.dashboard .data-table th { border-bottom: 1px solid #999 !important; }
  body.dashboard .data-table tr { border-bottom: 1px solid #e5e5e5 !important; }
  body.dashboard .kpi-value { color: #111 !important; }
  /* A tabela não pode partir uma linha ao meio entre duas páginas. */
  body.dashboard .data-table tr { break-inside: avoid; page-break-inside: avoid; }
  body.dashboard .data-table thead { display: table-header-group; }
  /* Barras e tags viram contorno: área chapada de cor gasta tinta e nem sempre
     é impressa. */
  body.dashboard .dash-barra-trilho, body.dashboard .dash-empresa-trilho {
    background: #eee !important; border: 1px solid #ccc !important;
  }
  body.dashboard .dash-tag { border: 1px solid #999 !important; color: #111 !important;
    background: transparent !important; }

  /* A marca d'água é `position: fixed`, e no papel isso se repete em TODA
     página — o PDF de 6 folhas foi de 4,7 MB por causa dela. */
  body.dashboard::before { display: none !important; }

  /* O formulário de filtro não serve no papel: sai como caixas cinzas vazias e
     os rótulos ficam claros sobre o branco. No lugar dele vai uma linha
     descrevendo o recorte, que é o que um relatório impresso precisa dizer. */
  body.dashboard .dash-filtros-grid,
  body.dashboard .dash-filtros-chips { display: none !important; }
  body.dashboard .dash-print-recorte {
    display: block; font-size: 0.82rem; color: #333 !important;
    padding: 0.5rem 0 0.15rem; border-top: 1px solid #ddd; margin-top: 0.5rem;
  }

  /* Os KPIs têm superfície própria e ficavam escuros com texto claro. */
  body.dashboard .kpi-tile {
    background: #fff !important; border: 1px solid #d4d4d4 !important;
    color: #111 !important; break-inside: avoid;
  }
  body.dashboard .kpi-row { break-inside: avoid; }
  body.dashboard .kpi-context { color: #444 !important; }
  /* "DATA E HORA" quebrava em três linhas e empurrava o cabeçalho todo. */
  body.dashboard .data-table th { white-space: nowrap; }
  body.dashboard .doctors-count-badge {
    background: transparent !important; color: #333 !important;
    border: 1px solid #999 !important;
  }
  /* Cabeçalho da tabela: fundo escuro com texto claro vira preto sobre branco. */
  body.dashboard .data-table thead, body.dashboard .data-table thead th {
    background: #fff !important; color: #111 !important;
  }
  /* O número ao lado da barra herdava o cinza-claro da tela. */
  body.dashboard .dash-barra-topo, body.dashboard .dash-barra-topo span {
    color: #111 !important;
  }
  body.dashboard .pill { border: 1px solid #999 !important; background: transparent !important;
    color: #111 !important; }
}
