/* =====================================================================
   Gestão de Acesso Condominial — Design System v2
   CSS puro, mobile-first, com tema claro e escuro.
   ===================================================================== */

/* ═══════════════════════════════════════════════════════════════════════
   ⚠ `hidden` PRECISA VENCER — SEMPRE. O `[hidden]{display:none}` que o
   navegador traz é da folha do USER AGENT, e QUALQUER regra de classe nossa
   com `display` ganha dele (folha de autor vence a do UA, mesma
   especificidade). Sem esta linha, um elemento que nasce `hidden` — botão que
   só serve com JS, aviso vazio, contador zerado — aparece na tela E NÃO FAZ
   NADA. Aconteceu 4 vezes: paginador (§3), `.cam-msg` (§5.55.9), o botão de
   gravar áudio e o de escanear QR. `!important` aqui não é força bruta: é a
   afirmação de que escondido é escondido.
   ═══════════════════════════════════════════════════════════════════════ */
[hidden]{ display:none !important; }

:root {
  /* Paleta base (tema claro) */
  --bg: #eef1f7;
  --bg-grad-1: #eef2fb;
  --bg-grad-2: #f5f7fc;
  --surface: #ffffff;
  --surface-2: #f5f7fb;
  --surface-3: #eef1f6;
  --border: #e4e8f0;
  --border-strong: #d4dae6;
  --text: #131a26;
  --text-soft: #4c5666;
  --text-faint: #5f6b79; /* >= 4.5:1 sobre superfícies claras (WCAG AA texto pequeno) */

  --primary: #3b6ef5;
  --primary-dark: #2a52c9;
  --primary-soft: #e7eefe;
  --primary-grad-1: #4f7bf7;
  --primary-grad-2: #6a8ffb;

  --success: #15a05a;
  --success-soft: #e3f6ec;
  --warning: #d98309;
  --warning-soft: #fdf1df;
  --danger: #e0443e;
  --danger-soft: #fdeae9;
  --info: #3b6ef5;
  --info-soft: #e7eefe;
  --neutral: #64748b;
  --neutral-soft: #eef1f6;

  /* ---- Cores de TEXTO de status (WCAG AA sobre fundo claro/*-soft) ----
     As cores acima (--success/--warning/…) são de ACENTO: servem para barras,
     pontos e ícones grandes. Como TEXTO pequeno elas reprovam em AA (o --warning
     nem chega a 3:1 sobre branco). Estes tokens são as versões escuras, medidas
     para >= 4.5:1 sobre a superfície e sobre o respectivo *-soft. */
  --success-text: #0c7a44;   /* 4.86:1 sobre --success-soft */
  --warning-text: #96590a;   /* 5.04:1 sobre --warning-soft */
  --danger-text:  #b8322c;   /* 5.06:1 sobre --danger-soft  */
  --info-text:    #2a52c9;   /* 6.6:1 sobre --info-soft     */
  --neutral-text: #4c5666;   /* 7.4:1 sobre --neutral-soft  */
  --accent-text:  #2a52c9;   /* links/realces sobre superfície (o --primary dá 4.44:1: reprova) */

  /* ---- Botões sólidos ----
     Texto sobre cor cheia. No claro: tinta BRANCA sobre fundo escurecido.
     No escuro: tinta ESCURA sobre a cor viva (padrão de dark UI) — assim o botão
     mantém a cor forte SEM texto ilegível. */
  --on-accent: #ffffff;
  --btn-primary-bg: #2a52c9;  /* 6.6:1 com texto branco */
  --btn-success-bg: #0c7040;  /* 6.1:1 */
  --btn-danger-bg:  #c03530;  /* 5.5:1 */
  --btn-warning-bg: #96570a;  /* 5.7:1 — o --warning cru daria 2.9:1 */

  /* ---- Geometria (revisão 2026-07: linguagem mais "enterprise") ----
     Antes: raio 16/10/22px + sombras fortes (cara de app de consumo).
     Agora: raio menor e sombra sutil — a hierarquia vem da BORDA e do espaçamento,
     não da sombra. Mais denso, mais legível em telas cheias de dados. */
  --radius: 10px;      /* cards, tabelas, modais */
  --radius-sm: 6px;    /* botões, inputs, chips */
  --radius-lg: 14px;   /* modais grandes */
  --radius-xs: 4px;    /* badges, tags */
  --shadow-xs: 0 1px 2px rgba(18,26,40,.04);
  --shadow: 0 1px 3px rgba(18,26,40,.06);
  --shadow-md: 0 4px 12px rgba(18,26,40,.08);
  --shadow-lg: 0 12px 32px rgba(18,26,40,.14);
  --ring: 0 0 0 3px var(--primary-soft);

  --bottom-nav-h: 64px;
  --sidebar-w: 244px;
  --header-h: 60px;

  --icon: 20px;

  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color-scheme: light;
}

/* ---------- Tema escuro ---------- */
:root[data-theme="dark"] {
  --bg: #0e1320;
  --bg-grad-1: #0d1220;
  --bg-grad-2: #121a2c;
  --surface: #161d2e;
  --surface-2: #1c2638;
  --surface-3: #222d42;
  --border: #283248;
  --border-strong: #35415b;
  --text: #eaeef6;
  --text-soft: #b8c5d6; /* contraste AA p/ texto pequeno no dark */
  --text-faint: #8b97ad; /* clareado: o antigo #6f7c93 dava 3.3:1 sobre --surface-3 (reprovava) */

  --primary: #6a8ffb;
  --primary-dark: #5379e8;
  --primary-soft: #1d2a48;
  --primary-grad-1: #5b82f6;
  --primary-grad-2: #7aa0fc;

  --success: #34c97e;
  --success-soft: #11321f;
  --warning: #e0a33c;
  --warning-soft: #34270f;
  --danger: #f1736d;
  --danger-soft: #371a1a;
  --info: #6a8ffb;
  --info-soft: #1d2a48;
  --neutral: #93a0b6;
  --neutral-soft: #222d42;

  /* No escuro os fundos *-soft são MUITO escuros, então a própria cor viva já
     passa em AA como texto — não precisa da versão escurecida do tema claro. */
  --success-text: var(--success);
  --warning-text: var(--warning);
  --danger-text:  var(--danger);
  --info-text:    var(--info);
  --neutral-text: var(--neutral);
  --accent-text:  var(--primary);

  /* Botão sólido no escuro: cor viva + tinta ESCURA (texto branco sobre estas
     cores claras dava 2.1–3.5:1). */
  --on-accent: #0d1220;
  --btn-primary-bg: var(--primary);
  --btn-success-bg: var(--success);
  --btn-danger-bg:  var(--danger);
  --btn-warning-bg: var(--warning);   /* 8.4:1 sobre a tinta escura */

  --shadow-xs: 0 1px 2px rgba(0,0,0,.3);
  --shadow: 0 1px 3px rgba(0,0,0,.35);
  --shadow-md: 0 4px 14px rgba(0,0,0,.4);
  --shadow-lg: 0 14px 36px rgba(0,0,0,.55);
  --ring: 0 0 0 3px rgba(106,143,251,.25);
  color-scheme: dark;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  /* Fundo LISO (era um gradiente radial forte): num sistema de dados, o fundo
     não deve competir com o conteúdo. */
  background: var(--bg);
  color: var(--text);
  font-size: 14px;               /* mais denso (era 15px) */
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
/* ⚠ O atributo [hidden] TEM QUE GANHAR de qualquer `display` nosso.
   A regra do navegador é `[hidden] { display: none }` — especificidade (0,1,0),
   perde para QUALQUER classe (0,1,0 empata e vence quem vier depois... e as
   nossas vêm depois). Foi assim que o `.flash { display:flex }` deixou visível o
   `<div id="wErr" class="flash flash-error" hidden>` da tela de água: uma FAIXA
   VERMELHA VAZIA, sem erro nenhum, em toda visita. Vale para todo elemento que o
   JS mostra/esconde via `.hidden = false` (wErr, notifBadge, …). */
[hidden] { display: none !important; }

a { color: var(--accent-text); text-decoration: none; }
h1,h2,h3,h4 { margin: 0 0 .4em; line-height: 1.22; letter-spacing: -.01em; }
h1 { font-size: 1.55rem; font-weight: 750; }
h2 { font-size: 1.2rem; font-weight: 700; }
h3 { font-size: 1.02rem; font-weight: 700; }
small { color: var(--text-faint); }
svg { display: inline-block; vertical-align: middle; }

/* ---------- Layout shell ---------- */
.app-shell { min-height: 100vh; display: flex; flex-direction: column; }
.app-header {
  position: sticky; top: 0; z-index: 30;
  background: var(--surface);
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 12px;
  padding: 0 16px; min-height: var(--header-h);
}
/* Marca: o logo vem do H::brandLogo() (símbolo SVG + wordmark). O `.dot` antigo
   saiu — o símbolo já é o ponto de cor do header. */
.app-header .brand { font-weight: 700; font-size: 1.04rem; display: flex; align-items: center; letter-spacing: -.01em; color: var(--text); text-decoration: none; }
.app-header .brand:hover { color: var(--text); }
.app-header .spacer { flex: 1; }
.app-header .user-chip { text-align: right; line-height: 1.15; }
.app-header .user-chip .name { font-weight: 650; font-size: .9rem; }
.app-header .user-chip .role { font-size: .72rem; color: var(--text-faint); }
.env-tag { font-size: .72rem; padding: 3px 9px; border-radius: 999px; background: var(--warning-soft); color: var(--warning-text); font-weight: 800; letter-spacing: .03em; }

/* Botão de tema (e demais ícones do header) — alvo de toque confortável. */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 11px; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--text-soft);
  transition: background .15s, color .15s, transform .15s;
}
@media (pointer: coarse) { .theme-toggle { width: 44px; height: 44px; } }
/* Botão de PÂNICO: precisa ser inconfundível no meio dos ícones do header. */
.theme-toggle.panic-btn { border-color: var(--danger); background: var(--danger-soft); color: var(--danger-text); }
.theme-toggle.panic-btn:hover { background: var(--danger); color: #fff; }
.theme-toggle:hover { color: var(--text); background: var(--surface-3); }
.theme-toggle svg { width: 19px; height: 19px; }

/* Sino de notificações */
.notif-wrap { position: relative; display: inline-flex; }
.notif-badge { position: absolute; top: -4px; right: -4px; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 999px; background: var(--danger, #d23b3b); color: #fff; font-size: .66rem; font-weight: 800; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 2px var(--surface); }
.notif-panel { position: absolute; top: 46px; right: 0; width: 320px; max-width: 88vw; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); z-index: 70; overflow: hidden; }
.notif-head { padding: 10px 14px; font-weight: 700; font-size: .82rem; border-bottom: 1px solid var(--border); color: var(--text-soft); }
.notif-empty { padding: 18px 14px; text-align: center; color: var(--text-faint); font-size: .85rem; }
.notif-item { display: flex; align-items: center; gap: 9px; padding: 11px 14px; border-bottom: 1px solid var(--border); color: inherit; text-decoration: none; font-size: .86rem; }
.notif-item:last-child { border-bottom: none; }
.notif-item:hover { background: var(--surface-2); }
.notif-item .notif-mk { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; background: var(--text-faint); }
.notif-item.danger .notif-mk { background: var(--danger); }
.notif-item.warning .notif-mk { background: var(--warning); }
.notif-item.info .notif-mk { background: var(--primary); }
.theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: inline-block; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: none; }

.app-body { flex: 1; display: flex; }
.sidebar { display: none; }
.main {
  flex: 1; min-width: 0;
  padding: 18px 16px calc(var(--bottom-nav-h) + 22px);
  max-width: 1120px; margin: 0 auto; width: 100%;
}

/* ---------- Bottom nav (mobile) ---------- */
.bottom-nav {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 40;
  height: var(--bottom-nav-h);
  background: var(--surface);
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-top: 1px solid var(--border);
  display: flex; justify-content: space-around; align-items: stretch;
  padding-bottom: env(safe-area-inset-bottom);
}
/* O item "Menu" é um <button> (abre o drawer); os demais são links. */
.bottom-nav a, .bottom-nav button {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; color: var(--text-faint); font-size: .72rem; font-weight: 650;
  position: relative; transition: color .15s;
  background: none; border: 0; cursor: pointer; font-family: inherit; padding: 0;
}
.bottom-nav a.active { color: var(--accent-text); }
.bottom-nav a.active::before { content: ""; position: absolute; top: 0; width: 26px; height: 3px; border-radius: 0 0 3px 3px; background: var(--primary); }
.bottom-nav a svg, .bottom-nav button svg { width: 23px; height: 23px; }

/* ---------- Cards ---------- */
/* A hierarquia vem da BORDA (não da sombra): card liso, borda 1px, sombra mínima. */
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-xs);
  padding: 16px; margin-bottom: 12px;
}
.card.tight { padding: 12px 14px; }
.card-title { font-size: .78rem; text-transform: uppercase; letter-spacing: .04em; color: var(--text-faint); font-weight: 700; margin-bottom: 10px; }

