/* =====================================================================
   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: var(--on-accent); }
.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); color: var(--on-accent); 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;
  /* ⚠ `--neutral-text`, NAO `--neutral`: acento nao e cor de texto (§6.2). A
     base dava 3,30:1 no claro e 4,13:1 no escuro — e ela E alcancavel, em
     `mural/shares.php` e `patrimonio/imoveis_index.php`, que usam `.badge` sem
     variante. As cinco variantes de `H::badge` sempre estiveram certas; era a
     base, que ninguem mediu porque "quase nunca se usa sozinha". */
  background: var(--neutral-soft); color: var(--neutral-text);
}
.badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; opacity: .9; }
/* ⚠ A BORDA NA COR DA FAMÍLIA É O QUE DÁ PRESENÇA AO SELO — mais do que
   escurecer o fundo. Sem contorno, o selo é uma mancha clara que se dissolve
   no cartão; com ele, vira um objeto, e o olho separa "estado" de "texto ao
   redor" sem precisar ler.
   ⚠ E ELA SUBSTITUI o `color-mix(currentColor 20%)` genérico da regra `.badge`
   acima: um contorno derivado do texto fica escuro demais no `-danger` e
   apagado demais no `-neutral`. Cada família tem o seu, medido. */
.badge-success { background: var(--success-soft); color: var(--success-text); border-color: var(--success-border); }
.badge-warning { background: var(--warning-soft); color: var(--warning-text); border-color: var(--warning-border); }
.badge-danger  { background: var(--danger-soft); color: var(--danger-text); border-color: var(--danger-border); }
.badge-info    { background: var(--info-soft); color: var(--info-text); border-color: var(--info-border); }
.badge-neutral { background: var(--neutral-soft); color: var(--neutral-text); border-color: var(--neutral-border); }

/* ---------- 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); }
/* ⚠ A REGRA BASE FALTAVA, e a classe é usada em 69 telas. Só existia
   `.field .hint` (descendente): fora de um `.field`, o parágrafo auxiliar saía
   com o tamanho e a cor do texto normal — a hierarquia que a classe existe
   para criar simplesmente não acontecia, sem erro e sem aviso (§6.5). O check
   17 dava verde porque o NOME está na folha.
   ⚠ Medido: `--text-faint` dá 5,70:1 sobre a superfície no claro, 5,31:1 sobre
   a superfície 2 e 7,63:1 no escuro — o piso é 4,5:1 porque isto é texto
   pequeno (§6.2). */
.hint { font-size: .76rem; color: var(--text-faint); }
.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: var(--warning-border); }
.alert-danger { background: var(--danger-soft); color: var(--danger-text); border-color: var(--danger-border); }
.alert-info { background: var(--info-soft); color: var(--info-text); border-color: var(--info-border); }

/* ---------- 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: var(--on-accent); 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; }
/* ⚠ TEXTO em cor de estado usa os tokens `-text`, NUNCA o acento cru: o
   `--warning` puro dá 2,6:1 e o `--danger` 3,0:1 como TEXTO, reprovando AA
   (§3.1). Estes utilitários existem para que ninguém precise escrever
   `style="color:var(--danger)"` na pressa e acabe no token errado. */
.text-danger  { color: var(--danger-text); }
.text-warning { color: var(--warning-text); }
.text-success { color: var(--success-text); }
.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); }

/* ---------- Sub-rótulo dentro de uma seção (`['sep' => '…']`) ----------
   "Portaria" tem 14 itens desde que as autorizações vieram de "Condomínio", e
   14 numa lista corrida é uma parede: o olho varre e não acha. Os três blocos
   — o que se faz AGORA, quem AUTORIZA, o que JÁ ACONTECEU — existiam só como
   comentário no PHP, e comentário não aparece na tela.

   ⚠ ELE NÃO PODE PARECER CLICÁVEL. É o mesmo erro que o cabeçalho de seção já
   cometeu neste arquivo: sem ícone, sem fundo, sem `border-radius`, sem alvo de
   toque. A hierarquia vem do TAMANHO e do peso, não de uma caixa.

   ⚠ E É MENOR QUE O CABEÇALHO DA SEÇÃO (.62 contra .68rem), de propósito: se
   os dois tivessem o mesmo peso, o operador leria dois títulos concorrentes e
   perderia qual contém qual.

   ⚠ `--text-faint`, NÃO `--faint`: mede 4,87:1 no pior caso contra 2,78:1 —
   e este texto é a única pista de que a lista mudou de assunto. */
.nav-sep {
  padding: 12px 12px 4px;
  font-size: .62rem; text-transform: uppercase; letter-spacing: .09em;
  color: var(--text-faint); font-weight: 700;
  user-select: none;
}
/* ⚠ O PRIMEIRO NÃO LEVA O RESPIRO DE CIMA: ele encosta no cabeçalho da seção,
   que já tem o seu próprio espaçamento — somados, abririam um buraco que faz o
   primeiro bloco parecer desgarrado. */
.nav-group-items > .nav-sep:first-child { padding-top: 2px; }

/* ---------- 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ó.
   ══════════════════════════════════════════════════════════════════════════ */

/* Idade da leitura no cartão: informação de fundo — ela existe para o dia em
   que o estado está velho, e não pode competir com o estado em si.
   ⚠ ESTE BLOCO ESTAVA DENTRO DO COMENTÁRIO ACIMA, partindo a frase no meio.
   Uma inserção por âncora encontrou o texto certo e caiu no lugar errado: o
   fecha-comentário dele terminava o comentário grande, as duas regras valiam,
   e as SEIS LINHAS seguintes de português viravam seletor — o navegador
   descartava até se recuperar. Âncora se confere pelo CONTEXTO, não pela
   existência (§3.26). */
