/* Horus — estilo mobile-first, alto contraste, alvos de toque grandes (spec §5).
   Reforma 2026-08-16/17 (pedido do Douglas: "layout parece gambiarra"), pesquisa
   real feita antes (ver VPS/CHANGELOG.md 2026-08-16): raio menor (6-12px, não
   14-20 — canto muito arredondado lê como app de consumidor, não ferramenta de
   trabalho), borda hairline no lugar de sombra pesada pra separar superfície
   (sombra suave grande é hoje o cliché nº1 de "dashboard gerado por IA"),
   navegação lateral em vez de barra horizontal com scroll (>8 abas não cabe numa
   barra de jeito nenhum).
   Tema: chegou a existir claro/escuro por tela (claro nas telas de operação,
   escuro no Relatório/gestão — achado real de pesquisa: POS de chão de loja
   como Toast/Square usa tema claro de propósito, dark mode piora legibilidade
   sob sol). Douglas testou e não gostou da MISTURA ("cria um padrão e mantém
   pra tudo" — 2026-08-17): app inteiro voltou a ser 1 tema só, agora CLARO
   (mesma paleta que já tinha ficado boa nas telas de operação), não mais o
   escuro original. Token com o mesmo nome em toda parte — trocar de novo no
   futuro (se pedir) é só mexer aqui, sem tocar regra por regra. */
/* Paleta trocada pra bater com a logo do Veloz (2026-08-17): azul-céu vibrante
   (respingo d'água da logo) como acento principal — botão, aba ativa, destaque
   — e azul-marinho (cor do texto "VELOZ" na logo) pra info/link, papel que
   --azul já tinha antes. Amarelo/dourado da logo (faixa embaixo do carro) NÃO
   virou 3º acento de propósito — pesquisa já feita nesse projeto (ver
   VPS/CHANGELOG.md 2026-08-16) recomenda 1 acento saturado só, dois azuis com
   papel diferente (ação vs. info) não quebra essa regra. */
:root {
  --bg: #f4f5f7; --bg-card: #ffffff; --bg-elevado: #eef0f3; --bg-elevado-2: #e3e6ea;
  --texto: #14181f; --texto-sub: #5b6472; --texto-sub2: #838d9c;
  --primario: #0ea5e9; --primario-escuro: #0284c7; --primario-fraco: rgba(14,165,233,.12);
  --alerta: #dc2626; --aviso: #b45309; --azul: #2d4a9e;
  --borda: rgba(15,23,42,.10); --borda-forte: rgba(15,23,42,.20);
  --sombra: 0 1px 3px rgba(15,23,42,.08);
  --radius: 10px; --radius-sm: 8px; --radius-lg: 16px;
  --transicao: 120ms ease;
  color-scheme: light;
}
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
/* overscroll-behavior-y: none bloqueava também o "puxar pra atualizar" nativo do
   celular — deixado livre de propósito (Douglas usa isso pra forçar recarregar
   quando quer garantir que pegou a versão mais nova). */
html, body { height: 100%; margin: 0; overscroll-behavior-x: none; }
body {
  background: var(--bg); color: var(--texto);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: 16px; -webkit-user-select: none; user-select: none;
  -webkit-font-smoothing: antialiased;
  transition: background var(--transicao), color var(--transicao);
}
h1, h2, h3 { margin: 0 0 8px; letter-spacing: -.01em; }
.hidden { display: none !important; }

button { font: inherit; color: inherit; cursor: pointer; background: none; border: none; padding: 0; }
button:disabled { cursor: default; opacity: .5; }
/* Anel de foco só aparece pra navegação por teclado (Tab), não some no toque/clique —
   acessível sem voltar a ter a "caixa feia" que o Douglas reportou (essa vinha do
   <button> nativo sem reset, corrigido abaixo). */
button:focus { outline: none; }
button:focus-visible { outline: 2px solid var(--azul); outline-offset: 2px; }