.stat-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; margin-bottom: 16px; }
/* Três números lado a lado DENTRO de um card (a conta da lojinha na ficha da
   estadia). ⚠ Não é `.stat-grid`: aquele é o bloco de KPIs da PÁGINA, com
   cartão, borda e barra de acento. Aqui os números moram dentro de um card que
   já existe — repetir a moldura criaria cartão dentro de cartão.
   ⚠ Estava no `$classeHook` do static_check como se fosse gancho de JS e não
   é: é LAYOUT, e sem regra os três números empilhavam um embaixo do outro.
   Silenciar o check em vez de escrever a regra é o erro que o §5.93 descreve. */
.kpi-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
@media (max-width: 520px) { .kpi-row { grid-template-columns: 1fr; gap: 8px; } }
.stat {
  position: relative; overflow: hidden;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 16px; box-shadow: var(--shadow); display: block;
  transition: transform .15s, box-shadow .15s, border-color .15s;
}
.stat:hover { box-shadow: var(--shadow); border-color: var(--border-strong); }
.stat::after { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: var(--neutral); opacity: .85; }
.stat .label { font-size: .77rem; color: var(--text-soft); font-weight: 650; }
.stat .value { font-size: 1.85rem; font-weight: 820; margin-top: 4px; letter-spacing: -.02em; }
.stat.accent-green::after { background: var(--success); }
.stat.accent-orange::after { background: var(--warning); }
.stat.accent-red::after { background: var(--danger); }
.stat.accent-blue::after { background: var(--primary); }
.stat.accent-green .value { color: var(--success-text); }
.stat.accent-orange .value { color: var(--warning-text); }
.stat.accent-red .value { color: var(--danger-text); }
.stat.accent-blue .value { color: var(--accent-text); }

/* ---------- List cards (mobile) ---------- */
.list-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 15px; margin-bottom: 11px;
  transition: transform .12s, box-shadow .12s, border-color .12s;
}
.list-card:hover { box-shadow: var(--shadow-md); border-color: var(--border-strong); }
.list-card .lc-title { font-weight: 720; font-size: 1rem; }
.list-card .lc-sub { color: var(--text-soft); font-size: .85rem; margin-top: 2px; }
.list-card .lc-meta { color: var(--text-faint); font-size: .82rem; margin-top: 4px; }

/* Miniatura de foto em linhas de lista (pessoas/veículos) */
.rowthumb { width: 42px; height: 42px; border-radius: 10px; object-fit: cover; background: var(--surface-3); border: 1px solid var(--border); flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; }
.rowthumb-empty { color: var(--text-faint); font-weight: 800; font-size: 1rem; }
.data td .rowthumb { width: 38px; height: 38px; border-radius: 8px; }
.list-card .lc-actions { margin-top: 11px; display: flex; gap: 8px; flex-wrap: wrap; }

/* ---------- Badges ---------- */
.badge {
  display: inline-flex; align-items: center; gap: 5px; padding: 3px 10px; border-radius: 999px;
  font-size: .71rem; font-weight: 750; white-space: nowrap; line-height: 1.5;
  background: var(--neutral-soft); color: var(--neutral);
}
.badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; opacity: .9; }
.badge-success { background: var(--success-soft); color: var(--success-text); }
.badge-warning { background: var(--warning-soft); color: var(--warning-text); }
.badge-danger  { background: var(--danger-soft); color: var(--danger-text); }
.badge-info    { background: var(--info-soft); color: var(--info-text); }
.badge-neutral { background: var(--neutral-soft); color: var(--neutral-text); }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  font-size: .875rem; font-weight: 600; cursor: pointer; line-height: 1.2;
  padding: 8px 15px; border-radius: var(--radius-sm);
  border: 1px solid transparent; background: var(--surface-2); color: var(--text);
  transition: box-shadow .12s, filter .12s, background .12s, border-color .12s; text-align: center;
}
/* Sem "pulo" no hover (era translateY -1px): num painel denso isso vira ruído.
   O feedback vem do brilho/sombra. */
.btn:hover { filter: brightness(1.06); }
.btn:active { filter: brightness(.96); }
.btn:disabled { opacity: .6; cursor: not-allowed; transform: none; }
.btn-primary { background: var(--btn-primary-bg); color: var(--on-accent); }
.btn-primary:hover { box-shadow: var(--shadow); }
.btn-secondary { background: var(--surface); color: var(--text); border-color: var(--border-strong); }
.btn-secondary:hover { background: var(--surface-2); }
.btn-danger { background: var(--btn-danger-bg); color: var(--on-accent); }
.btn-success { background: var(--btn-success-bg); color: var(--on-accent); }
.btn-ghost { background: transparent; color: var(--accent-text); padding: 8px 11px; }
.btn-ghost:hover { background: var(--primary-soft); }
.btn-sm { padding: 7px 13px; font-size: .82rem; border-radius: 9px; }
.btn-block { width: 100%; }
.btn-row { display: flex; gap: 10px; flex-wrap: wrap; }

/* ---------- Forms ---------- */
.field { margin-bottom: 15px; }
.field label { display: block; font-weight: 650; font-size: .85rem; margin-bottom: 6px; color: var(--text-soft); }
.field .hint { font-size: .76rem; color: var(--text-faint); margin-top: 5px; }
.input, .select, .textarea {
  width: 100%; padding: 11px 13px; font-size: .95rem; color: var(--text);
  background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  font-family: inherit; transition: border-color .15s, box-shadow .15s;
}
.input::placeholder, .textarea::placeholder { color: var(--text-faint); }
.input:focus, .select:focus, .textarea:focus { outline: none; border-color: var(--primary); box-shadow: var(--ring); }
.textarea { min-height: 84px; resize: vertical; }
.field-error { color: var(--danger-text); font-size: .78rem; margin-top: 4px; font-weight: 600; }
/* Legenda de obrigatórios (o "*" sozinho não é anunciado nem óbvio). */
.form-required-note { font-size: .8rem; color: var(--text-faint); margin: 0 0 12px; }
.form-grid { display: grid; grid-template-columns: 1fr; gap: 0 15px; }