.auto-idade { font-size: .72rem; color: var(--text-faint); font-weight: 600; }
.auto-idade[hidden] { display: none; }

/* ⚠ `--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; }

/* ═════ BIBLIOTECA DE FOTOS DAS PROPOSTAS ═══════════════════════════════════
   A grade é auto-ajustável: a mesma tela serve a 3 fotos e a 300, sem número
   de colunas chumbado que quebre no celular. */
.filtros-linha { display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-end; margin-bottom: 12px; }
.filtros-linha .field { margin: 0; flex: 1 1 240px; }

.foto-grade { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
.foto-item {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); padding: 10px; display: flex; flex-direction: column; gap: 8px;
}
/* ⚠ A ATENUAÇÃO É SÓ NA IMAGEM, nunca no cartão inteiro: `opacity` no
   contêiner apagaria junto o SELO e a LEGENDA — e é o texto que informa o
   estado, não a transparência (a mesma lição do cartão "Sem resposta",
   §5.96). O selo "Arquivada" tem de continuar legível. */
.foto-item.arquivada img { opacity: .55; }
.foto-item img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: var(--radius-sm); background: var(--surface-2); display: block;
}
.foto-item .field { margin: 0; }
.foto-selo { margin: 0; }
.foto-form { display: flex; flex-direction: column; gap: 6px; }
.foto-acoes { display: flex; flex-wrap: wrap; gap: 6px; }
.foto-meta { margin: 0; font-size: .78rem; }

/* O seletor de fotos dentro do bloco fica recolhido: aberto por padrão, uma
   grade de 40 imagens empurraria o botão de salvar para fora da tela. */
/* Cada bloco da proposta no editor: fechado por padrão (são 23), com o resumo
   dizendo o essencial. ⚠ O alvo do `summary` tem de dar 44px em toque — ele é
   o que se aperta 23 vezes seguidas procurando o bloco certo. */
.bloco-edit > summary {
  cursor: pointer; padding: 10px 2px; display: flex; gap: 8px;
  align-items: center; flex-wrap: wrap;
}
.bloco-edit > summary .muted { font-size: .8rem; }
@media (pointer: coarse) { .bloco-edit > summary { min-height: 44px; } }

.foto-bloco { margin-top: 8px; }
.foto-bloco > summary { cursor: pointer; padding: 6px 0; font-weight: 500; }


/* O seletor dentro do card de blocos da proposta. */
.foto-seletor { display: grid; gap: 8px; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); }
.foto-escolha { position: relative; display: block; cursor: pointer; }
.foto-escolha img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block;
  border-radius: var(--radius-sm);
  /* ⚠ A BORDA É O QUE IDENTIFICA O ESTADO, então precisa de 3:1 — o hairline
     some e o cartão marcado fica indistinguível do não marcado. */
  border: 2px solid var(--border-strong);
}
.foto-escolha input:checked + img { border-color: var(--primary); }
.foto-escolha .fe-num {
  position: absolute; top: 4px; left: 4px; min-width: 22px; height: 22px;
  display: none; align-items: center; justify-content: center;
  border-radius: 999px; background: var(--btn-primary-bg); color: var(--on-accent);
  font-size: .72rem; font-weight: 600; padding: 0 6px;
}
.foto-escolha input:checked ~ .fe-num { display: inline-flex; }
.foto-escolha figcaption { font-size: .74rem; color: var(--text-soft); margin-top: 4px; }

/* ═════ PRÉVIA DO VALOR DA PROPOSTA ═════════════════════════════════════════
   Ela aparece DENTRO do formulário, acima dos botões: o gestor mexe num campo,
   toca em "Ver o valor" e lê o total sem sair da tela nem criar nada. */
.prev-box { margin-top: 14px; border-left: 3px solid var(--primary); }
.prev-box h2 { margin-top: 0; }
.prev-msg { margin: 0 0 8px; }
.prev-valor { text-align: right; white-space: nowrap; }
.prev-nota { font-size: .8rem; }
.prev-total th, .prev-total td {
  border-top: 2px solid var(--border-strong); font-size: 1.15rem; padding-top: 8px;
}

/* Lista sem marcador, com o espaçamento do corpo de texto — para enumerar
   guias, links e itens curtos dentro de um card. Estava sendo usada sem regra
   (o `<ul>` saía com bolinha e recuo do navegador). */
.lista-limpa{ list-style:none; padding:0; margin:0 }
.lista-limpa > li + li{ margin-top:6px }

/* ═══════════════════════════════════════════════════════════════════════════
   CANDIDATOS A CADASTRO (/vehicles/candidatos)

   ⚠ CARTÃO, NÃO LINHA DE TABELA. A foto da passagem é a evidência mais forte
   que a tela tem — e é o que o operador olha antes de decidir cadastrar um
   veículo. Ela não cabe numa célula, e sem ela a decisão passaria a ser tomada
   com base numa frase.
   ═══════════════════════════════════════════════════════════════════════════ */
.cand-lista { display: flex; flex-direction: column; gap: 10px; }

.cand { display: flex; gap: 14px; align-items: flex-start; }
@media (max-width: 640px) { .cand { flex-direction: column; } }