/* Botões grandes — regra de ouro: nada obrigatório digitado se puder ser toque */
.btn { min-height: 48px; padding: 12px 20px; border-radius: var(--radius); border: none; font-size: 16px; font-weight: 600; transition: background var(--transicao), transform var(--transicao), opacity var(--transicao); }
.btn:active { transform: scale(.98); }
.btn-grande { min-height: 64px; font-size: 20px; width: 100%; }
.btn-primario { background: var(--primario); color: #06213a; box-shadow: 0 2px 10px rgba(14,165,233,.28); }
.btn-primario:hover { background: #38bdf8; }
.btn-primario:active { background: var(--primario-escuro); }
.btn-perigo { background: var(--alerta); color: #2a0a0a; }
.btn-perigo:hover { background: #ff8a8a; }
.btn-link { background: transparent; border: none; padding: 6px 2px; color: var(--azul); text-decoration: none; min-height: 44px; font-weight: 600; border-radius: var(--radius-sm); }
.btn-link:hover { text-decoration: underline; }
.btn-secundario { background: var(--bg-elevado); color: var(--texto); border: 1px solid var(--borda); }
.btn-secundario:hover { background: var(--bg-elevado-2); }

/* Login por PIN */
#tela-login { min-height: 100vh; display: flex; align-items: center; justify-content: center; }
.login-box { text-align: center; width: 100%; max-width: 360px; padding: 24px; }
.login-box h1 { font-size: 40px; margin: 0 0 4px; }
.login-box .logo-login { max-width: 260px; width: 80%; height: auto; margin: 0 0 8px; }
.sub { color: var(--texto-sub); margin: 0 0 20px; }
.login-box form { text-align: left; }
.login-box .btn { width: 100%; margin-top: 4px; }
.erro { color: var(--alerta); margin-bottom: 12px; font-weight: 600; }

/* App shell — sidebar fixa no desktop, barra inferior + "Mais" no celular (troca
   2026-08-16: barra horizontal com scroll/gaveta hambúrguer, que escondia opção
   usada todo dia, virou sidebar de verdade ≥900px; <900px vira barra inferior
   com as 4 ações mais usadas na operação + "Mais" com o resto — pesquisa real:
   >8 seções não cabe em tab bar, mas tab bar de 3-5 itens é o que funciona bem
   no polegar; sidebar com tudo listado é o padrão pra ferramenta com muita
   seção). */
/* height (não só min-height) é o que faz #conteudo realmente rolar SOZINHO
   dentro da viewport (achado 2026-08-17, revisando o pedido do WhatsApp de
   ocupar o espaço certo): sem isso .app-corpo cresce do tamanho do conteúdo e
   quem rola é a página inteira, então "100%" de altura dentro de #conteudo
   (ex: o chat do WhatsApp) não tinha contra o que se ajustar de verdade. */
#app { height: 100vh; display: flex; }
.badge { background: var(--azul); color: #06182f; padding: 2px 10px; border-radius: 999px; font-size: 12px; font-weight: 700; text-transform: uppercase; }
/* Candidatos (2026-08-13) — status da ficha. */
.badge-novo { background: var(--azul); color: #06182f; }
.badge-em-analise { background: var(--aviso); color: #3d2c00; }
.badge-aprovado { background: var(--primario); color: #06213a; }
.badge-rejeitado { background: var(--alerta); color: #450a0a; }

.sidebar { display: none; }
#btn-sidebar-abrir { display: none; } /* só existe ≥900px, ver dentro da media query */
.app-corpo { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.sidebar-marca { display: flex; align-items: center; font-size: 21px; font-weight: 800; letter-spacing: -.02em; color: var(--primario); }
.marca-icone { width: 26px; height: 26px; object-fit: contain; flex-shrink: 0; margin-right: 8px; }
.sidebar-marca #btn-sidebar-fechar { margin-left: auto; }
.nav-abas { display: flex; flex-direction: column; gap: 2px; }
.nav-abas button { display: flex; align-items: center; gap: 12px; white-space: nowrap; transition: background var(--transicao), color var(--transicao); }
.nav-abas button svg { flex-shrink: 0; opacity: .8; transition: opacity var(--transicao); }
.nav-abas button.ativo svg { opacity: 1; }
.sidebar-usuario { display: flex; align-items: center; gap: 8px; min-width: 0; }
.sidebar-usuario strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

@media (min-width: 900px) {
  .sidebar {
    display: flex; flex-direction: column; width: 224px; min-width: 224px;
    height: 100vh; position: sticky; top: 0;
    background: var(--bg-card); border-right: 1px solid var(--borda);
    overflow: hidden;
    transition: width 160ms ease, min-width 160ms ease;
  }
  .sidebar-marca { padding: 22px 22px 16px; white-space: nowrap; }
  .sidebar-busca { padding: 0 16px 10px; }
  .sidebar-busca input {
    width: 100%; min-height: 36px; font-size: 13px; padding: 7px 10px; border-radius: var(--radius-sm);
    border: 1px solid var(--borda); background: var(--bg-elevado); color: var(--texto);
  }
  .sidebar-busca input:focus { outline: none; border-color: var(--azul); }
  .nav-abas { padding: 4px 12px; flex: 1; overflow-y: auto; }
  .nav-abas button { padding: 10px 12px; border-radius: var(--radius-sm); color: var(--texto-sub); font-weight: 600; font-size: 14px; text-align: left; }
  .nav-abas button:hover { color: var(--texto); background: var(--bg-elevado); }
  .nav-abas button.ativo { background: var(--primario-fraco); color: var(--primario); }
  .sidebar-rodape { padding: 14px 16px 18px; border-top: 1px solid var(--borda); display: flex; flex-direction: column; gap: 8px; white-space: nowrap; }
  .nav-mobile, #mais-fundo { display: none !important; }

  /* Sidebar retrátil — botão de FECHAR mora dentro dela mesma (canto da marca
     "Horus"); botão de REABRIR (2026-08-17: "tem que ficar na esquerda, olhe
     vários sistemas" — não fixo na direita, do outro lado da tela) só existe
     quando ela está oculta, na mesma quina esquerda que ela ocupava. Estado
     lembrado entre sessões (ver app.js). */
  #btn-sidebar-fechar {
    width: 26px; height: 26px; min-height: 0; border-radius: 6px; color: var(--texto-sub);
    font-size: 15px; line-height: 1; display: flex; align-items: center; justify-content: center;
  }
  #btn-sidebar-fechar:hover { color: var(--texto); background: var(--bg-elevado); }
  #btn-sidebar-abrir { display: none; }
  #app.sidebar-oculta .sidebar { width: 0; min-width: 0; border-right: none; }
  #app.sidebar-oculta #btn-sidebar-abrir {
    display: flex; align-items: center; justify-content: center;
    position: fixed; top: 14px; left: 14px; z-index: 45;
    width: 38px; height: 38px; border-radius: var(--radius-sm);
    background: var(--bg-card); border: 1px solid var(--borda); color: var(--texto-sub);
    font-size: 16px; cursor: pointer; transition: background var(--transicao), color var(--transicao);
  }
  #app.sidebar-oculta #btn-sidebar-abrir:hover { color: var(--texto); background: var(--bg-elevado); }
}

#conteudo { flex: 1; padding: 12px; overflow-y: auto; max-width: 720px; margin: 0 auto; width: 100%; }
@media (min-width: 900px) { #conteudo { max-width: 1400px; padding: 24px 32px; } }

/* Barra inferior (<900px) — só as ações mais usadas na operação (Fila sempre 1º)
   + "Mais" abrindo uma folha com o resto (inclusive Relatório/Cadastros pra
   quem tem permissão, e "Trocar usuário"). */
.nav-mobile {
  display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  background: var(--bg-card); border-top: 1px solid var(--borda);
  padding-bottom: env(safe-area-inset-bottom);
}
.nav-mobile button { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 8px 4px 7px; color: var(--texto-sub); font-size: 10px; font-weight: 700; min-height: 0; }
.nav-mobile button.ativo { color: var(--primario); }
.nav-mobile button svg { opacity: .85; }
.nav-mobile button.ativo svg { opacity: 1; }
@media (max-width: 899px) {
  .sidebar { display: none; }
  #conteudo { padding-bottom: 76px; }
}
/* Folha "Mais" (celular) — reaproveita o modal padrão (bottom sheet). */
.mais-item { display: flex; align-items: center; gap: 14px; padding: 13px 4px; border-bottom: 1px solid var(--borda); color: var(--texto); font-weight: 600; text-align: left; width: 100%; }
.mais-item:last-of-type { border-bottom: none; }
.mais-item svg { flex-shrink: 0; color: var(--texto-sub); }

/* WhatsApp precisa do espaço todo (é uma ferramenta de trabalho tela cheia, não
   um relatório de leitura — largura de texto confortável não se aplica aqui),
   diferente do resto do app que fica melhor com largura travada pra não esticar
   linha/tabela até a borda. Douglas 2026-08-17: "tem espaço em branco que pode
   aumentar". :has() escapa o max-width só quando a tela é o WhatsApp, sem
   precisar de outra classe/id só pra isso. */
/* Zero padding mesmo (2026-08-17, Douglas riscou no print: "ainda tem margem
   ali") — WhatsApp ocupa o retângulo inteiro, sem nem a folga de 16/20px de
   antes. Cantos arredondados/sombra do #wa_root removidos no JS (ver
   whatsapp.js) porque em tela cheia de verdade eles cortavam esquina contra a
   borda do navegador em vez de "flutuar" como card. */
#conteudo:has(#wa_root) { max-width: none; padding: 0; }

.banner { padding: 10px 16px; text-align: center; font-weight: 600; }
.banner-offline { background: var(--alerta); color: #fff; }
.banner-pending { background: var(--aviso); color: #1a1a1a; }

/* Kanban — nenhuma tela de operação com rolagem vertical de página (spec §1) */
.kanban-toolbar { display: flex; gap: 10px; align-items: center; margin-bottom: 12px; flex-wrap: wrap; }
.kanban-toolbar .btn-grande { width: auto; flex: 0 0 auto; }
.filtros { display: flex; gap: 8px; flex-wrap: wrap; }
.chip { background: var(--bg-elevado); border: 1px solid transparent; border-radius: 999px; padding: 8px 16px; color: var(--texto-sub); white-space: nowrap; font-weight: 600; transition: background var(--transicao), color var(--transicao); }
.chip:hover { color: var(--texto); }
.chip.ativo { background: var(--primario-fraco); color: var(--primario); border-color: rgba(14,165,233,.35); }
.kanban-board { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
@media (max-width: 900px) { .kanban-board { grid-template-columns: 1fr; } }
.coluna { background: var(--bg-card); border: 1px solid var(--borda); border-radius: var(--radius); padding: 10px; min-height: 200px; }
.coluna h2 { font-size: 15px; text-transform: uppercase; letter-spacing: .04em; color: var(--texto-sub2); margin: 4px 6px 10px; }
.cards { display: flex; flex-direction: column; gap: 10px; }

.card-os { background: var(--bg-elevado); border: 1px solid var(--borda); border-radius: 12px; padding: 12px; border-left: 4px solid var(--primario); box-shadow: var(--sombra); }
.card-os.timer-amarelo { border-left-color: var(--aviso); }
.card-os.timer-vermelho { border-left-color: var(--alerta); }
.card-topo { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; }
.card-placa { font-size: 20px; letter-spacing: 1px; }
.card-topo-icones { display: flex; gap: 2px; }
.card-midia, .card-recibo { cursor: pointer; font-size: 20px; padding: 4px 6px; margin: -4px -6px; }

/* Recibo (2026-08-14) — fundo branco de propósito (recibo impresso/foto pra
   cliente não deve sair no tema escuro do app). */
.recibo { background: #fff; color: #111; border-radius: 8px; padding: 18px; font-family: 'Courier New', monospace; }
.recibo h2 { margin: 0 0 2px; font-size: 17px; }
.recibo p { margin: 2px 0; }
.recibo .linha { display: flex; justify-content: space-between; gap: 8px; padding: 2px 0; font-size: 14px; }
.recibo .linha.destaque { font-weight: 700; font-size: 16px; }
.recibo hr { border: none; border-top: 1px dashed #999; margin: 10px 0; }
@media print {
  body * { visibility: hidden; }
  #recibo-imprimir-wrap, #recibo-imprimir-wrap * { visibility: visible; }
  #recibo-imprimir-wrap { position: fixed; inset: 0; background: #fff; }
  #recibo-imprimir-wrap .btn, #recibo-imprimir-wrap .btn-link { display: none !important; }
}
.card-veiculo, .card-servico { color: var(--texto-sub); font-size: 14px; }
.card-total { font-size: 13px; font-weight: 700; color: var(--primario); margin-top: 2px; }
.card-contrato { font-size: 13px; font-weight: 700; color: var(--azul); margin-top: 2px; }
.card-timer { font-weight: 700; margin: 6px 0; }
.card-executores { font-size: 13px; color: var(--texto-sub); margin-bottom: 8px; }
.card-os .btn { margin-top: 6px; }
.card-linha-baixo { display: flex; justify-content: space-between; align-items: center; }
.card-linha-baixo .btn-voltar { color: var(--texto-sub); }

/* Check-in móvel — retrato, uma mão, câmera prioritária */
.checkin-passo { display: flex; flex-direction: column; gap: 14px; max-width: 480px; margin: 0 auto; }
.checkin-header { display: flex; justify-content: space-between; align-items: center; }
/* Altura travada (não aspect-ratio) — em mobile o "100vh" some por trás da barra do
   navegador, e um aspect-ratio 3/4 esticado na largura toda empurrava o botão de
   disparo pra fora da tela visível. Com altura fixa o botão sempre cabe embaixo. */
.checkin-camera-wrap { position: relative; background: #000; border-radius: var(--radius); overflow: hidden; height: 38vh; max-height: 340px; min-height: 220px; }
.checkin-camera-wrap video, .checkin-camera-wrap img { width: 100%; height: 100%; object-fit: cover; }
.checkin-camera-overlay { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; pointer-events: none; }
.checkin-moldura { border: 3px dashed rgba(255,255,255,.7); width: 78%; height: 34%; border-radius: 10px; }
.checkin-shutter { display: flex; justify-content: center; }
.btn-shutter { width: 76px; height: 76px; border-radius: 50%; background: #fff; border: 6px solid var(--bg-elevado); }
.btn-shutter.gravando { background: var(--alerta); }
.btn-shutter.processando { opacity: .4; animation: horus-pulsar 1s ease-in-out infinite; }
@keyframes horus-pulsar { 0%, 100% { transform: scale(1); } 50% { transform: scale(.85); } }
.placa-lida { width: 100%; text-align: center; font-size: 32px; letter-spacing: 3px; background: var(--bg-card); color: var(--texto); padding: 14px; border-radius: var(--radius); border: 2px solid var(--borda); font-weight: 700; text-transform: uppercase; }
.placa-lida:focus { outline: none; border-color: var(--primario); }
.placa-lida::placeholder { color: var(--texto-sub); letter-spacing: 1px; font-size: 20px; }
.dado-cliente { background: var(--bg-card); border-radius: var(--radius); padding: 14px; }
.dado-cliente .linha { display: flex; justify-content: space-between; padding: 4px 0; color: var(--texto-sub); }
.dado-cliente .destaque { color: var(--aviso); font-weight: 700; }
.grid-botoes { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }
.grid-botoes button { min-height: 60px; border-radius: var(--radius); border: 1px solid var(--borda); background: var(--bg-card); color: var(--texto); font-size: 17px; font-weight: 700; transition: border-color var(--transicao), background var(--transicao); }
.grid-botoes button:hover { border-color: var(--borda-forte); }
.grid-botoes button.selecionado { border-color: var(--primario); background: var(--primario-fraco); color: var(--primario); }
/* Passo 4 (fotos do veículo) — tela cheia, parecida com o app de câmera nativo
   do celular (spec Douglas 2026-08-13), não segue o layout padrão .checkin-passo. */
.camera-tela-cheia { position: fixed; inset: 0; z-index: 200; background: #000; }
.camera-tela-cheia video { width: 100%; height: 100%; object-fit: cover; display: block; }
.camera-topo {
  position: absolute; top: 0; left: 0; right: 0; display: flex; justify-content: space-between; align-items: center;
  padding: max(14px, env(safe-area-inset-top)) 14px 28px; background: linear-gradient(rgba(0,0,0,.6), transparent);
}
.camera-topo .btn-link { color: #fff; }
.camera-ok { background: var(--primario); color: #06213a; border: none; border-radius: 999px; padding: 9px 20px; font-weight: 800; font-size: 15px; min-height: 40px; }
.camera-ok:disabled { background: rgba(255,255,255,.22); color: rgba(255,255,255,.6); }
/* 2026-08-18 — Passo 4 (fotos do veículo) ganhou 4 ângulos obrigatórios
   (frente/lateral/traseira/lateral): label grande dizendo qual falta
   (`.camera-guia`) + chips de progresso (`.camera-progresso`) no rodapé,
   acima da galeria de miniaturas. */
.camera-guia { position: absolute; top: 66px; left: 0; right: 0; text-align: center; color: #fff; font-size: 19px; font-weight: 800; text-shadow: 0 1px 6px rgba(0,0,0,.85); pointer-events: none; padding: 0 20px; }
.camera-progresso { display: flex; gap: 6px; justify-content: center; flex-wrap: wrap; padding: 0 2px 8px; }
.camera-progresso .chip-angulo { font-size: 11px; font-weight: 700; padding: 5px 10px; border-radius: 999px; background: rgba(255,255,255,.14); color: rgba(255,255,255,.75); border: 1px solid rgba(255,255,255,.3); }
.camera-progresso .chip-angulo.feito { background: var(--primario); color: #06213a; border-color: var(--primario); }
.camera-progresso .chip-angulo.atual { border-color: #fff; color: #fff; }
.camera-miniaturas .rotulo-angulo { position: absolute; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,.72); color: #fff; font-size: 8px; font-weight: 700; text-align: center; padding: 1px 2px; line-height: 1.3; }
.camera-rodape {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 10px 14px max(16px, env(safe-area-inset-bottom)); background: linear-gradient(transparent, rgba(0,0,0,.65));
}
.camera-miniaturas { display: flex; gap: 8px; overflow-x: auto; padding: 4px 2px 14px; }
.camera-miniaturas .miniatura { position: relative; flex: 0 0 auto; width: 52px; height: 52px; border-radius: 8px; overflow: hidden; border: 2px solid rgba(255,255,255,.55); }
.camera-miniaturas .miniatura img { width: 100%; height: 100%; object-fit: cover; display: block; }
.camera-miniaturas .remover { position: absolute; top: -5px; right: -5px; width: 18px; height: 18px; padding: 0; border: none; border-radius: 50%; background: rgba(0,0,0,.75); color: #fff; font-size: 10px; line-height: 1; }
.camera-controles { position: relative; display: flex; align-items: center; justify-content: center; min-height: 74px; }
.camera-pular { position: absolute; left: 0; color: #fff; }
.camera-shutter { width: 74px; height: 74px; border-radius: 50%; background: #fff; border: 5px solid rgba(255,255,255,.45); }
.camera-shutter.processando { opacity: .4; animation: horus-pulsar 1s ease-in-out infinite; }

/* Visualizador de foto/vídeo do check-in (galeria do kanban) — tela cheia de
   verdade, resolve o modal pequeno (bottom sheet) cortando foto grande embaixo
   da tela (achado real, Douglas 2026-08-13). */
.midia-tela-cheia { position: fixed; inset: 0; z-index: 250; background: #000; display: flex; align-items: center; justify-content: center; }
.midia-tela-cheia img, .midia-tela-cheia video { max-width: 100%; max-height: 100%; object-fit: contain; }
.midia-tela-cheia .fechar-midia {
  position: absolute; top: max(14px, env(safe-area-inset-top)); right: 14px;
  width: 40px; height: 40px; border-radius: 50%; border: none; background: rgba(0,0,0,.6); color: #fff; font-size: 18px; line-height: 1;
}

/* Caixa / formulários */
.form-linha { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
.form-linha label { color: var(--texto-sub); font-size: 14px; }
.form-linha input, .form-linha select, .form-linha textarea {
  min-height: 52px; font-size: 17px; padding: 10px 14px; border-radius: var(--radius-sm); border: 1px solid var(--borda);
  background: var(--bg-elevado); color: var(--texto); transition: border-color var(--transicao);
}
.form-linha input:focus, .form-linha select:focus, .form-linha textarea:focus { outline: none; border-color: var(--azul); }
/* Campo de data com máscara (Horus.aplicarMascaraData) — o input visível fica
   sempre DD/MM/AAAA; um <input type="date"> nativo fica escondido atrás do
   botão 📅 só pra abrir o calendário do aparelho (Douglas 2026-08-18: "não
   funciona direito pra puxar o calendário"). */
.input-com-calendario { padding-right: 40px !important; width: 100%; }
.input-data-oculto { position: absolute; right: 4px; top: 50%; transform: translateY(-50%); width: 32px; height: 32px; opacity: 0; pointer-events: none; }
.btn-calendario { position: absolute; right: 4px; top: 50%; transform: translateY(-50%); width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; background: none; border: none; cursor: pointer; font-size: 17px; padding: 0; line-height: 1; }
/* Período personalizado (De/Até/Aplicar): o input não é filho direto do flex
   row, então não herda o stretch automático — ficava com a largura padrão do
   navegador (~200px) e vazava a tela no mobile (Douglas 2026-08-18). */
#rl-custom { flex-wrap: wrap; }
#rl-custom input { width: 100%; }
.cartao { background: var(--bg-card); border: 1px solid var(--borda); border-radius: var(--radius); padding: 16px; margin-bottom: 12px; box-shadow: var(--sombra); }
/* Layout do Relatório (2026-08-10, reformulado pela 2ª vez): a 1ª tentativa usou
   CSS Grid auto-fill + itens full-span misturados no mesmo grid — isso deixa
   "buracos" de verdade (colunas da linha anterior que sobram vazias quando o
   item seguinte precisa da linha toda, e o algoritmo de auto-placement não
   preenche pra trás). Trocado por linhas EXPLÍCITAS: cada .linha-cartoes é seu
   próprio flex container só com os cards que eu decidi agrupar — nunca sobra
   espaço "buraco", porque não existe auto-placement adivinhando o resto da
   linha. Fora de uma .linha-cartoes, todo .cartao continua 1 por linha (full
   width), que é o padrão seguro. */
.linha-cartoes { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 12px; }
.linha-cartoes > .cartao { flex: 1 1 320px; margin-bottom: 0; min-width: 0; }
/* Tabela de detalhe (Relatório/Clientes, 2026-08-10) — scroll horizontal próprio,
   nunca deixa a página inteira rolar de lado no celular (tela estreita + várias colunas). */
.tabela-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.tabela-simples { width: 100%; border-collapse: collapse; font-size: 13px; }
.tabela-simples th, .tabela-simples td { padding: 6px 10px; border-bottom: 1px solid var(--borda); text-align: left; white-space: nowrap; }
.tabela-simples th { color: var(--texto-sub); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: .03em; }
.tabela-simples tbody tr:hover { background: var(--bg-elevado); }
.tabela-simples tbody tr.linha-clicavel { cursor: pointer; }
.tabela-simples tbody tr.linha-clicavel:hover { background: var(--primario-fraco); }
/* Destaque nome do cliente + cor do veículo na aba Clientes (Douglas 2026-08-10). */
.tabela-simples td.cl-nome { font-weight: 700; font-size: 14px; color: var(--texto); }
.cor-bolinha { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 5px; border: 1px solid var(--borda-forte); vertical-align: middle; }
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px,1fr)); gap: 10px; }
.stat { background: var(--bg-card); border: 1px solid var(--borda); border-radius: var(--radius); padding: 14px; box-shadow: var(--sombra); min-width: 0; }
/* KPI com previsão embutida — trocado 2026-08-17 por um aviso só acima do grid
   (ver relatorio.js), não mais borda por cartão (Douglas: "tudo de cor diferente").
   Regra mantida só por segurança caso algo ainda use a classe. */
.stat.previsto { outline: 2px solid #3b82f6; outline-offset: -2px; }
/* Valor cortando pra fora do card (2026-08-17, ex: "R$ 9.800,0" sem o último
   dígito) — número grande + card estreito sem permissão de quebrar linha.
   clamp() reduz a fonte sozinha quando o card fica estreito (celular/grid com
   muitas colunas), min-width:0 no .stat acima permite o grid encolher o card de
   verdade em vez de estourar a coluna. */
.stat .valor { font-size: clamp(16px, 3.2vw, 26px); font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.15; }
@supports (font-size: 1cqw) {
  .stat { container-type: inline-size; }
  .stat .valor { font-size: clamp(13px, 11cqw, 26px); }
}
.stat .rotulo { color: var(--texto-sub); font-size: 14px; }

/* Relatório — gráficos sem dependência externa (barra em div, não SVG/canvas).
   2026-08-10: achado real — cada coluna usava flex:1 sem largura mínima, então
   com muitos dias (ex: mês inteiro dentro de um card só com metade da tela)
   o rótulo "30/08" ficava espremido num espaço menor que o próprio texto e
   vazava pra fora do card (sem quebrar linha, sem cortar). Fix: min-width por
   coluna (cresce pra preencher quando cabe poucos itens, some no mínimo antes
   de vazar) + .grafico-v-wrap com scroll horizontal próprio quando não cabe —
   mesmo padrão já usado em .tabela-wrap pras tabelas. */
.grafico-v-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* 140px→100px→76px (2026-08-10, Douglas pediu reduzir de novo). */
.grafico-v-cols { display: flex; align-items: flex-end; gap: 3px; height: 76px; }
.grafico-v-cols .barra { flex: 1 1 0; min-width: 34px; background: linear-gradient(180deg, #38bdf8, var(--primario)); border-radius: 4px 4px 0 0; min-height: 2px; transition: opacity var(--transicao); }
.grafico-v-cols .barra:hover { opacity: .8; }
/* Fim de semana/feriado (spec Douglas 2026-08-09; tom suavizado 2026-08-10 —
   Douglas achou o dashboard "cara de IA"/cores demais competindo com o verde
   principal; pesquisa real: manter 1 acento saturado só (verde), sinalização
   secundária em tom dessaturado, não outra cor forte gritando junto). */
.grafico-v-cols .barra.fim-semana { background: linear-gradient(180deg, #a3915c, #8a7a4a); }
.heatmap-rotulo-linha.fim-semana { color: #c9b880; font-weight: 700; }
/* Previsto (projeção, ainda não aconteceu) — borda azul que bate o olho sem precisar
   de legenda pra interpretar (spec Douglas 2026-08-09). Outline em vez de border pra
   não empurrar a largura da barra no flex. Coexiste com .fim-semana. */
.grafico-v-cols .barra.previsto { outline: 2px solid #3b82f6; outline-offset: -2px; }
/* Linha de ícone acima das barras (chuva) — fonte grande de propósito, spec
   Douglas 2026-08-09: "pode aumentar a fonte", sem legenda, bate o olho. */
.grafico-v-icones { display: flex; gap: 3px; margin-bottom: 4px; min-height: 20px; }
.grafico-v-icones span { flex: 1 1 0; min-width: 34px; text-align: center; font-size: 18px; line-height: 1; }
.grafico-v-labels { display: flex; gap: 3px; margin-top: 6px; }
.grafico-v-labels span { flex: 1 1 0; min-width: 34px; font-size: 10px; color: var(--texto-sub2); text-align: center; white-space: nowrap; }
/* Rosca/donut (2026-08-10, sugestão do Douglas pra Por porte/Por forma de
   pagamento) — CSS puro via conic-gradient, sem canvas/SVG/lib externa. */
.rosca-wrap { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
.rosca { width: 130px; height: 130px; border-radius: 50%; position: relative; flex-shrink: 0; }
.rosca-centro { position: absolute; inset: 18px; background: var(--bg-card); border-radius: 50%; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; }
.rosca-centro .valor { font-size: 15px; font-weight: 800; }
.rosca-centro .rotulo { font-size: 10px; color: var(--texto-sub); }
.rosca-legenda { flex: 1; min-width: 140px; display: flex; flex-direction: column; gap: 8px; }
.rosca-item { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.rosca-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.rosca-item .rosca-nome { flex: 1; min-width: 0; }
.rosca-item .rosca-pct { color: var(--texto-sub); font-size: 12px; }
.rosca-item .rosca-valor { font-weight: 700; }
.linha-h { display: flex; align-items: center; gap: 10px; padding: 7px 0; }
.linha-h .rotulo-h { width: 120px; font-size: 13px; color: var(--texto-sub); flex-shrink: 0; }
.linha-h .barra-h-wrap { flex: 1; background: var(--bg-elevado); border-radius: 6px; overflow: hidden; height: 20px; }
.linha-h .barra-h { background: linear-gradient(90deg, var(--primario-escuro), var(--primario)); height: 100%; border-radius: 6px; transition: width 300ms ease; }
.linha-h .valor-h { width: 76px; text-align: right; font-size: 13px; font-weight: 700; flex-shrink: 0; }

/* Heatmap calendário (dia×hora, dia do mês, mês do ano) — spec Douglas 2026-08-09:
   grade linha=balde de tempo, coluna=hora + coluna Total. 5 faixas de cor por
   quantil (não degradê contínuo — ver renderHeatmap no JS pro motivo). Sem lib
   externa, mesmo espírito dos outros gráficos — CSS Grid + cor calculada em JS.
   Raio de borda pequeno e sem "bounce" no hover de propósito (Douglas: "parece
   botão, não é fluido" — célula de heatmap deve parecer ladrilho, não botão). */
.heatmap-wrap { overflow-x: auto; }
/* Sem gap entre células (rodada 11, spec Douglas: "faz tudo junto pra ficar mais
   suave a mudança de cor, sem as bordas em cada quadradinho") — cores encostadas
   viram um gradiente contínuo em vez de blocos separados. */
.heatmap-grid { display: grid; gap: 0; font-size: 13px; }
/* Fonte maior nos rótulos de linha (dia + dia da semana) — spec Douglas
   2026-08-09, rodada 12: "aumenta as fontes, principalmente dos dias e dia da
   semana". 8h-18h em vez de 6h-21h libera espaço horizontal pra isso caber. */
.heatmap-rotulo-linha { display: flex; flex-direction: column; align-items: flex-start; justify-content: center; color: var(--texto-sub2); font-size: 13px; padding-right: 4px; line-height: 1.25; }
.heatmap-rotulo-linha .num { font-weight: 700; font-size: 14px; }
.heatmap-rotulo-linha .dow { font-size: 10px; opacity: .8; }
.heatmap-rotulo-coluna { text-align: center; color: var(--texto-sub2); font-size: 12px; padding-bottom: 2px; }
/* Sem border-radius (spec Douglas rodada 11) — quadrados encostados formam um
   bloco de cor liso/contínuo. min-height um pouco maior (36→40px) pra caber o
   ícone de chuva no canto sem espremer o valor/quantidade. */
/* Altura reduzida (2026-08-10, Douglas: "Dia do mês" tem até 31 linhas — ainda
   comprido demais mesmo depois de 46px→30px, reduzido de novo pra 22px). */
.heatmap-celula { position: relative; border-radius: 0; padding: 1px; min-height: 26px; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; cursor: default; transition: filter var(--transicao); color: #0b1220; }
.heatmap-celula:hover { filter: brightness(1.12); z-index: 1; }
.heatmap-celula .hm-valor { font-size: 11px; font-weight: 700; line-height: 1.1; }
.heatmap-celula .hm-qtd { font-size: 9px; opacity: .8; line-height: 1.1; }
.heatmap-celula .hm-pct { font-size: 8px; opacity: .7; line-height: 1.1; }
.heatmap-celula .hm-chuva { position: absolute; top: 1px; right: 1px; font-size: 10px; line-height: 1; }
.heatmap-celula.vazia { background: var(--bg-elevado); opacity: .35; }
.heatmap-celula.total { border-radius: 0; box-shadow: inset 0 0 0 1px rgba(11,18,32,.35); }
/* Total costuma ter número maior (soma de 24h, formato "R$1,9k") — fonte um
   pouco menor que as células normais pra não estourar a coluna mais estreita. */
.heatmap-celula.total .hm-valor { font-size: 9px; }
.heatmap-celula.total .hm-qtd { font-size: 8px; }
/* Célula com contribuição de previsão (dia futuro dentro do período) — mesma borda
   azul do gráfico "Movimento por dia", sem legenda (spec Douglas 2026-08-09). */
.heatmap-celula.previsto { outline: 2px solid #3b82f6; outline-offset: -2px; }
.heatmap-legenda { display: flex; align-items: center; gap: 6px; margin-top: 10px; font-size: 11px; color: var(--texto-sub2); }

/* Escala de funcionários */
.escala-dia { display: flex; flex-direction: column; padding: 10px 0; border-bottom: 1px solid var(--borda); }
.escala-dia:last-child { border-bottom: none; }
.escala-nome { font-weight: 600; }
.escala-toggle { width: 46px; height: 26px; border-radius: 999px; background: var(--bg-elevado); position: relative; transition: background var(--transicao); flex-shrink: 0; cursor: pointer; }
.escala-toggle::after { content: ''; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: 50%; background: var(--texto-sub); transition: transform var(--transicao), background var(--transicao); }
.escala-toggle.ativo { background: var(--primario-fraco); }
.escala-toggle.ativo::after { transform: translateX(20px); background: var(--primario); }

/* Horários do dia (entrada/saída) — spec Douglas 2026-08-09, rodada 2. */
.escala-horarios { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 8px; align-items: center; }
.escala-horarios label { display: flex; flex-direction: column; gap: 2px; font-size: 11px; color: var(--texto-sub); }
.escala-horarios input[type="time"] { background: var(--bg-elevado); border: 1px solid var(--borda); border-radius: 6px; color: var(--texto); padding: 4px 6px; font-size: 13px; }

/* Padrão semanal — grade funcionário × dia (D S T Q Q S S). */
.escala-padrao-linha { padding: 8px 0; border-bottom: 1px solid var(--borda); }
.escala-padrao-linha:last-child { border-bottom: none; }
.escala-padrao-dias { display: flex; gap: 4px; margin-top: 6px; }
.escala-padrao-dia { flex: 1; background: var(--bg-elevado); border: 1px solid var(--borda); border-radius: 6px; color: var(--texto-sub); padding: 6px 2px; text-align: center; }
.escala-padrao-dia .dow { display: block; font-size: 10px; font-weight: 700; }
.escala-padrao-dia .hr { display: block; font-size: 9px; margin-top: 2px; }
.escala-padrao-dia.ativo { background: var(--primario-fraco); border-color: var(--primario); color: var(--texto); }
/* Formulário de edição em lote do padrão semanal (2026-08-11) — troca do
   prompt()-por-dia por um form de verdade com checkbox por dia da semana. */
.escala-padrao-dias-check { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 10px; }
.escala-check-dia { display: flex; align-items: center; gap: 5px; font-size: 13px; color: var(--texto-sub); }
.escala-check-dia input { width: 18px; height: 18px; }

/* Modal simples */
.modal-fundo { position: fixed; inset: 0; background: rgba(0,0,0,.6); display: flex; align-items: flex-end; justify-content: center; z-index: 50; }
/* Bottom sheet (nasce embaixo) é padrão mobile — no desktop sobra espaço vazio
   em cima e fica "estranho" (Douglas 2026-08-17, print do modal de ficha do
   cliente). ≥900px centraliza de verdade, cantos redondos nos 4 lados. */
@media (min-width: 900px) {
  .modal-fundo { align-items: center; }
  .modal-caixa { border-radius: var(--radius-lg) !important; }
}
/* min-width:0 é o fix de verdade (2026-08-10) — .modal-caixa é filho flex de
   .modal-fundo, e por padrão um item flex nunca encolhe abaixo do tamanho
   mínimo do próprio conteúdo (min-width:auto implícito), mesmo com max-width
   definido. O modal de perfil tem stat-grid de 4 colunas (min 140px cada) —
   sem isso, o conteúdo "empurrava" a caixa toda pra ~600px+, ignorando os
   480px do max-width. Com min-width:0, o conteúdo interno (stat-grid, tabelas)
   passa a ser responsável por se ajustar/rolar dentro dos 480px, que é o que já
   acontecia com sucesso pro payment/galeria antes disso existir. */
.modal-caixa { background: var(--bg-card); border-radius: 20px 20px 0 0; padding: 20px; padding-bottom: 28px; width: 100%; min-width: 0; max-width: 480px; max-height: 90vh; overflow-y: auto; box-shadow: 0 -8px 32px rgba(0,0,0,.4); }
/* Modal do perfil de carro/cliente (2026-08-10) é bem mais denso que o de
   pagamento/galeria (stat-grid de 6, 2 tabelas) — Douglas achou "fino e
   comprido" nos 480px padrão, pediu mais largura. Classe extra só nele, não
   mexe nos outros modais que já funcionavam bem estreitos. */
.modal-larga { max-width: 760px; }