.day-picker { display: flex; gap: 6px; flex-wrap: wrap; }
.day-picker label {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  cursor: pointer; font-size: .8rem; font-weight: 700; user-select: none; transition: all .12s;
}
.day-picker input { position: absolute; opacity: 0; width: 0; height: 0; }
.day-picker label:has(input:checked) { background: var(--btn-primary-bg); border-color: var(--btn-primary-bg); color: var(--on-accent); }
/* O input real tem 0x0 — sem isto o anel de foco fica invisível no teclado. */
.day-picker label:has(input:focus-visible) { outline: 2px solid var(--primary); outline-offset: 2px; }

/* ---------- Tables (desktop) ---------- */
.table-wrap { overflow-x: auto; border-radius: var(--radius); box-shadow: var(--shadow); }
table.data { width: 100%; border-collapse: collapse; background: var(--surface); border-radius: var(--radius); overflow: hidden; }
/* Densidade maior (era 12x15): num sistema de dados cabem mais linhas sem rolar. */
table.data th, table.data td { text-align: left; padding: 9px 14px; border-bottom: 1px solid var(--border); font-size: .875rem; }
table.data th { background: var(--surface-2); font-size: .74rem; text-transform: uppercase; letter-spacing: .03em; color: var(--text-faint); font-weight: 700; }
table.data tr:last-child td { border-bottom: none; }
table.data tbody tr { transition: background .12s; }
table.data tbody tr:hover td { background: var(--surface-2); }

/* ---------- Flash / alerts ---------- */
.flash { padding: 13px 15px; border-radius: var(--radius-sm); margin-bottom: 14px; font-size: .9rem; font-weight: 550; border: 1px solid transparent; display: flex; gap: 9px; align-items: flex-start; }
.flash .flash-close {
  margin-left: auto; background: none; border: 0; cursor: pointer; color: inherit;
  font-size: 1.15rem; line-height: 1; opacity: .65;
  /* Era ~18x22px: alvo pequeno demais, e é o ÚNICO jeito de fechar um erro
     (que não some sozinho). */
  min-width: 32px; min-height: 32px; display: inline-flex; align-items: center; justify-content: center;
  border-radius: 8px; flex: 0 0 auto;
}
.flash .flash-close:hover { opacity: 1; background: color-mix(in srgb, currentColor 12%, transparent); }
@media (pointer: coarse) { .flash .flash-close { min-width: 44px; min-height: 44px; } }
.flash-success { background: var(--success-soft); color: var(--success-text); border-color: color-mix(in srgb, var(--success) 30%, transparent); }
.flash-error { background: var(--danger-soft); color: var(--danger-text); border-color: color-mix(in srgb, var(--danger) 30%, transparent); }
/* Sucesso COM RESSALVA (aconteceu, mas confira). Cor de TEXTO --warning-text:
   a de acento (--warning) sobre o soft dá 2,6:1 e reprova AA. */
.flash-warning { background: var(--warning-soft); color: var(--warning-text); border-color: color-mix(in srgb, var(--warning) 30%, transparent); }
.alert { padding: 12px 14px; border-radius: var(--radius-sm); font-size: .85rem; margin-bottom: 12px; border: 1px solid transparent; }
.alert-warning { background: var(--warning-soft); color: var(--warning-text); border-color: color-mix(in srgb, var(--warning) 25%, transparent); }
.alert-danger { background: var(--danger-soft); color: var(--danger-text); border-color: color-mix(in srgb, var(--danger) 25%, transparent); }
.alert-info { background: var(--info-soft); color: var(--info-text); border-color: color-mix(in srgb, var(--info) 25%, transparent); }

/* ---------- Page header ---------- */
.page-head { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
/* O título da tela é SEMPRE <h1> (era <h2> em 56 telas, que ficavam sem h1 nenhum
   e quebravam a navegação por headings). Tamanho normalizado aqui para que a
   promoção h2->h1 não deixe os títulos gigantes. */
.page-head h1 { margin: 0; font-size: 1.35rem; font-weight: 750; display: flex; align-items: center; gap: 9px; }
.page-head .spacer { flex: 1; }

/* ---------- Empty state ---------- */
.empty { text-align: center; padding: 40px 16px; color: var(--text-soft); }
.empty .icon { font-size: 2rem; margin-bottom: 8px; }
.empty p { margin: 4px 0 16px; font-weight: 550; }

/* ---------- Search ---------- */
.search-box { position: relative; margin-bottom: 14px; }
.search-box input { padding-left: 40px; }
.search-box .si { position: absolute; left: 13px; top: 50%; transform: translateY(-50%); color: var(--text-faint); }

/* ---------- Filters ---------- */
.filters { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 16px; }
.filters .input, .filters .select { width: auto; min-width: 120px; flex: 1 1 140px; }

/* ---------- Pagination ---------- */
.pagination { display: flex; gap: 6px; justify-content: center; margin: 18px 0; flex-wrap: wrap; }
.pagination a, .pagination span {
  padding: 8px 13px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface); font-size: .85rem; font-weight: 650; color: var(--text-soft);
}
.pagination a:hover { background: var(--surface-2); }
.pagination .current { background: var(--btn-primary-bg); color: var(--on-accent); border-color: var(--btn-primary-bg); }
.pagination { margin: 12px 0 0; }

/* Rodapé de listagem: seletor "por página" + paginação */
.list-foot { display: flex; flex-direction: column; align-items: center; gap: 6px; margin: 16px 0 4px; }
.perpage { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: center; margin: 0; }
.perpage-label { display: inline-flex; align-items: center; gap: 6px; font-size: .85rem; color: var(--text-soft); font-weight: 600; }
.perpage .select { width: auto; min-width: 76px; padding-top: 6px; padding-bottom: 6px; }
.perpage-total { font-size: .8rem; color: var(--text-faint); }

/* ---------- Chaves (acionar portões) ---------- */
.key-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 14px; }
.key-card {
  position: relative; display: flex; flex-direction: column; gap: 8px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: 16px; box-shadow: var(--shadow); transition: transform .12s ease, box-shadow .12s ease, border-color .12s ease;
}
.key-card:hover { box-shadow: var(--shadow-md); border-color: var(--border-strong); }
.key-card.is-off { opacity: .72; }
.key-top { display: flex; align-items: center; justify-content: space-between; }
.key-ico {
  display: inline-flex; align-items: center; justify-content: center; width: 42px; height: 42px;
  border-radius: 12px; color: #fff; background: linear-gradient(135deg, var(--primary), var(--primary-strong, var(--primary)));
  box-shadow: 0 4px 12px rgba(0,0,0,.18);
}
.key-card.is-off .key-ico { background: var(--surface-2); color: var(--text-faint); box-shadow: none; }
.key-status { font-size: .72rem; font-weight: 700; padding: 3px 9px; border-radius: 999px; letter-spacing: .02em; }
.key-status.on { color: var(--success-text); background: var(--success-soft); }
.key-status.off { color: var(--danger-text); background: var(--danger-soft); }
.key-name { font-size: 1.04rem; font-weight: 750; line-height: 1.2; }
.key-desc { font-size: .82rem; color: var(--text-soft); line-height: 1.35; }
.key-foot { margin-top: auto; padding-top: 6px; }
.key-btn { width: 100%; display: inline-flex; align-items: center; justify-content: center; padding-top: 11px; padding-bottom: 11px; font-weight: 700; }
@media (max-width: 560px) {
  .key-grid { grid-template-columns: 1fr; gap: 11px; }
  .key-card { padding: 14px; }
}

/* ---------- Modal ---------- */
.modal-overlay { position: fixed; inset: 0; background: rgba(8,12,22,.55); backdrop-filter: blur(3px); z-index: 60; display: flex; align-items: center; justify-content: center; padding: 16px; animation: fade .15s ease; }
/* Respeita o atributo [hidden]: sem isto o display:flex acima deixaria o modal
   sempre visível (era por isso que o modal de captura de foto abria sozinho na
   edição de pessoa). Especificidade (0,2,0) vence a regra base (0,1,0). */
.modal-overlay[hidden] { display: none; }
.modal { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); padding: 22px; width: 100%; max-width: 430px; animation: pop .16s ease; }
.modal h3 { margin-bottom: 8px; }
.modal p { color: var(--text-soft); font-size: .92rem; }
.modal .modal-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 18px; }
@keyframes fade { from { opacity: 0; } }
@keyframes pop { from { opacity: 0; transform: translateY(8px) scale(.98); } }

/* ---------- Detail sections ---------- */
.section { margin-bottom: 18px; }
.kv { display: grid; grid-template-columns: 140px 1fr; gap: 8px 16px; font-size: .9rem; }
.kv dt { color: var(--text-faint); font-weight: 650; }
.kv dd { margin: 0; }

.wizard-steps { display: flex; gap: 6px; margin-bottom: 18px; }
.wizard-steps .step { flex: 1; text-align: center; font-size: .73rem; font-weight: 800; color: var(--text-faint); padding-bottom: 9px; border-bottom: 3px solid var(--border); transition: all .15s; }
.wizard-steps .step.active { color: var(--accent-text); border-color: var(--primary); }
.wizard-steps .step.done { color: var(--success-text); border-color: var(--success); }

.muted { color: var(--text-faint); }
.text-right { text-align: right; }
.mt { margin-top: 14px; }
.mb { margin-bottom: 14px; }
.hide { display: none; }
code { background: var(--surface-3); padding: 2px 6px; border-radius: 6px; font-size: .85em; }