.cand-foto {
  flex: 0 0 190px; max-width: 190px; aspect-ratio: 4/3;
  background: var(--surface-3); border: 1px solid var(--border);
  border-radius: var(--radius-sm); overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
@media (max-width: 640px) { .cand-foto { flex: none; max-width: 100%; width: 100%; } }
.cand-foto img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ⚠ "Sem foto" é DITO, não deixado em branco: um retângulo vazio é
   indistinguível de imagem que não carregou. */
.cand-sem-foto {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  color: var(--text-faint); font-size: .8rem;
}

.cand-corpo { flex: 1 1 auto; min-width: 0; }
.cand-topo { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-bottom: 8px; }
.cand-porque { margin: 0 0 6px; }
.cand-quando { margin: 0 0 10px; font-size: .85rem; }

.cand-acoes { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.cand-desc { display: flex; gap: 6px; align-items: center; margin: 0; flex-wrap: wrap; }
.cand-desc .input-sm { max-width: 230px; }

/* Abas — `aria-current` é quem informa; a cor é o reforço (§3.1). */
.abas { display: flex; gap: 4px; flex-wrap: wrap; }
.aba {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 12px; border-radius: var(--radius-sm);
  color: var(--text-faint); text-decoration: none; font-size: .9rem;
  border: 1px solid transparent;
}
.aba:hover { background: var(--surface-2); }
.aba.ativa {
  background: var(--surface-2); border-color: var(--border-strong);
  color: var(--text); font-weight: 600;
}
.aba-n {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; padding: 0 6px;
  border-radius: 999px; font-size: .75rem; font-weight: 600;
  background: var(--surface-3); color: var(--text);
  /* ⚠ A BORDA AQUI IDENTIFICA (separa o "3" do rótulo, senão "Insistentes 3"
     se lê como um texto só), então vale o mínimo de 3:1 — e --border-strong
     é hairline (1,40:1), não indicador. */
  border: 1px solid var(--text-faint);
}
/* ⚠ FUNDO SÓLIDO usa --btn-primary-bg, nunca --primary cru: o acento sobre
   branco dá 4,44:1 e reprova AA; a versão escurecida existe para isto. */
.aba.ativa .aba-n { background: var(--btn-primary-bg); color: var(--on-accent); border-color: transparent; }

/* Alvo de toque: a aba é navegação principal desta tela. */
@media (pointer: coarse) { .aba { min-height: 44px; } }

.input-sm { padding: 5px 8px; font-size: .85rem; }

/* Ícone em corpo de destaque (hero do /clima quando não há pictograma do tempo).
   ⚠ CLASSE, não `style` inline: o bloco já aparece em duas telas (§5.71) e
   `font-size` não redimensiona SVG — quem manda é width/height. */
.ico-hero { width: 56px; height: 56px; stroke-width: 1.4; }

/* ═══════════════════════════════════════════════════════════════════════════
   O TERCEIRO ESTADO — "não consegui buscar este dado"

   Vindo do design system novo (`design-system/sgci-dimora/base/css/base.css`),
   adaptado aos tokens daqui. É o primeiro componente do DS a entrar no núcleo,
   e foi escolhido por dois motivos: é o que o briefing pedia como requisito
   mais importante, e é o que já estava sendo reinventado.

   ⚠ ELE JÁ EXISTIA EM DOIS LUGARES, ESCRITO DIFERENTE. A linha do tempo
   hachurava a 45° com `--warning-soft`; a saúde do motor, a 45° com
   `--surface-2`. Duas telas que mostram a MESMA ideia — "não consegui olhar" —
   com desenhos diferentes, e a terceira nasceria com um terceiro. Regra
   copiada diverge na primeira correção (§3.16); aqui ela já tinha divergido
   antes da segunda cópia.

   ─── OS QUATRO CANAIS ──────────────────────────────────────────────────────
   O que separa "não sei" de "está tudo bem" não é a cor — é a soma de:

     canal        normal        zero de verdade     NÃO RESPONDEU
     ─────────────────────────────────────────────────────────────
     textura      lisa          lisa                HACHURADA
     contorno     sólido        sólido              TRACEJADO
     o valor      o número      0, escrito          HACHURA no lugar

   ⚠ O TERCEIRO CANAL É O QUE MAIS IMPORTA: no terceiro estado o valor não vira
   "—" nem "0". Vira uma hachura que ocupa o MESMO espaço que o número
   ocuparia. Um travessão lê como zero; a hachura lê como "havia um número aqui
   e eu não consegui buscá-lo".
   ═══════════════════════════════════════════════════════════════════════════ */

/* A textura, uma vez só. Quem precisar de hachura usa esta classe junto com a
   própria geometria — é o que impede a terceira tela de inventar a terceira
   hachura.

   ⚠ A TINTA É `--text-faint`, NÃO `--faint`. O DS usa `--faint`, e ele
   funciona lá porque os componentes dele vivem sobre a superfície do cartão.
   Aqui a hachura cai também sobre a superfície MÉDIA — a faixa da linha do
   tempo — e no tema escuro `--faint` sobre `--surface-2` dá 2,78:1: uma
   textura que mal se vê é um canal de informação que não existe. Medidas as
   seis combinações (dois temas × três superfícies), `--text-faint` passa em
   todas, com 4,87:1 no pior caso. */
.hachura {
  background-image: repeating-linear-gradient(135deg,
    var(--text-faint) 0, var(--text-faint) 1.5px,
    transparent 1.5px, transparent 4px);
}

/* O lugar do valor que não veio. A largura vai em `ch` para ficar do tamanho
   do dado que falta: 3ch numa contagem, 5ch numa temperatura, 8ch num horário. */
.hatch {
  display: inline-block;
  min-width: 3ch; height: 1.05em;
  vertical-align: -.18em;
  background-color: var(--surface-3);
  background-image: repeating-linear-gradient(135deg,
    var(--text-faint) 0, var(--text-faint) 1.5px,
    transparent 1.5px, transparent 4px);
  /* ⚠ A BORDA E CANAL DE INFORMACAO, nao contorno decorativo — e ela que
     sobrevive ao alto contraste do sistema, quando a cor da hachura e
     descartada. `--border-strong` e o MESMO #7d8289 que a medicao ja tinha
     reprovado para a tinta: 2,78:1 no escuro. A tinta foi corrigida na epoca e
     a borda ficou para tras, no mesmo bloco. Alvo 3:1 (WCAG 1.4.11). */
  border: 1px dashed var(--text-faint);
  border-radius: var(--radius-xs);
}
.hatch.w2 { min-width: 2ch; }
.hatch.w5 { min-width: 5ch; }
.hatch.w8 { min-width: 8ch; }
.hatch.w12 { min-width: 12ch; }
/* Bloco, para o lugar de um gráfico, uma faixa ou uma foto que não veio. */
.hatch.block { display: block; width: 100%; height: auto; min-height: 56px; }

/* A célula inteira, quando a linha existe mas aquela coluna não respondeu. */
td.unknown, th.unknown { color: var(--text-faint); }

/* ⚠ A ORIGEM, SEMPRE VISÍVEL. No terceiro estado isto vira obrigação: quem não
   respondeu, e desde quando. Sem essa linha o operador não sabe se reinicia a
   câmera ou se liga para o provedor — a tela diria "não sei" e o mandaria
   adivinhar o resto. */
.since {
  font-family: var(--font-mono);
  /* ⚠ `--text-faint`, pelo mesmo motivo da hachura logo acima. O comentario
     dali mediu as 6 combinacoes e concluiu que `--faint` dava 2,78:1 — e esta
     linha, escrita junto, ficou com `--faint` mesmo. A regra valia para as
     duas: a `.since` e a frase que explica a hachura, e hachura muda e um
     beco (§6.1.2). */
  font-size: 10.5px; color: var(--text-faint); white-space: nowrap;
}

/* ⚠ ALTO CONTRASTE DO SISTEMA OPERACIONAL. Ali o navegador joga fora a nossa
   cor, e com ela a hachura. A FORMA e o TRACEJADO sobrevivem — e é por isso
   que o tracejado é canal de informação, não enfeite. Sem este bloco, o
   terceiro estado ficaria idêntico ao normal para quem mais precisa dele. */
@media (forced-colors: active) {
  .hatch, .hachura {
    border: 1px dashed CanvasText;
    background: Canvas;
    forced-color-adjust: none;
  }
}

/* ── Rodapé com a versão ────────────────────────────────────────────────────
   ⚠ MORA AQUI, e não num <style> de view: ele aparece em TODA tela, então é do
   design system por definição. Bloco de estilo que aparece em duas telas sobe
   ANTES da segunda cópia, não depois (§5.71). */
.app-rodape {
  margin: 28px 0 0;
  padding: 12px 0 4px;
  border-top: 1px solid var(--border);
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  font-size: .78rem; color: var(--text-faint);
}
.app-rodape a {
  color: var(--text-faint); text-decoration: none;
  /* Alvo de toque decente sem inchar a linha no desktop. */
  padding: 4px 2px;
}
.app-rodape a:hover { color: var(--text); text-decoration: underline; }
.app-rodape-sep { opacity: .5; }
@media (pointer: coarse) { .app-rodape a { padding: 10px 4px; } }
/* Numa folha impressa, "o que mudou" não leva a lugar nenhum. */
/* ═══════════════════════════════════════════════════════════════════════════
   IMPRESSÃO — a folha REAFIRMA o tema claro, nunca o herda.

   ⚠ ESTA REGRA FALTAVA, E O CLAUDE.md AFIRMAVA QUE ELA EXISTIA. A Dimora a tem
   desde sempre; o sgci.io não tinha, e o §3.20 descrevia a lição como se
   valesse para os dois. Alguém consertou num app, escreveu o aprendizado, e o
   outro ficou sem — que é a mesma classe de defeito do §3.16, atravessando os
   dois produtos.

   ⚠ O ESTRAGO É SILENCIOSO. O navegador não imprime cor de fundo: no tema
   escuro, `--text` é quase branco e o papel é branco. Qualquer tela que alguém
   mande imprimir sai quase vazia — a linha do tempo, a saúde do motor, uma
   lista, um relatório. E há botão de "Imprimir" dentro do sistema: a ficha de
   patrimônio tem um, e ela usa o layout padrão.

   ⚠ MAS NÃO SÃO AS TELAS DE IMPRESSÃO DEDICADAS, e eu quase escrevi isso aqui.
   A ordem de serviço, o ticket do valet, as etiquetas e a proposta são
   STANDALONE: têm `<html>` próprio e não carregam esta folha, então nunca
   herdaram o tema escuro. Elas estavam certas. Verificar o caminho inteiro
   antes de afirmar o diagnóstico é o que separou "as telas de impressão estão
   quebradas" (falso) de "toda tela normal impressa está" (verdadeiro).

   ⚠ SÓ OS TOKENS QUE A FOLHA USA, não o tema claro inteiro reescrito — é o
   padrão que a Dimora já usa. Reescrever tudo duplicaria a paleta e sairia de
   sincronia na primeira mudança da ponte. Ao acrescentar uma cor que precise
   sair no papel, acrescente aqui também.
   ═══════════════════════════════════════════════════════════════════════════ */
@media print {
  :root, :root[data-theme="dark"] {
    --bg: #ffffff;
    --surface: #ffffff;
    --surface-2: #ffffff;
    --surface-3: #f2f2f2;
    --text: #111111;
    --text-soft: #333333;
    --text-faint: #444444;
    --faint: #666666;
    --border: #bbbbbb;
    --border-strong: #888888;
    /* O acento vira tinta escura: azul claro sobre papel branco não se lê. */
    --primary: #2b2d31;
    --primary-dark: #111111;
    --primary-soft: #f2f2f2;
    --accent-text: #111111;
    --on-accent: #ffffff;
    --info: #2b2d31;
    --info-soft: #f2f2f2;
    --info-text: #111111;

    /* ⚠ AS CORES DE ESTADO PRECISAM ENTRAR, e quase ficaram de fora. No tema
       escuro `--success-text` é verde CLARO (#34c97e) — no papel branco ele
       simplesmente some. E selo de estado aparece em relatório impresso: a
       fila de revisão, a saúde do motor, qualquer lista com situação. São os
       tons do tema claro, que já foram escolhidos para ler sobre branco. */
    --success: #2a5d37;      --success-soft: #eef5ef;  --success-text: #2a5d37;
    --warning: #714500;      --warning-soft: #f7f1e8;  --warning-text: #714500;
    --danger:  #7b3935;      --danger-soft:  #f7eceb;  --danger-text:  #7b3935;
    --neutral: #4d5156;      --neutral-soft: #f2f2f2;  --neutral-text: #4d5156;

    /* Botão raramente vai ao papel, mas quando vai tem de ser legível. */
    --btn-primary-bg: #2b2d31;
    --btn-success-bg: #2a5d37;
    --btn-warning-bg: #714500;
    --btn-danger-bg:  #7b3935;

    /* Gradiente não existe no papel. */
    --primary-grad-1: #2b2d31;
    --primary-grad-2: #2b2d31;
    --bg-grad-1: #ffffff;
    --bg-grad-2: #ffffff;

    color-scheme: light;
  }

  /* ⚠ A HACHURA TEM DE SOBREVIVER AO PAPEL. Sem `print-color-adjust`, o
     navegador descarta o `background-image` e o terceiro estado vira um
     retângulo vazio — a distinção entre "zero" e "não consegui buscar" morre
     justamente no formato que alguém vai arquivar ou levar para uma reunião. */
  .hachura, .hatch {
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
  }

  /* O que não vai para o papel. */
  .app-header, .sidebar, .bottom-nav, .menu-drawer,
  .skip-link, .app-rodape, .panic-btn, .theme-toggle, .flash { display: none !important; }

  /* ⚠ Link impresso perde o destino. Num relatório que alguém vai arquivar, a
     URL entre parênteses é a diferença entre "clique aqui" e uma referência. */
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9px; color: var(--text-faint); }

  /* ⚠ OS TOKENS DA MARCA TAMBEM SE DESFAZEM NO PAPEL. Eles entraram na ponte
     DEPOIS que este bloco foi escrito, e por isso ficaram de fora: no tema
     escuro `--mark-signal` e um lilas CLARO (#9ea0fa) que na folha branca da
     2,37:1. Hoje o efeito e inerte — a marca so aparece no cabecalho, que a
     impressao esconde — mas qualquer `H::brandMark()` em conteudo imprimivel
     traz o defeito de volta, e o token e o mesmo. E o §3.20 com cinco tokens
     a mais: nao basta desfazer fundo e texto. */
  :root, :root[data-theme="dark"] {
    --mark-signal:           #6664c0;
    --mark-signal-strong:    #49429f;
    --mark-signal-soft:      #f4f5ff;
    --mark-signal-border:    #d6d9ff;
    --mark-signal-on-chrome: #9ea0fa;
  }
}

/* ── Corpo de markdown renderizado ──────────────────────────────────────────
   Usado pelo /docs e pela tela de versao. Subiu do <style> da view do /docs
   quando a segunda tela apareceu — regra copiada diverge na primeira
   correcao, e quem paga e a tela que ninguem lembrou de atualizar. */
.doc-body { line-height:1.65; overflow-wrap:anywhere; }
.doc-body h1 { font-size:1.45rem; margin:0 0 12px; }
.doc-body h2 { font-size:1.15rem; margin:26px 0 8px; padding-bottom:6px; border-bottom:1px solid var(--border); scroll-margin-top:16px; }
.doc-body h3 { font-size:1rem; margin:18px 0 6px; scroll-margin-top:16px; }
.doc-body h4, .doc-body h5, .doc-body h6 { font-size:.92rem; margin:14px 0 4px; }
.doc-body p { margin:0 0 10px; }
.doc-body ul, .doc-body ol { margin:0 0 10px; padding-left:22px; }
.doc-body li { margin:3px 0; }
.doc-body li > ul, .doc-body li > ol { margin:3px 0; }
.doc-body hr { border:0; border-top:1px solid var(--border); margin:22px 0; }
.doc-body a { color:var(--accent-text); }
.doc-body code { background:var(--bg); border:1px solid var(--border); border-radius:var(--radius-xs); padding:1px 5px; font-size:.85em; }
.doc-body pre.md-code { background:var(--bg); border:1px solid var(--border); border-radius:var(--radius-sm); padding:12px 14px; overflow:auto; margin:0 0 12px; position:relative; }
.doc-body pre.md-code code { background:none; border:0; padding:0; font-size:.83rem; line-height:1.5; white-space:pre; }
.doc-body blockquote { margin:0 0 12px; padding:8px 14px; border-left:3px solid var(--primary); background:var(--bg); border-radius:0 var(--radius-sm) var(--radius-sm) 0; }
.doc-body blockquote p:last-child { margin-bottom:0; }
.doc-body .md-table-wrap { overflow-x:auto; margin:0 0 12px; }
.doc-body table.data { font-size:.85rem; }
.doc-body strong { font-weight:600; }


/* ═══════════════════════════════════════════════════════════════════════════
   A FAIXA LATERAL — só em card que REPRESENTA um estado

   ⚠ `.card.estado-*`, NÃO `.card`. Um cartão de conteúdo comum com barra
   colorida na lateral ganha uma moldura decorativa que não diz nada — e, pior,
   ensina o olho a ignorar a faixa justamente onde ela carrega informação
   (§3.10). Use em cartão que É um estado: a cisterna, a saúde do motor, o
   alarme, o worker. Não use em cartão que apenas CONTÉM dados.

   ⚠ E A FAIXA NUNCA VEM SOZINHA. Ela acompanha um selo ou um texto que diz o
   mesmo — cor não comunica estado sozinha (§6.2), e quem não distingue verde
   de âmbar precisa da palavra.
   ═══════════════════════════════════════════════════════════════════════════ */
.card.estado-ok      { border-left: 3px solid var(--success); }
.card.estado-atencao { border-left: 3px solid var(--warning); }
.card.estado-ruim    { border-left: 3px solid var(--danger); }
.card.estado-info    { border-left: 3px solid var(--info); }
/* ⚠ O quarto estado (§3.4) também tem faixa, e ela é TRACEJADA: "não consegui
   olhar" não pode parecer "está tudo bem" nem "está ruim". */
.card.estado-incerto { border-left: 3px dashed var(--text-faint); }

/* ═══════════════════════════════════════════════════════════════════════════
   O FIO NA LINHA DE TABELA — o mesmo vocabulário, na lista

   ⚠ UM FIO DE 3px, NÃO A LINHA PINTADA. Pintar o fundo da linha inteira numa
   tabela de 40 registros produz o mosaico que o §3.10 descreve; o fio à
   esquerda dá o mesmo relance sem competir com o texto da linha.
   ═══════════════════════════════════════════════════════════════════════════ */
table.data tr.estado-ok      > td:first-child { box-shadow: inset 3px 0 0 var(--success); }
table.data tr.estado-atencao > td:first-child { box-shadow: inset 3px 0 0 var(--warning); }
table.data tr.estado-ruim    > td:first-child { box-shadow: inset 3px 0 0 var(--danger); }
table.data tr.estado-info    > td:first-child { box-shadow: inset 3px 0 0 var(--info); }

/* ⚠ NO MODO CARTÃO DO CELULAR a linha vira um bloco, e o `inset` na primeira
   célula sumiria no meio dele. A faixa migra para a borda do cartão. */
@media (max-width: 720px) {
  table.data.cards-mobile tr.estado-ok      { border-left: 3px solid var(--success); }
  table.data.cards-mobile tr.estado-atencao { border-left: 3px solid var(--warning); }
  table.data.cards-mobile tr.estado-ruim    { border-left: 3px solid var(--danger); }
  table.data.cards-mobile tr.estado-info    { border-left: 3px solid var(--info); }
  table.data.cards-mobile tr[class*="estado-"] > td:first-child { box-shadow: none; }
}


/* ⚠ SUBIU DO `<style>` DA /linha-do-tempo QUANDO A SEGUNDA TELA APARECEU, e não
   depois: bloco de estilo que serve a duas telas é do design system (§3.16). O
   componente `components/linha_tempo_lista.php` usa isto, e ele agora vive
   também na ficha da pessoa — deixar a regra na tela de origem faria o
   componente sair CRU na outra, sem erro nenhum para investigar (§6.5). */
.lt-tag { display: inline-flex; align-items: center; gap: 5px; font-size: .85rem; }

/* A AÇÃO SUGERIDA — o que fazer a respeito, e quem resolve.

   ⚠ VIVE NO DESIGN SYSTEM DESDE A PRIMEIRA TELA, e não na segunda: o bloco
   entra nas quatro que incluem o componente (busca de acessos, linha do tempo,
   ficha da pessoa, ficha do veículo) e escrevê-lo numa delas faria as outras
   três saírem cruas, sem erro nenhum para investigar (§6.5).

   ⚠ A BARRA LATERAL É O CANAL, NÃO A COR. Num tema escuro, num alto contraste
   do sistema ou numa folha impressa, a cor pode se perder — a borda de 3px
   sobrevive aos três e continua dizendo "isto aqui é outra coisa, é uma
   instrução". Cor sozinha nunca comunica estado (§6.2).

   ⚠ E É `--warning-text`, NÃO `--warning`: as cores de acento reprovam em AA
   como texto pequeno, e este texto tem .84rem. */
.lt-acao {
  margin: 6px 0 0;
  padding: 6px 10px;
  border-left: 3px solid var(--warning);
  background: var(--warning-soft);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  font-size: .84rem;
  line-height: 1.45;
  color: var(--text);
}
/* ⚠ QUEM RESOLVE É A SEGUNDA PERGUNTA, e ela merece peso — é o que separa
   "eu resolvo agora" de "preciso chamar alguém". */
.lt-acao strong { display: block; margin-top: 2px; color: var(--warning-text); }

/* ⚠ NO PAPEL A TARJA TEM DE SOBREVIVER. O navegador não imprime fundo por
   padrão (§3.20): sem isto, a instrução sairia como um parágrafo solto no meio
   da tabela, sem nada indicando que é outra coisa. A borda basta. */
@media print {
  .lt-acao { background: none; border-left-color: #000; }
  .lt-acao strong { color: #000; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   RELATÓRIOS — a miniatura da foto e a fila de ações da linha.

   ⚠ ESTE BLOCO SUBIU PARA CÁ NA SEGUNDA CÓPIA, NÃO NA TERCEIRA. Ele nasceu no
   `<style>` da aba "Quem mais passa"; quando escrevi a de aniversários,
   copiei — e as duas já iam divergir na primeira correção, porque nada liga uma
   à outra. Bloco de estilo que aparece em duas telas é do design system, e sobe
   ANTES da segunda cópia (§3.16). A de "Pessoas" seria a terceira.

   ⚠ 3:4 É O MESMO RECORTE QUE VAI AO InControl (`ImageTools::crop3x4`).
   Qualquer outra proporção deforma o rosto — e é pela foto que o operador
   reconhece a pessoa (§3.13).
   ═══════════════════════════════════════════════════════════════════════════ */
.rp-foto {
  width: 44px; height: 59px;
  object-fit: cover;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  display: block;
}
/* ⚠ A hachura do "sem foto" ocupa o MESMO espaço da imagem: ausência de foto
   tem de ler como um lugar vazio, não como uma linha mais estreita (§6.1.2). */
.rp-semfoto { display: inline-block; }
.rp-acoes { display: flex; gap: 6px; justify-content: flex-end; }
@media (max-width: 760px) { .rp-acoes { justify-content: flex-start; } }

/* ── A GRADE DE FINS DE SEMANA da emissão de cortesia ───────────────────────
   ⚠ AQUI, E NÃO NUM `<style>` DA VIEW. Bloco de estilo que aparece numa tela é
   do design system assim que aparece numa segunda — e a segunda deste é a tela
   de janela de cortesia, da fatia 2 (§3.16: sobe ANTES da cópia, não depois).

   ⚠ E ELE NÃO É O `.day-picker`, apesar de a marcação ser parecida — os dois
   são um `<label>` com `input` escondido dentro. Aquele desenha QUADRADOS de
   44×44 para os dias da semana ("S T Q Q S S D"); aqui o rótulo é uma FAIXA de
   texto ("6 a 8 de março de 2026"), que num quadrado de 44px transbordaria.
   Reusá-lo seria o caso do `.form-grid`/`.grid-2` ao contrário: lá eu ia
   escrever a terceira cópia de um comportamento existente, aqui eu ia usar um
   componente que não faz o que a tela pede (§6.5). Fica escrito para ninguém
   "unificar" os dois depois.

   ⚠ O ALVO DE TOQUE É O `<label>` INTEIRO, com 44px de altura mínima: o gestor
   marca cinco ou seis datas de uma vez, e um alvo do tamanho da caixinha faz
   metade dos cliques errarem (§6.3). */
.ct-grade{
  display:grid;gap:8px;
  grid-template-columns:repeat(auto-fill, minmax(220px, 1fr));
  margin-top:12px;
}
.ct-op{
  display:flex;align-items:center;gap:10px;
  min-height:44px;padding:8px 12px;cursor:pointer;
  border:1px solid var(--border);border-radius:var(--radius-sm);
  background:var(--surface);font-size:14px;
}
.ct-op:hover{border-color:var(--border-strong)}
/* ⚠ O MARCADO MUDA POR DOIS CANAIS — borda E fundo. Cor sozinha some no alto
   contraste do sistema operacional, e aí a grade inteira fica igual (§6.1.2). */
.ct-op:has(input:checked){border-color:var(--primary);background:var(--primary-soft)}
/* ⚠ `var(--ring-color, …)` ERA UM TOKEN QUE NUNCA EXISTIU: o fallback valeria
   SEMPRE, e um nome que nunca resolve lê-se como token de verdade para a
   próxima pessoa. A convenção da folha é `outline: 2px solid var(--primary)`,
   e é a que o `.day-picker` já usa. */
.ct-op:focus-within{outline:2px solid var(--primary);outline-offset:2px}
.ct-op input{flex:none;width:18px;height:18px}

/* ═══════════════════════════════════════════════════════════════════════════
   DESLIZE PARA ABRIR — o controle de abertura de porta.

   ⚠ ELE ESTAVA ESCRITO À MÃO EM DUAS VIEWS, e as cópias já tinham divergido:
   trilho de 62px numa e 66px na outra, punho de 52 e 54, rótulo em .92rem e
   .95rem, folga de 10px e 12px no fim do curso. Nada ligava uma à outra, e
   ninguém abre as duas lado a lado — o `/k/{token}` é um link que vai para o
   celular de um visitante, o `/cerberus` é a portaria remota (§3.16).

   ⚠ A ALTURA DO PUNHO MORA AQUI, E O JS A MEDE. Era um número escrito nos dois
   lugares (`Math.max(62, …)` numa view, `Math.max(66, …)` na outra): mudar o
   CSS sem mudar o JS deixaria o preenchimento desencontrado do punho, e a
   terceira tela nasceria com um terceiro par.

   ⚠ A GEOMETRIA É DE TOQUE: 62px de trilho e 52 de punho passam dos 44×44 do
   §6.3 com folga — quem usa isto está com o celular numa mão, de noite, na
   frente de um portão.
   ═══════════════════════════════════════════════════════════════════════════ */
.deslize {
  position: relative;
  height: 62px;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  overflow: hidden;
  user-select: none;
  touch-action: none;
}
.deslize:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.deslize .dz-fill {
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 62px; border-radius: 999px;
  background: linear-gradient(135deg, var(--primary-grad-1), var(--primary-grad-2));
  opacity: .22;
  transition: width .05s linear;
}
.deslize .dz-label {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: .92rem;
  color: var(--text-soft);
  pointer-events: none;
  padding: 0 64px;
  text-align: center;
}
.deslize .dz-handle {
  position: absolute; top: 5px; left: 5px;
  width: 52px; height: 52px; border-radius: 50%;
  background: linear-gradient(135deg, var(--primary-grad-1), var(--primary-grad-2));
  color: var(--on-accent);
  display: flex; align-items: center; justify-content: center;
  font-size: 1.4rem; font-weight: 800;
  cursor: grab; touch-action: none;
  box-shadow: 0 6px 16px color-mix(in srgb, var(--primary) 40%, transparent);
}
.deslize.dz-arrastando .dz-handle { cursor: grabbing; }

/* ── OS QUATRO ESTADOS, e cada um fala por DOIS canais (cor + palavra) ──────
   ⚠ `warn` É O TERCEIRO ESTADO DA ABERTURA (§3.5): "não sei se abriu". Ele é
   TRACEJADO de propósito — no alto contraste do sistema a cor é descartada e
   sobraria um aviso idêntico ao normal, que é justamente o caso em que a
   pessoa não pode apertar de novo (§6.1.2). */
.deslize[data-state="success"] { border-color: var(--success); }
.deslize[data-state="success"] .dz-handle { background: var(--success); box-shadow: none; }
.deslize[data-state="error"] { border-color: var(--danger); }
.deslize[data-state="error"] .dz-handle { background: var(--danger); box-shadow: none; }
.deslize[data-state="processing"] .dz-handle { background: var(--warning); }
.deslize[data-state="warn"] { border-color: var(--warning); border-style: dashed; }
/* ⚠ A HACHURA NO PUNHO É O QUARTO CANAL, E EU QUASE A PERDI NA EXTRAÇÃO.
   `processing` e `warn` usam o MESMO âmbar — um é "estou tentando", o outro é
   "tentei e não sei" —, e sem a textura os dois ficam idênticos justamente no
   estado em que a pessoa não pode tocar de novo. É o desenho que o design
   system já usa para "havia um dado aqui e eu não consegui buscá-lo" (§6.1.2),
   e aqui o dado que falta é o desfecho da abertura. Ela estava na view antiga,
   com o motivo escrito ao lado; a cópia nova nasceria pior que a velha, que é
   o §3.16 na direção que ninguém espera. */
.deslize[data-state="warn"] .dz-handle {
  background: var(--warning);
  box-shadow: none;
  background-image: repeating-linear-gradient(135deg,
    color-mix(in srgb, var(--on-accent) 40%, transparent) 0,
    color-mix(in srgb, var(--on-accent) 40%, transparent) 2px,
    transparent 2px, transparent 6px);
}

/* ⚠ `sem-js` É O ESTADO EM QUE A MARCAÇÃO NASCE. O deslize só vira `ready`
   quando o `deslize.js` liga nele; com o script num arquivo externo, "não
   carregou" passou a ser um caso possível — e um controle que parece pronto e
   não faz nada é pior que controle ausente (§3.21). Aqui ele fica apagado e
   DIZ o que fazer. */
.deslize[data-state="sem-js"] { opacity: .55; }
.deslize[data-state="sem-js"] .dz-handle { background: var(--neutral); box-shadow: none; cursor: default; }

/* ⚠ A LINHA DE STATUS CARREGA O VEREDITO, não um rótulo de apoio — é nela que
   a frase do servidor aparece ("Sem confirmação", o motivo da recusa). O peso
   e o tamanho são os da view antiga de propósito: eu tinha escrito `.82rem` em
   `--text-faint`, que rebaixa justamente a frase que a pessoa precisa ler de
   pé na frente do portão. */
.dz-status { margin: 9px 0 0; font-size: .9rem; font-weight: 650; color: var(--text-soft); text-align: center; }

/* ⚠ A HACHURA PRECISA DE `print-color-adjust` NO ALTO CONTRASTE E NO PAPEL,
   mas aqui NÃO: esta tela não é impressa, e no `forced-colors` o navegador
   descarta a nossa cor — o que sobrevive é a FORMA. É por isso que a borda
   engrossa e o tracejado fica: eles são canal de informação, não enfeite
   (§6.1.2). */
@media (forced-colors: active) {
  .deslize { border-width: 2px; }
  .deslize[data-state="warn"] { border-width: 3px; border-style: dashed; }
}