/* ---------- Desktop ---------- */
@media (min-width: 860px) {
  .bottom-nav { display: none; }
  .sidebar {
    display: block; width: var(--sidebar-w); flex-shrink: 0;
    background: var(--surface); border-right: 1px solid var(--border);
    padding: 14px 12px; position: sticky; top: var(--header-h); height: calc(100vh - var(--header-h)); overflow-y: auto;
  }
  .sidebar .group-label { font-size: .67rem; text-transform: uppercase; letter-spacing: .06em; color: var(--text-faint); font-weight: 800; padding: 16px 12px 6px; }
  .sidebar a.nav-item {
    display: flex; align-items: center; gap: 11px; padding: 9px 12px; border-radius: var(--radius-sm);
    color: var(--text-soft); font-weight: 650; font-size: .9rem; margin-bottom: 2px; transition: background .12s, color .12s;
  }
  .sidebar a.nav-item:hover { background: var(--surface-2); color: var(--text); }
  .sidebar a.nav-item.active { background: var(--primary-soft); color: var(--primary-dark); }
  :root[data-theme="dark"] .sidebar a.nav-item.active { color: var(--primary); }
  .main { padding: 24px 28px 32px; max-width: none; }
  .form-grid.cols-2 { grid-template-columns: 1fr 1fr; }
  .stat-grid { grid-template-columns: repeat(4, 1fr); }
  .mobile-only { display: none !important; }
}
@media (max-width: 859px) {
  .desktop-only { display: none !important; }
}

/* ---------- Accordion de navegação (sidebar desktop + drawer mobile) ---------- */
/* Cada seção é um <details>; o <summary> é o cabeçalho. SÓ UMA seção fica aberta
   por vez (app.js → initNavAccordion); sem JS, o servidor já abre só a da tela
   atual. Resolve o "não cabe na tela" com muitos módulos.

   ⚠ O cabeçalho é um RÓTULO DE SEÇÃO, não um item de menu. Por isso ele NÃO tem
   ícone à esquerda (só os itens têm), NÃO ganha pílula de fundo no hover e usa
   um tamanho/cor próprios. Antes ele era ícone + texto + pílula — visualmente
   idêntico a um item, e o usuário clicava achando que ia para algum lugar. */
.nav-group { margin: 0; }
.nav-group + .nav-group { border-top: 1px solid var(--border); }
.nav-group > summary.nav-group-head {
  display: flex; align-items: center; gap: 8px; cursor: pointer; list-style: none;
  padding: 11px 12px 9px; border-radius: 0; background: none;
  font-size: .68rem; text-transform: uppercase; letter-spacing: .1em;
  color: var(--text-faint); font-weight: 800; user-select: none;
  transition: color .12s;
}
.nav-group > summary.nav-group-head::-webkit-details-marker { display: none; } /* Safari: some o triângulo */
.nav-group > summary.nav-group-head::marker { content: ""; }                    /* demais navegadores */
.nav-group > summary.nav-group-head:hover { color: var(--accent-text); }
.nav-group > summary.nav-group-head:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.nav-group .nav-group-name { flex: 1; min-width: 0; }
.nav-group .nav-chevron { width: 14px; height: 14px; flex: 0 0 14px; opacity: .55; transition: transform .18s ease; }
.nav-group[open] > summary .nav-chevron { transform: rotate(180deg); opacity: .9; }
/* Aberta = destaque: é o único cabeçalho colorido da lista, então o olho acha
   na hora em que seção você está. */
.nav-group[open] > summary.nav-group-head { color: var(--accent-text); }
/* Trilho: amarra visualmente os itens ao rótulo que os abriu. */
.nav-group-items {
  padding: 0 0 10px 0; margin-left: 12px; padding-left: 8px;
  border-left: 2px solid var(--border);
}
.nav-group[open] > .nav-group-items { border-left-color: var(--primary-soft); }

/* ---------- Drawer de menu (mobile) ---------- */
.menu-drawer-overlay { padding: 0; }
.menu-drawer {
  width: min(86vw, 330px); height: 100%; margin-left: auto;
  background: var(--surface); border-left: 1px solid var(--border);
  display: flex; flex-direction: column; overflow-y: auto;
  padding: 8px 12px calc(env(safe-area-inset-bottom) + 14px);
  box-shadow: var(--shadow-lg);
}
.menu-drawer-head {
  display: flex; align-items: center; gap: 8px; padding: 8px 4px 10px;
  position: sticky; top: 0; z-index: 1; background: var(--surface);
  border-bottom: 1px solid var(--border); margin-bottom: 6px;
}
.menu-drawer-head strong { font-size: 1.05rem; }
.menu-drawer-nav { flex: 1; }
.menu-drawer .nav-item {
  display: flex; align-items: center; gap: 11px; padding: 10px 12px;
  border-radius: var(--radius-sm); color: var(--text-soft); font-weight: 650; font-size: .95rem;
  margin-bottom: 1px;
}
.menu-drawer .nav-item:hover { background: var(--surface-2); }
.menu-drawer .nav-item.active { background: var(--primary-soft); color: var(--primary-dark); }
:root[data-theme="dark"] .menu-drawer .nav-item.active { color: var(--primary); }
.menu-drawer-foot { margin-top: auto; padding-top: 12px; }

/* Botão "Sair" da sidebar (é <button>, não <a> — precisa do mesmo visual). */
.sidebar .nav-logout { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border); }
.sidebar .nav-logout .nav-item {
  width: 100%; display: flex; align-items: center; gap: 11px; padding: 9px 12px;
  border-radius: var(--radius-sm); color: var(--text-soft); font-weight: 650; font-size: .9rem;
  background: none; border: 0; cursor: pointer; text-align: left; font-family: inherit;
}
.sidebar .nav-logout .nav-item:hover { background: var(--surface-2); color: var(--text); }

/* ---------- CRÍTICO: tamanho dos ícones de navegação ---------- */
/* SVGs sem width/height explícitos esticam para preencher o flex container.
   Fixamos um tamanho para todos os ícones de navegação. */
.sidebar a.nav-item svg,
.bottom-nav a svg,
.bottom-nav button svg,
.nav-item svg,
.menu-link svg {
  width: var(--icon); height: var(--icon);
  flex: 0 0 var(--icon); stroke-width: 2;
}
.bottom-nav a svg, .bottom-nav button svg { width: 23px; height: 23px; flex-basis: 23px; }

/* ---------- Refinamentos mobile / UX (revisão geral) ---------- */
.table-wrap { -webkit-overflow-scrolling: touch; }

/* Tabelas que viram CARTÕES no celular (opt-in: class="data cards-mobile").
   Cada linha vira um card; cada célula mostra o rótulo da coluna (data-label). */
@media (max-width: 640px) {
  .table-wrap:has(table.cards-mobile) { box-shadow: none; overflow: visible; border-radius: 0; }
  table.data.cards-mobile, table.data.cards-mobile tbody, table.data.cards-mobile tr, table.data.cards-mobile td { display: block; width: 100%; }
  table.data.cards-mobile thead { display: none; }
  table.data.cards-mobile tr { border: 1px solid var(--border); border-radius: var(--radius); margin-bottom: 10px; padding: 4px 12px; background: var(--surface); box-shadow: var(--shadow); }
  table.data.cards-mobile td { display: flex; align-items: center; justify-content: space-between; gap: 14px; text-align: right; padding: 9px 0; border: none; border-bottom: 1px solid var(--border); font-size: .92rem; }
  table.data.cards-mobile td:last-child { border-bottom: none; }
  table.data.cards-mobile td::before { content: attr(data-label); font-weight: 700; color: var(--text-faint); font-size: .74rem; text-transform: uppercase; letter-spacing: .02em; text-align: left; flex: 0 0 auto; }
  /* Células sem rótulo (foto, ações): ocupam a linha inteira, centralizadas. */
  table.data.cards-mobile td[data-label=""] { justify-content: center; }
  table.data.cards-mobile td[data-label=""]::before { content: none; }
  table.data.cards-mobile td.text-right { justify-content: center; }
}
@media (max-width: 640px) {
  /* iOS: fonte >= 16px no campo evita o zoom automático ao focar. */
  .input, .select, .textarea { font-size: 16px; }
  /* Cabeçalho de página: título + ações quebram em vez de estourar. */
  .page-head { flex-wrap: wrap; gap: 8px 10px; }
  .page-head h1 { font-size: 1.3rem; }
  .page-head .spacer { display: none; }
  /* Botões pequenos com área de toque mais confortável. */
  .btn-sm { padding: 9px 14px; }
  /* Detalhes (rótulo/valor) com coluna de rótulo mais estreita. */
  .kv { grid-template-columns: 96px 1fr; gap: 6px 12px; }
  /* Um pouco mais justo para telas estreitas. */
  .main { padding-left: 13px; padding-right: 13px; }
  .card { padding: 15px; }
  .btn-row .btn { flex: 1 1 auto; }
}

/* =====================================================================
   Refinamento visual v2.1 — placa Mercosul + acentos de cor / ícones
   ===================================================================== */

/* ---------- Placa Mercosul (H::plate) ---------- */
.plate-tag {
  display: inline-flex; flex-direction: column; align-items: stretch;
  min-width: 74px; border-radius: 5px; overflow: hidden; vertical-align: middle;
  border: 1.5px solid #23262b; background: #f7f8f8; line-height: 1;
  box-shadow: var(--shadow-xs);
  font-family: ui-monospace, "SFMono-Regular", "DejaVu Sans Mono", "Courier New", monospace;
}
.plate-tag .plate-top {
  display: flex; align-items: center; justify-content: center; gap: 4px;
  background: linear-gradient(180deg, #1f52cc, #123d9e); color: #fff;
  font-size: .5rem; font-weight: 800; letter-spacing: .12em; padding: 1px 4px 2px;
}
.plate-tag .plate-flag {
  width: 11px; height: 7px; border-radius: 1px; flex: 0 0 auto;
  background: linear-gradient(180deg, #159a3f 0 44%, #f4d000 44% 76%, #159a3f 76%);
  box-shadow: inset 0 0 0 .5px rgba(0,0,0,.3);
}
.plate-tag .plate-num {
  padding: 2px 7px 3px; text-align: center; color: #15181c;
  font-weight: 800; font-size: .92rem; letter-spacing: .12em;
}
.plate-tag.plate-sm { min-width: 60px; }
.plate-tag.plate-sm .plate-top { font-size: .44rem; padding: 1px 3px; }
.plate-tag.plate-sm .plate-num { font-size: .76rem; padding: 1px 5px 2px; letter-spacing: .09em; }
/* A placa é um objeto físico (clara); no dark só suavizamos a borda. */
:root[data-theme="dark"] .plate-tag { border-color: #3a3f47; box-shadow: 0 1px 3px rgba(0,0,0,.5); }

/* ---------- Título de card com acento colorido ---------- */
.card-title { display: flex; align-items: center; gap: 8px; }
.card-title::before {
  content: ""; width: 4px; height: 13px; border-radius: 3px; flex: 0 0 auto;
  background: linear-gradient(180deg, var(--primary-grad-1), var(--primary-grad-2));
}

/* ---------- Cabeçalho de página: fio inferior sutil ---------- */
.page-head { padding-bottom: 12px; border-bottom: 1px solid var(--border); }

/* ---------- Cards de estatística tingidos pelo acento ---------- */
.stat::after { width: 5px; border-radius: 0 3px 3px 0; }
.stat.accent-blue   { background: linear-gradient(180deg, color-mix(in srgb, var(--primary) 8%, var(--surface)), var(--surface)); }
.stat.accent-green  { background: linear-gradient(180deg, color-mix(in srgb, var(--success) 9%, var(--surface)), var(--surface)); }
.stat.accent-orange { background: linear-gradient(180deg, color-mix(in srgb, var(--warning) 10%, var(--surface)), var(--surface)); }
.stat.accent-red    { background: linear-gradient(180deg, color-mix(in srgb, var(--danger) 9%, var(--surface)), var(--surface)); }

/* ---------- Menu lateral ativo com acento em gradiente ---------- */
.sidebar a.nav-item.active {
  background: linear-gradient(90deg, var(--primary-soft), transparent);
  box-shadow: inset 3px 0 0 var(--primary);
}

/* ---------- Botões: cor CHEIA (o gradiente clareava o fundo e derrubava o
   contraste do texto para 2.1–3.5:1 — reprovava em AA nos dois temas). Sem o
   "glow" colorido da v2.1 — sombra sutil só no hover (visual enterprise). ---------- */
.btn-success { background: var(--btn-success-bg); color: var(--on-accent); }
.btn-danger  { background: var(--btn-danger-bg);  color: var(--on-accent); }
.btn-success:hover, .btn-danger:hover { box-shadow: var(--shadow); }

/* ---------- Badges com contorno sutil (destacam sobre fundos tingidos) ---------- */
.badge { border: 1px solid color-mix(in srgb, currentColor 20%, transparent); }

/* ---------- Seção atual no cabeçalho (desktop) ---------- */
.app-section { display: none; }
@media (min-width: 860px) {
  .app-section { display: inline-flex; align-items: center; gap: 8px; margin-left: 8px; padding-left: 14px; border-left: 1px solid var(--border-strong); color: var(--text-soft); font-weight: 700; font-size: .92rem; }
  .app-section .as-ico { width: 18px; height: 18px; color: var(--primary); flex: 0 0 auto; }
  .app-section .as-txt { max-width: 340px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* ---------- Ícone do cabeçalho de página (opt-in: .ph-ico no page-head) ---------- */
.page-head .ph-ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 11px; flex: 0 0 auto;
  background: linear-gradient(135deg, color-mix(in srgb, var(--primary) 16%, var(--surface)), var(--surface));
  color: var(--primary); border: 1px solid var(--border);
}
.page-head .ph-ico svg { width: 21px; height: 21px; }

/* ---------- Empty state com ícone destacado ---------- */
.empty .icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 60px; height: 60px; border-radius: 18px; margin: 0 auto 12px;
  background: var(--surface-2); color: var(--text-faint); font-size: 1.9rem;
}
.empty .icon svg { width: 30px; height: 30px; }

/* ---------- Ícone nos stat cards (dashboard) ---------- */
.stat { position: relative; }
.stat .stat-ico {
  position: absolute; top: 12px; right: 12px; width: 34px; height: 34px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 10px; background: color-mix(in srgb, currentColor 14%, transparent);
  opacity: .9;
}
.stat .stat-ico svg { width: 19px; height: 19px; }
.stat.accent-blue .stat-ico { color: var(--primary); }
.stat.accent-green .stat-ico { color: var(--success); }
.stat.accent-orange .stat-ico { color: var(--warning); }
.stat.accent-red .stat-ico { color: var(--danger); }

/* ===================================================================
   Acessibilidade
   =================================================================== */
/* Foco visível p/ teclado (WCAG 2.4.7) sem afetar o clique de mouse. */
a:focus-visible, button:focus-visible, .btn:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible,
[tabindex]:focus-visible, summary:focus-visible {
  outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 5px;
}
/* Alvos de toque confortáveis em telas de toque (WCAG 2.5.5 = 44x44). */
@media (pointer: coarse) {
  .btn { min-height: 44px; }
  .btn-sm, .btn-ghost { min-height: 44px; }
  .pagination a, .pagination span { min-height: 44px; min-width: 44px; display: inline-flex; align-items: center; justify-content: center; }
  .bottom-nav a { min-height: 44px; }
}
/* Respeita "reduzir movimento". */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important; animation-iteration-count: 1 !important;
    transition-duration: .001ms !important; scroll-behavior: auto !important;
  }
}
/* "Pular para o conteúdo" — aparece só ao focar via teclado. */
.skip-link {
  position: absolute; left: 12px; top: -52px; z-index: 100;
  background: var(--btn-primary-bg); color: var(--on-accent); padding: 9px 14px;
  border-radius: 0 0 10px 10px; font-weight: 700; transition: top .15s;
}
.skip-link:focus { top: 0; color: var(--on-accent); }

/* ---------- Chip de imagem de dispositivo (tipos/produtos do Omada) ----------
   As ilustrações são cinza p/ fundo claro; o chip claro as mostra bem nos dois
   temas (padrão do próprio Omada). Fallback: ícone vetorial do sistema. */
/* ⚠ O chip NÃO pode ser claro: as artes de produto/tipo são quase todas BRANCAS
   (roteador branco, AP branco, notebook prateado…) e sumiam no fundo claro.
   Cinza-escuro translúcido: dá contraste com a arte branca e funciona nos dois
   temas (no claro vira um cinza médio; no escuro, um cinza mais profundo). */
.dev-chip {
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(38, 46, 60, .72);
  border: 1px solid rgba(255, 255, 255, .10);
  border-radius: var(--radius-sm);
  flex: 0 0 auto; overflow: hidden;
}
.dev-chip img { width: 78%; height: 78%; object-fit: contain; }
/* Fallback vetorial: aqui o ícone é de cor única e segue o tema — chip neutro. */
.dev-chip.dev-chip-icon { background: var(--surface-2); border-color: var(--border); color: var(--text-soft); }
.dev-chip.dev-chip-icon svg { width: 55%; height: 55%; }
:root[data-theme="dark"] .dev-chip { background: rgba(18, 24, 34, .78); }

/* Só para leitor de tela (rótulos de tabela, status ao vivo, legendas). */
.sr-only {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ---------- Ordenação por clique no cabeçalho ---------- */
.th-sortable { cursor: pointer; user-select: none; -webkit-user-select: none; white-space: nowrap; transition: background .12s, color .12s; }
.th-sortable:hover { color: var(--text); background: var(--surface-3); }
.th-arrow { color: var(--accent-text); font-weight: 800; font-size: .8em; }

/* ---------- Estado "ao vivo" x "sem conexão" (telas de operação/portaria) ----------
   Num painel de portaria, mostrar dado velho como se fosse novo é risco real.
   Estas classes dão o vocabulário único: ponto pulsante + rótulo TEXTUAL. */
.live-flag { display: inline-flex; align-items: center; gap: 6px; font-size: .78rem; font-weight: 700; color: var(--success-text); }
.live-flag .live-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--success); flex: 0 0 auto; animation: livePulse 1.6s ease-in-out infinite; }
.live-flag.stale { color: var(--danger-text); }
.live-flag.stale .live-dot { background: var(--danger); animation: none; }
@keyframes livePulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }

/* Estado vazio: alias tolerante (3 telas usavam .empty-state, que não existia). */
.empty-state { text-align: center; padding: 40px 16px; color: var(--text-soft); }

/* ---------- Barra de status com TEXTO (calendário e Gantt de OS) ----------
   Era cor cheia + texto branco (branco sobre laranja/azul-claro dá ~2.5:1:
   reprova). Agora fundo suave + texto no token escuro — passa em AA e segue o tema. */
.status-bar {
  display: block; font-size: .72rem; line-height: 1.25; text-decoration: none;
  border-radius: 5px; padding: 1px 5px; margin-bottom: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  border: 1px solid transparent; font-weight: 600;
}
.sb-success { background: var(--success-soft); color: var(--success-text); border-color: color-mix(in srgb, var(--success) 35%, transparent); }
.sb-warning { background: var(--warning-soft); color: var(--warning-text); border-color: color-mix(in srgb, var(--warning) 35%, transparent); }
.sb-danger  { background: var(--danger-soft);  color: var(--danger-text);  border-color: color-mix(in srgb, var(--danger) 35%, transparent); }
.sb-info    { background: var(--info-soft);    color: var(--info-text);    border-color: color-mix(in srgb, var(--info) 35%, transparent); }
.sb-neutral { background: var(--neutral-soft); color: var(--neutral-text); border-color: color-mix(in srgb, var(--neutral) 35%, transparent); }

[x-cloak] { display: none !important; }

/* Círculo cromático: matiz no ÂNGULO, saturação no RAIO. Desenhado pelo JS num
   <canvas>; nasce `hidden` e só aparece se o JS conseguir pintar — botão que não
   responde é pior que botão ausente. */
.cor-roda { position: relative; width: 150px; height: 150px; flex: none; }
.cor-roda canvas { display: block; border-radius: 50%; cursor: crosshair;
  border: 1px solid var(--border-strong); background: var(--surface); touch-action: none; }
.cor-mira { position: absolute; width: 16px; height: 16px; margin: -8px 0 0 -8px;
  border-radius: 50%; border: 2px solid #fff; box-shadow: 0 0 0 1.5px rgba(0,0,0,.55);
  pointer-events: none; transition: left .06s linear, top .06s linear; }
.cor-livre { flex-wrap: wrap; }

/* ── SELETOR DE ÍCONE (components/icon_picker.php) ───────────────────────────
   ⚠ Vinha num <style> DENTRO do componente, que pode ser incluído uma vez POR
   LINHA numa tabela de cômodos — ou seja, o mesmo CSS saía 20 vezes na mesma
   página. É a causa-raiz da §5.71 em miniatura: bloco de estilo que aparece
   duas vezes é do design system, não da tela. */
.icon-picker { border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.ip-head { display: flex; gap: 10px; align-items: center; padding: 10px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.ip-search { flex: 1; min-width: 180px; }
.ip-atual { display: inline-flex; align-items: center; gap: 6px; font-size: .82rem; white-space: nowrap; }
.ip-atual-nome { font-family: ui-monospace, monospace; font-size: .78rem; }
/* Altura limitada: 82 ícones soltos empurrariam o botão Salvar para fora da tela. */
.ip-scroll { max-height: 300px; overflow-y: auto; padding: 10px; }
.ip-group + .ip-group { margin-top: 12px; }
.ip-group-t { font-size: .7rem; text-transform: uppercase; letter-spacing: .05em; font-weight: 800;
  color: var(--text-faint); margin: 0 0 6px; }
.ip-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(78px, 1fr)); gap: 6px; }

.ip-item { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 8px 4px;
  border: 1px solid transparent; border-radius: var(--radius-sm); cursor: pointer; text-align: center; }
.ip-item:hover { background: var(--surface-2); border-color: var(--border); }
/* O radio é a fonte da verdade (funciona sem JS); a moldura só reflete o :checked.
   Duas regras de propósito: `:has()` é moderno e resolve sem JS; `.is-sel` é posta
   pelo JS. Se o navegador não entender `:has()`, o operador ainda VÊ qual escolheu —
   um seletor de ícone sem realce de seleção seria adivinhação. */
.ip-item input { position: absolute; opacity: 0; width: 0; height: 0; }
.ip-item:has(input:checked), .ip-item.is-sel { border-color: var(--primary); background: var(--surface-2); }
.ip-item input:focus-visible + .ip-box { outline: 2px solid var(--primary); outline-offset: 2px; }
.ip-box { display: inline-flex; align-items: center; justify-content: center; width: 38px; height: 38px;
  border-radius: var(--radius-sm); background: #fff; }
.ip-box img { width: 30px; height: 30px; object-fit: contain; }
.ip-auto .ip-box { background: var(--surface-2); color: var(--text-soft); }
.ip-label { font-size: .68rem; line-height: 1.2; color: var(--text-soft); overflow-wrap: anywhere; }
.ip-vazio { text-align: center; padding: 14px; }
.ip-inline > summary { cursor: pointer; font-size: .82rem; color: var(--accent-text);
  padding: 6px 0; list-style: revert; }
.ip-inline[open] > summary { margin-bottom: 6px; }
@media (pointer: coarse) { .ip-inline > summary { min-height: 44px; display: flex; align-items: center; } }

/* Rótulo que ENVOLVE um checkbox. ⚠ O layout vale SEMPRE (era `style=` inline
   repetido em 6 telas); só o alvo de 44px é do toque, no @media lá embaixo.
   Deixar tudo dentro do @media tirava o alinhamento no desktop. */
.check-row { display: flex; align-items: center; gap: 8px; }
.check-cell { text-align: center; }

/* ── Controle de COR (iluminação da piscina) ─────────────────────────────────
   ⚠ A amostra é um alvo com BORDA — sem ela, o branco e o branco-quente somem
   no fundo claro e viram dois botões invisíveis. E o estado "esta é a cor
   atual" NÃO fica só no anel: o `aria-pressed` conta para o leitor de tela e o
   nome da cor vai no `title` + `.sr-only`, porque quem não distingue azul de
   turquesa não pode depender do quadradinho. */
.auto-cor { display: flex; flex-direction: column; gap: 8px; align-items: stretch; }
.cor-paleta { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; }
.cor-amostra {
  width: 32px; height: 32px; padding: 0; cursor: pointer;
  background: var(--amostra, #fff);
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  box-shadow: none;
}
.cor-amostra:hover { border-color: var(--text-faint); }
.cor-amostra.sel { outline: 2px solid var(--primary); outline-offset: 2px; }
.cor-amostra:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.cor-livre { display: flex; align-items: center; gap: 8px; margin: 0; }
.cor-livre input[type="color"] {
  width: 46px; height: 34px; padding: 2px; cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface);
}
@media (pointer: coarse) {
  .cor-amostra { width: 44px; height: 44px; }
  .cor-livre input[type="color"] { width: 56px; height: 44px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   AUTOMAÇÃO — o cartão de dispositivo e o que orbita nele.
   ──────────────────────────────────────────────────────────────────────────
   ⚠ POR QUE ISTO ESTÁ AQUI, e não num <style> da tela. Estas regras viviam
   DUPLICADAS inline em 5 views (panel, mine, scenes, water, access) e já
   tinham DIVERGIDO: o `.auto-conn` (online/offline em TEXTO) e o `.auto-info`
   existiam só no `mine.php`; o `.live-dot` tinha uma margem a mais no
   `panel.php`; o `.auto-on` tinha 4 versões. Ou seja: toda correção precisava
   ser feita 2–4 vezes — e o histórico mostra que não era. As três melhorias
   mais importantes do módulo (estado por texto, indicador ao vivo com rótulo,
   controle `info`) ficaram cada uma presa numa única tela. Um lugar só.
   ══════════════════════════════════════════════════════════════════════════ */

/* ⚠ `--text-muted` NÃO EXISTIA. Quatro regras usavam `var(--text-muted, #6b7280)`
   e caíam SEMPRE no cinza fixo — que sobre a superfície escura dá ~3,4:1 e
   reprova AA em texto pequeno. Em vez de espalhar o nome errado, o nome passa a
   existir e aponta para o token real (que já é AA nos dois temas). */
:root { --text-muted: var(--text-faint); }

.auto-grid {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
}
.auto-card {
  display: flex; flex-direction: column; gap: 7px;
  padding: 12px 14px; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs);
  transition: border-color .12s, box-shadow .12s;
}
.auto-card.is-on { border-color: var(--success-text); box-shadow: 0 0 0 1px var(--success-text); }
.auto-card.is-monitor { background: var(--surface-2); }
.auto-card.busy { opacity: .6; pointer-events: none; }
.auto-card.flash { animation: autoflash .5s ease; }
@keyframes autoflash { from { box-shadow: 0 0 0 3px var(--primary-soft); } to { box-shadow: var(--shadow-xs); } }

/* Topo: ponto + CONEXÃO EM TEXTO + categoria. */
.auto-top {
  display: flex; align-items: center; gap: 8px;
  font-size: .74rem; color: var(--text-faint);
  text-transform: uppercase; letter-spacing: .03em;
}
.auto-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; display: inline-block; }
.auto-dot.on  { background: var(--success); }
.auto-dot.off { background: var(--danger); }
/* ⚠ ESTADO NUNCA SÓ POR COR. Antes o painel dizia online/offline com um ponto de
   9px + um `title` — invisível no toque e sem significado para quem não distingue
   verde de vermelho. O texto é o que comunica; o ponto é reforço. */
.auto-conn { font-weight: 700; }
.auto-conn.on  { color: var(--success-text); }
.auto-conn.off { color: var(--danger-text); }

/* Veredito da CHECAGEM DE VÍNCULO (automation/controlart_check).
   ⚠ Tokens de TEXTO, não os de acento: `--success`/`--warning` reprovam em AA
   como cor de texto (§3.1). E a cor nunca é o único sinal — a frase inteira diz
   o que aconteceu; isto aqui só reforça. */
.chk-ok   { color: var(--success-text); font-weight: 600; }
.chk-warn { color: var(--warning-text); font-weight: 600; }
.auto-cat { margin-left: auto; }

.auto-id { display: flex; gap: 10px; align-items: center; min-width: 0; }
.auto-name { font-weight: 750; font-size: 1rem; line-height: 1.2; }
.auto-state { font-weight: 800; font-size: .95rem; color: var(--text-soft); }
.auto-card.is-on .auto-state { color: var(--success-text); }
/* Terceiro estado: "não sabemos" ≠ "desligado". */
.auto-state.unknown { color: var(--text-faint); font-weight: 700; font-style: italic; }
/* GRUPO em divergência: uns membros ligados, outros não.
   ⚠ Token de TEXTO (`--warning-text`), nunca o acento `--warning` — como cor de
   texto ele reprova em AA (§3.1). E a cor só reforça: o rótulo já diz "Parcial —
   2 de 3 ligados", que é o que de fato informa. */
.auto-state.parcial { color: var(--warning-text); font-size: .88rem; }

/* Ações: SEGMENTADO de 44px. Antes eram 2–3 botões `flex:1` numa grade de 2
   colunas no celular — cada um sobrava com ~40–63px e "Desligar" não cabia. */
.auto-actions { display: flex; gap: 8px; margin-top: 2px; }
.auto-seg {
  flex: 1; display: flex; min-height: 44px; overflow: hidden;
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
}
.auto-seg .sg-b {
  flex: 1; min-height: 44px; padding: 0 6px; border: 0; cursor: pointer;
  background: transparent; color: var(--text);
  font-family: inherit; font-size: .9rem; font-weight: 700;
}
.auto-seg .sg-b + .sg-b { border-left: 1px solid var(--border-strong); }
.auto-seg .sg-b:hover { background: var(--surface-2); }
.auto-seg .sg-b:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
/* A posição ATUAL fica preenchida — o segmentado mostra estado, não só oferece ação. */
.auto-seg .sg-on[aria-pressed="true"]  { background: var(--btn-success-bg); color: var(--on-accent); }
.auto-seg .sg-off[aria-pressed="true"] { background: var(--neutral); color: var(--on-accent); }
.auto-alt {
  flex: none; min-height: 44px; padding: 0 12px; cursor: pointer;
  background: transparent; color: var(--text-soft);
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  font-family: inherit; font-size: .85rem; font-weight: 600;
}
.auto-alt:hover { background: var(--surface-2); }

/* ═══ PERSIANA: Subir · Parar · Descer ═══
   Três botões no mesmo segmentado. "Parar" fica no MEIO de propósito — é o alvo
   que a pessoa procura com pressa, com a persiana já em movimento. Sem
   `aria-pressed`: são COMANDOS, não a posição de um interruptor (o estado atual
   está no texto do cartão, acima). */
.auto-seg-3 .sg-b { font-size: .86rem; }
.auto-seg-3 .sg-parar { color: var(--danger-text); }
.auto-seg-3 .sg-parar:hover { background: var(--danger-soft); }

/* ═══ Botões de ícone do topo do cartão (atualizar / menu rápido) ═══
   44px em toque, discretos em repouso — não competem com o comando principal. */
.auto-mini { flex: none; display: flex; }
.auto-icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0; cursor: pointer;
  background: transparent; color: var(--text-faint);
  border: 1px solid transparent; border-radius: var(--radius-sm);
  list-style: none;   /* <summary> não mostra o triângulo */
}
.auto-icon-btn::-webkit-details-marker { display: none; }
.auto-icon-btn:hover { background: var(--surface-2); color: var(--text); border-color: var(--border); }
.auto-icon-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
.auto-icon-btn svg { width: 15px; height: 15px; }
.auto-icon-btn.girando svg { animation: autospin .7s linear infinite; }
@keyframes autospin { to { transform: rotate(360deg); } }

/* ═══ Menu rápido (nome + cômodo) ═══ <details> nativo: teclado e ESC de graça. */
.auto-quick { position: relative; flex: none; }
.auto-quick-pop {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 30;
  width: min(300px, 78vw); padding: 12px;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--radius); box-shadow: var(--shadow-lg, 0 8px 28px rgba(0,0,0,.16));
  text-transform: none; letter-spacing: 0;   /* o .auto-top é uppercase; aqui não */
  font-size: .9rem; color: var(--text);
}
.auto-quick-pop label { display: block; font-size: .78rem; font-weight: 700; color: var(--text-soft); margin: 0 0 3px; }
.auto-quick-pop .input { width: 100%; margin-bottom: 9px; }
.auto-quick-acoes { display: flex; gap: 8px; align-items: center; }
.auto-quick-msg { margin: 8px 0 0; font-size: .82rem; font-weight: 600; }
.auto-quick-msg.erro { color: var(--danger-text); }
.auto-quick-msg.ok   { color: var(--success-text); }
/* ⚠ Regra de CLASSE vence o atributo `hidden` — a mesma armadilha do paginador
   (§3) e do `.cam-msg` da Dimora (§5.55.9). */
.auto-quick-msg[hidden] { display: none; }
@media (pointer: coarse) {
  .auto-icon-btn { width: 44px; height: 44px; }
}
.auto-monitor { margin-top: 2px; font-size: .78rem; color: var(--text-faint); font-weight: 600;
  display: flex; align-items: center; gap: 6px; }

/* Controles ajustáveis (temperatura-alvo / modo) — bomba de calor, clima. */
.auto-controls { display: grid; gap: 8px; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border); }
.auto-ctrl { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0; }
.auto-ctrl-lbl { font-size: .78rem; color: var(--text-faint); min-width: 96px; }
.auto-ctrl select, .auto-ctrl input[type="number"] {
  min-height: 44px; padding: 8px 10px; font-size: .9rem;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.auto-ctrl input[type="number"] { width: 5.5em; }
.auto-num { display: inline-flex; align-items: center; gap: 6px; }
.auto-unit { font-size: .82rem; color: var(--text-faint); }
.auto-info { font-weight: 800; font-size: .92rem; color: var(--text-soft); }

/* Indicador "ao vivo" — com RÓTULO. (O `water.php` já fazia certo; as outras
   telas tinham só um ponto pulsante e um `title`.) */
.live-wrap { display: inline-flex; align-items: center; gap: 7px; font-size: .8rem; color: var(--text-faint); }
.live-dot {
  width: 9px; height: 9px; border-radius: 50%; flex: none; display: inline-block;
  background: var(--success); box-shadow: 0 0 0 0 rgba(21,160,90,.5);
  animation: livepulse 2s infinite;
}
.live-dot.stale { background: var(--text-faint); animation: none; }
@keyframes livepulse {
  0%   { box-shadow: 0 0 0 0 rgba(21,160,90,.45); }
  70%  { box-shadow: 0 0 0 6px rgba(21,160,90,0); }
  100% { box-shadow: 0 0 0 0 rgba(21,160,90,0); }
}

/* Banner de automação pausada. */
.auto-banner {
  display: flex; align-items: center; gap: 12px; padding: 12px 16px; margin-bottom: 14px;
  background: var(--warning-soft); border: 1px solid color-mix(in srgb, var(--warning) 45%, transparent);
  border-radius: var(--radius-lg); color: var(--warning-text);
}
.auto-banner-ico { display: flex; flex: none; }
.auto-banner-sub { font-size: .85rem; }

/* Interruptores mestres (habilitar/desabilitar subsistemas). */
.auto-sw-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 10px; }
.auto-sw {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius);
}
.auto-sw-info { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.auto-sw-info strong { font-size: .92rem; }
.auto-sw-info span { font-size: .76rem; color: var(--text-faint); }

/* Lista de eventos (últimas ações). Estava duplicada em access.php e mine.php. */
.ev-list { display: flex; flex-direction: column; }
.ev-row { display: flex; align-items: center; gap: 9px; padding: 8px 0;
  border-bottom: 1px solid var(--border); font-size: .88rem; }
.ev-row:last-child { border-bottom: none; }
.ev-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.ev-dot.on  { background: var(--success); }
.ev-dot.off { background: var(--danger); }
/* O resultado em TEXTO, não só a cor do ponto. */
.ev-res { font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; font-weight: 700; }
.ev-res.on  { color: var(--success-text); }
.ev-res.off { color: var(--danger-text); }
.ev-dev { font-weight: 700; }
.ev-det { color: var(--text-soft); flex: 1; }
.ev-when { color: var(--text-faint); font-size: .8rem; white-space: nowrap; }

/* Aviso flutuante: "acionou, mas não deu para confirmar o estado".
   ⚠ NUNCA verde — o operador leria "está do jeito que pedi". */
.auto-aviso {
  position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%); z-index: 60;
  max-width: min(560px, calc(100vw - 24px));
  display: flex; gap: 10px; align-items: flex-start; padding: 12px 14px;
  background: var(--surface); color: var(--warning-text);
  border: 1px solid var(--warning); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); font-size: .9rem; line-height: 1.45;
}
/* ⚠ VARIANTES DE COR do mesmo toast — a PORTARIA é a segunda tela a usá-lo, e
   bloco que aparece em duas telas é do design system, não da tela (§5.71).
   E seguem a regra do §3.1: o ACENTO é a borda; o TEXTO usa o token `-text`.
   Escrever `background: var(--success); color: var(--on-accent)` dava 3,38:1 —
   reprova AA, e num toast que às vezes é a única confirmação que a portaria vê. */
.auto-aviso.ok   { color: var(--success-text); border-color: var(--success); }
.auto-aviso.erro { color: var(--danger-text);  border-color: var(--danger); }
.auto-aviso b { display: block; }
.auto-aviso button { flex: none; min-width: 44px; min-height: 44px; border: 0;
  background: none; color: inherit; font-size: 1.1rem; cursor: pointer; }
@media (prefers-reduced-motion: no-preference) { .auto-aviso { animation: avisoin .18s ease; } }
@keyframes avisoin { from { opacity: 0; transform: translate(-50%, 8px); } to { opacity: 1; transform: translate(-50%, 0); } }

/* ⚠ UMA COLUNA no celular, não duas. Com 2 colunas o cartão ficava com ~133px
   úteis e a linha de ações não cabia (o "Desligar" era cortado, e com o
   "Alternar" eram três botões de ~40px). Cartão largo > cartão espremido. */
@media (max-width: 560px) {
  .auto-grid { grid-template-columns: 1fr; }
}

/* Formulário que é só um botão embutido numa linha (evita ~30 style="display:inline"). */
.inline-form { display: inline; margin: 0; }

/* Alvo de toque: o bloco de `pointer: coarse` cobria só `.btn` — as CAIXAS DE
   SELEÇÃO ficaram de fora, e telas como /automation/access existem justamente
   para marcar dezenas delas. */
@media (pointer: coarse) {
  .check-row { min-height: 44px; }
  .check-row input[type="checkbox"], .check-cell input[type="checkbox"] { width: 22px; height: 22px; }
  .check-cell { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; }
}

/* ══════════════════════════════════ CONVERSA DO CONCIERGE (atendimento) ══
   ⚠ É a MESMA thread que o hóspede vê no app dele. O que a equipe escreve
   aqui aparece lá como resposta do concierge — ele não muda de canal.
   Três autores, distinguidos por posição E por rótulo em texto (cor sozinha
   não comunica, §3.1). */
.cv-adm { display: flex; flex-direction: column; gap: 10px; max-height: 460px; overflow-y: auto; }
/* Anexo (áudio/foto) na thread do operador. A borda existe porque a foto pode
   ser clara: sem ela, uma parede branca se dissolve no fundo do card e a
   imagem parece não ter carregado. */
/* ═══ O OPERADOR COMO CAMADA (modo assistido do concierge) ═══
   ⚠ Bloco DESTACADO de propósito: é a diferença entre "a IA está sozinha" e
   "tem gente informando", e o operador precisa ver isso de relance. A borda
   usa `--primary` como ACENTO (não como texto — §3.1). */
.cv-op{
  border:1px solid var(--border); border-left:3px solid var(--primary);
  border-radius:var(--radius); padding:12px 14px; background:var(--surface-2);
}
.cv-op-head{
  display:flex; align-items:center; justify-content:space-between;
  gap:12px; flex-wrap:wrap; margin-bottom:10px;
}
.cv-op-head span{ flex:1 1 240px; }
.cv-op .btn{ flex:none; }
.cv-adm-audio{ display:block; width:100%; max-width:280px; height:36px; margin:4px 0 6px; }
.cv-adm-foto{ display:block; margin:4px 0 6px; }
.cv-adm-foto img{ display:block; max-width:100%; max-height:240px; width:auto;
  border:1px solid var(--border); border-radius:var(--radius-sm); }
.cv-adm-msg { max-width: 78%; }
.cv-adm-msg.hospede { align-self: flex-start; }
.cv-adm-msg.ia, .cv-adm-msg.equipe { align-self: flex-end; text-align: right; }
.cv-adm-msg .quem { display: block; font-size: .72rem; color: var(--text-faint); margin-bottom: 2px; }
.cv-adm-msg .txt {
  display: inline-block; padding: 8px 12px; text-align: left;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-2); font-size: .93rem; line-height: 1.45;
}
/* A equipe (pessoa) ganha o acento; a IA fica neutra — quem lê precisa saber
   na hora se aquilo foi um humano ou o robô que respondeu. */
.cv-adm-msg.equipe .txt { border-left: 3px solid var(--primary); }
.cv-adm-msg.hospede .txt { background: var(--surface); }

/* ═══════════════════════════════════════ EMERGÊNCIA (chamado do hóspede) ═══
   ⚠ O CHAMADO ABERTO NÃO É UMA LINHA DE TABELA. Quem abre esta tela precisa
   ver, num relance, que tem alguém pedindo socorro — uma linha a mais numa
   grade se lê como registro histórico, não como urgência. */
.emerg-aberta{ border-left:4px solid var(--danger) }
.emerg-aberta.assumida{ border-left-color:var(--warning) }
.emerg-aberta.encerrada{ border-left-color:var(--border-strong) }
.emerg-topo{ display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:wrap }
/* Selo com ÍCONE + TEXTO: estado nunca só por cor (§3.1). E o texto usa o
   token `-text`, não o acento cru — este reprova AA em corpo pequeno. */
.emerg-selo{
  display:inline-flex; align-items:center; gap:6px;
  color:var(--danger-text); font-weight:700; font-size:.82rem;
  text-transform:uppercase; letter-spacing:.04em;
}
.emerg-aberta.assumida .emerg-selo{ color:var(--warning-text) }
.emerg-aberta.encerrada .emerg-selo{ color:var(--neutral-text) }
.emerg-falha{
  display:flex; gap:8px; align-items:flex-start;
  margin:10px 0 0; padding:8px 12px; border-radius:var(--radius-sm);
  background:var(--danger-soft); color:var(--danger-text);
}
.emerg-falha svg{ flex:none; margin-top:2px }
.emerg-acoes{ display:flex; flex-wrap:wrap; gap:10px; align-items:center; margin-top:14px }
/* "Estou indo" é o único botão em destaque da tela — é ele que PARA a
   insistência, e ninguém pode ficar procurando qual é. */
.btn-emerg{ background:var(--btn-danger-bg); color:var(--on-accent) }

/* A cascata, na ordem em que as pessoas serão chamadas. */
.emerg-degraus{ margin:10px 0 0; padding-left:22px }
.emerg-degraus li{ padding:5px 0; border-top:1px solid var(--border) }
.emerg-degraus li:first-child{ border-top:0 }
.emerg-degraus li.feito{ opacity:.6 }
.emerg-degraus .muted{ display:block; font-size:.85rem }

.emerg-linha{ list-style:none; margin:8px 0 0; padding:0 }
.emerg-linha li{
  display:flex; gap:12px; align-items:baseline;
  padding:6px 0; border-top:1px solid var(--border); font-size:.92rem;
}
.emerg-linha li:first-child{ border-top:0 }
.emerg-linha .hr{ flex:none; font-size:.78rem; color:var(--text-faint); white-space:nowrap }

/* ═══════════════════════════════ CLASSES QUE FALTAVAM (correção 2026-08) ═══
   ⚠ POR QUE ISTO EXISTE: `class="grid-2"` sem regra correspondente NÃO DÁ
   ERRO — o navegador simplesmente não aplica nada, e a tela sai crua. É a mesma
   armadilha já registrada para os tokens ("var() indefinida some em silêncio"),
   agora do lado da CLASSE. Havia 50 nomes nesta situação, alguns em 15 telas.
   O `static_check.php` passou a cruzar toda `class=` contra este arquivo. */

/* Duas colunas que viram uma no celular. O layout mais repetido do sistema —
   estava escrito em 7 telas e não existia em lugar nenhum. */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; align-items: start; }
.grid-2 > * { min-width: 0; }                 /* sem isto, tabela larga estoura a coluna */
@media (max-width: 760px) { .grid-2 { grid-template-columns: 1fr; } }
/* Modificador do `.form-grid`: três colunas em tela larga. */
@media (min-width: 900px) { .form-grid.cols-3 { grid-template-columns: repeat(3, 1fr); } }

/* Barra de ações no fim de um formulário: separada por uma linha, para o olho
   saber que ali acabou o preenchimento e começa a decisão. */
.form-actions {
  display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
  margin-top: 18px; padding-top: 15px; border-top: 1px solid var(--border);
}
/* Ações no cabeçalho da página (ao lado do título). */
.page-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
/* Linha de campos lado a lado dentro de um formulário. */
.form-row { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; }
.form-row > * { flex: 1 1 180px; min-width: 0; }

/* Bloco de um tipo de credencial (cartão / senha / controle) na ficha. */
.cred-bloco {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 12px; margin-top: 10px; background: var(--surface-2);
}

/* Variantes do `.alert`. O `.alert` sozinho já existia, mas sem cor — então
   "deu certo" e "deu errado" saíam idênticos, que é o defeito do §3.1
   (nunca comunique estado só por... nem por cor nenhuma, neste caso). */
.alert-success { background: var(--success-soft); color: var(--success-text); border-color: var(--success-text); }
.alert-error   { background: var(--danger-soft);  color: var(--danger-text);  border-color: var(--danger-text); }

/* Botão de ação de RISCO MODERADO (apagar registro que se refaz, por exemplo).
   Fundo de cor cheia + `--on-accent`, como os outros sólidos (§3.1). */
.btn-warning { background: var(--btn-warning-bg); color: var(--on-accent); }
.btn-warning:hover { filter: brightness(.94); }

/* Utilitários de tabela. */
.nowrap { white-space: nowrap; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .86rem; }
/* Rótulo "(opcional)" ao lado do nome do campo — cinza e menor que o rótulo. */
.opcional { font-weight: 400; font-size: .8rem; color: var(--text-faint); }

/* Portaria do evento: cartão de quem chegou. */
.pk { display: flex; gap: 10px; align-items: center; padding: 9px 0; border-top: 1px solid var(--border); }
.pk:first-child { border-top: 0; }
.chegada-form { display: inline-flex; gap: 6px; align-items: center; margin: 0; }

/* Valet e veículos. */
.valet-veiculo { align-items: end; }
.vl-placa { display: flex; align-items: center; gap: 8px; }
.merge-thumbs-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
