/* 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 pro guia visual oficial da marca (2026-08-24), depois
   ajustada no mesmo dia: laranja (guia original) trocado por dourado —
   Douglas achou o laranja "sem combinar, feio" vendo ao vivo. Dourado casa
   com o cromado/prata da logo e fica longe do âmbar de --aviso (não confunde
   ação com alerta). --primario segue como acento de ação (botão, aba ativa,
   destaque, barra de progresso), Azul Médio (--azul) pra info/link/foco —
   mesma regra de "1 acento saturado só" que valia pro azul-céu antigo
   continua valendo (pesquisa original: VPS/CHANGELOG.md 2026-08-16). */
:root {
  --bg: #f4f5f7; --bg-card: #ffffff; --bg-elevado: #eef0f3; --bg-elevado-2: #e3e6ea;
  --texto: #1A1A1A; --texto-sub: #4A4A4A; --texto-sub2: #838d9c;
  --primario: #F0A800; --primario-escuro: #B87F00; --primario-fraco: rgba(240,168,0,.12);
  --alerta: #D93636; --alerta-escuro: #B02525; --aviso: #b45309; --azul: #2E7AB5;
  --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;
  --font-heading: 'Poppins', sans-serif;
  --font-body: 'Inter', sans-serif;
  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: var(--font-body), -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 { font-family: var(--font-heading), sans-serif; 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: #1A1A1A; box-shadow: 0 2px 10px rgba(240,168,0,.28); }
.btn-primario:hover { background: #FFD066; }
.btn-primario:active { background: var(--primario-escuro); }
/* #2a0a0a sobre #D93636 dava 3,95:1 e reprova nos 4,5:1 de texto — e este é o botão de
   "Fechar caixa" e "Cancelar OS", onde ler errado custa caro. Branco dá 4,63:1. */
.btn-perigo { background: var(--alerta); color: #fff; }
/* Escurece em vez de clarear: #ff8a8a com texto branco dava 2,27:1 — o rótulo quase
   sumia no instante em que a pessoa aponta pra ação destrutiva. #B02525 dá 6,69:1.
   Achado do ux-front em 2026-09-08. */
.btn-perigo:hover { background: var(--alerta-escuro); }
.btn-link { background: transparent; border: none; padding: 6px 2px; color: #256598; text-decoration: none; min-height: 44px;  /* nao --azul #2E7AB5: medido, ele da 4,21:1 no fundo da pagina e 4,28:1 na barra de descarte -- reprova o AA em toda superficie que nao seja branco puro. #256598 da 5,42 a 6,19:1 nos quatro fundos do sistema. O token nao mudou porque --azul tambem e FUNDO de badge, e escurece-lo pioraria o texto escuro que fica em cima. ux-front 2026-09-08. */ 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; }
.marca-icone { height: 32px; width: auto; 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: 0;
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.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; }
  /* 76px = altura da .nav-mobile fixa. O env() e o que faltava: num iPhone com
     viewport-fit=cover a nav cresce 34px de safe area e o ultimo item de qualquer
     lista ficava embaixo dela (achado do ux-front, 2026-09-06 -- Chromium emula
     safe area como 0, entao isso nunca aparece em teste sem CDP). */
  #conteudo {
    padding-bottom: 76px;                                          /* (a) sem env(): o parser descarta a linha de baixo */
    padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px)); /* (b) o 0px evita virar initial(0) e atropelar a de cima */
  }
}
/* 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; }

/* ---- WhatsApp: layout das duas colunas -------------------------------------
   Mora aqui, e não no style inline do whatsapp.js, porque media query não existe
   em atributo style — era exatamente por isso que o módulo nunca teve celular.
   Só as propriedades de LAYOUT saíram do inline; cor e tipografia continuam lá.
   Achado do QA em 2026-09-08: a 360px a conversa aparecia com 80px de 380 (21%),
   e a data que o Douglas pediu ("nem sei de quando foi a mensagem") não cabia na
   tela em largura nenhuma de celular. */
#wa_root { display: flex; height: 100%; overflow: hidden; }
.wa-col-lista { width: 320px; min-width: 280px; position: relative; overflow: hidden; border-right: 1px solid #d1d7db; }
/* min-width:0 mata o mínimo automático de item flex, que é o min-content do
   conteúdo. Sem ele a coluna da conversa se recusa a encolher abaixo de ~380px e
   empurra a si mesma pra fora da tela — o "min-width:380px" que o QA mediu não
   está escrito em lugar nenhum, é esse mínimo automático. */
#wa_thread { flex: 1; min-width: 0; display: flex; flex-direction: column; position: relative; }
.wa-bolha { max-width: 65%; }
.wa-voltar { display: none; }

@media (max-width: 899px) {
  /* Uma coluna de cada vez (lista → toca → conversa → voltar → lista), padrão do
     WhatsApp no celular. 899px é a MESMA linha em que o app troca sidebar por
     barra inferior (bloco de cima): dois breakpoints diferentes recriariam o bug
     de hoje, em que o app está em modo celular e o módulo em modo desktop. */
  .wa-col-lista { width: 100%; min-width: 0; border-right: none; }
  #wa_thread { display: none; }
  #wa_root.wa-vendo-conversa .wa-col-lista { display: none; }
  #wa_root.wa-vendo-conversa #wa_thread { display: flex; }

  /* Com a LISTA na tela a barra inferior continua ali, então devolve o espaço que
     o `:has(#wa_root){padding:0}` acima zerou — ele tem especificidade maior que
     o #conteudo do bloco de 899px, e por isso a última conversa (e, no layout
     antigo, a própria caixa de digitação) ficava atrás da nav. */
  #conteudo:has(#wa_root) {
    padding-bottom: 76px;                                          /* (a) sem env(): o parser descarta a linha de baixo */
    padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px)); /* (b) o 0px evita virar initial(0) e atropelar a de cima */
  }
  /* Com a CONVERSA aberta a barra inferior sai: o caminho de volta é o ← do
     cabeçalho, e 76px é ~10% da altura útil de um 360x740. */
  #conteudo:has(#wa_root.wa-vendo-conversa) { padding-bottom: 0; }
  #app:has(#wa_root.wa-vendo-conversa) .nav-mobile { display: none; }

  /* Bolha a 85% e folga lateral de 8px: a 360px o padding de 8% comia 58px e
     deixava a bolha com 196px. */
  .wa-bolha { max-width: 85%; }
  #wa_msgs { padding: 12px 8px !important; }

  .wa-voltar {
    display: flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; min-width: 44px; margin-left: -8px;  /* -8px alinha o ícone à borda sem encolher o alvo */
    border: none; background: transparent; color: #54656f; border-radius: 50%; cursor: pointer;
  }
  .wa-voltar:active { background: rgba(0, 0, 0, .06); }

  /* Alvos de toque. `!important` porque os tamanhos vêm de style inline no JS, e
     aumentá-los lá quebraria a densidade do desktop, que é mouse. */
  #wa_root .wa-toque   { width: 44px !important; height: 44px !important; min-width: 44px !important;
                         display: flex !important; align-items: center; justify-content: center; }
  #wa_root .wa-toque-g { width: 48px !important; height: 48px !important; min-width: 48px !important; }
  #wa_root .wa-chip-filtro { min-height: 44px; padding: 10px 16px !important; }
  #wa_root .wa-linha-toque { min-height: 48px; }  /* cabeçalho de grupo é um toggle, e tinha 31px */
  /* Tem que continuar DEPOIS de .wa-toque: mesma especificidade e os dois com
     !important, então quem ganha é a ordem no arquivo. Reordenou, o emoji volta. */
  #wa_root .wa-btn-emoji { display: none !important; }  /* teclado do celular já tem emoji, e libera 52px pro campo */

  /* iOS Safari dá zoom automático em input com fonte < 16px e o layout inteiro sai
     do lugar. Vale pro modal de nova conversa também, que é irmão do #wa_root. */
  #wa_root input, #wa_modal_nc input, #wa_modal_nc select { font-size: 16px !important; }
}

.banner { padding: 10px 16px; text-align: center; font-weight: 600; }
.banner-offline { background: var(--alerta); color: #fff; }
/* #1a1a1a sobre #b45309 dava 3,38:1 — e este banner é o aviso de que desconto/adicional
   mudou depois da forma escolhida, dentro do modal de cobrança. Branco dá 5,08:1. */
.banner-pending { background: var(--aviso); color: #fff; }

/* 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(240,168,0,.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); }
/* Era `--primario-fraco` com texto `--primario`: composto sobre branco dá 1,88:1 e o
   botão escolhido praticamente não mudava de aparência. É o botão de FORMA DE PAGAMENTO
   do modal de cobrança — a pessoa não tinha certeza se tinha escolhido, e a caixinha (que
   só libera depois da forma) parecia quebrada. Fundo cheio com #1A1A1A dá 8,43:1.
   O ✓ entra porque cor sozinha não pode carregar o estado (WCAG 1.4.1). */
.grid-botoes button.selecionado { border-color: var(--primario-escuro); background: var(--primario); color: #1A1A1A; }
.grid-botoes button.selecionado::before { content: "✓ "; font-weight: 800; }
/* 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, 0px)) 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, 0px)); 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, 0px)); 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;
}

/* Galeria deslizante com zoom (2026-08-18) — arraste/swipe troca de foto,
   roda do mouse/pinça/duplo clique dá zoom. Ver Horus.abrirGaleriaFotos. */
.galeria-lightbox { position: fixed; inset: 0; z-index: 300; background: #000; display: flex; flex-direction: column; touch-action: none; }
.galeria-topo {
  display: flex; justify-content: space-between; align-items: center; color: #fff;
  padding: max(14px, env(safe-area-inset-top, 0px)) 16px 10px; flex-shrink: 0;
}
.galeria-topo .btn-link { color: #fff; }
.galeria-trilho-wrap { flex: 1; overflow: hidden; position: relative; min-height: 0; cursor: grab; }
.galeria-trilho { display: flex; height: 100%; width: 100%; }
.galeria-item { flex: 0 0 100%; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; overflow: hidden; }
.galeria-item img { max-width: 100%; max-height: 100%; object-fit: contain; touch-action: none; user-select: none; will-change: transform; }
.galeria-miniaturas { display: flex; gap: 6px; padding: 10px 12px max(10px, env(safe-area-inset-bottom, 0px)); overflow-x: auto; flex-shrink: 0; }
.galeria-mini { flex: 0 0 auto; width: 44px; height: 44px; border-radius: 6px; overflow: hidden; border: 2px solid transparent; opacity: .55; cursor: pointer; }
.galeria-mini img { width: 100%; height: 100%; object-fit: cover; }
.galeria-mini.ativa { border-color: #fff; opacity: 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; }
/* Rótulo de seção do Relatório (2026-08-22, reorganização pra dar narrativa/
   hierarquia à tela — antes era uma lista plana de ~15 cartões do mesmo peso
   visual, sem indicar o que agrupa o quê). Reaproveita o mesmo estilo já usado
   em `.coluna h2` (título de coluna do kanban) por consistência, em vez de
   inventar um 2º padrão de "título de seção" no mesmo app. */
.rl-secao { font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--texto-sub2); margin: 22px 2px 10px; }

/* Relatório — reforma em hero+abas (2026-08-22, 2ª rodada: a 1ª reorganização
   em seções foi rejeitada — "refeito do zero, não aproveite nada" — Douglas
   pediu faturamento em destaque + abas + taxas fora do fluxo principal.
   Prototipado antes num Artifact separado pra validar visual sem precisar
   deployar, só depois implementado de verdade aqui. */
.rl-aviso-previsao { color: var(--azul); font-size: 13px; font-weight: 600; margin: 0 0 8px; }
/* Ponta clara do gradiente escurecida de #2E7AB5 (var(--azul)) pra #1F6AA8
   (2026-09-03, medição do ux-front): os rótulos pequenos do hero usavam
   opacity .7/.75, o que dava ~2.6:1 de contraste sobre o azul original —
   reprovava WCAG AA (4.5:1) desde antes desta mudança. Agora rótulo é branco a
   88% SEM opacity, sobre o azul mais escuro: 4.87:1. Hierarquia passa a vir de
   tamanho/peso, não de opacidade. Só o gradiente daqui muda — var(--azul)
   continua o mesmo pro resto do app. */
.rl-hero { background: linear-gradient(135deg, #1F6AA8, #0A4D8C); border-radius: var(--radius-lg); padding: 20px 24px; color: #fff; display: flex; flex-direction: column; gap: 16px; }
.rl-hero-topo { display: flex; align-items: flex-start; gap: 24px; }
.rl-hero-divisor { width: 1px; align-self: stretch; background: rgba(255,255,255,.22); flex-shrink: 0; }
.rl-hero-principal { min-width: 0; }
.rl-hero-principal .rotulo { font-size: 12px; text-transform: uppercase; letter-spacing: .05em; color: rgba(255,255,255,.88); margin-bottom: 4px; font-weight: 700; }
/* tabular-nums: sem isso o número muda de largura ao passar de 8 pra 11 e a
   barra logo abaixo "dança" a cada atualização. */
.rl-hero-principal .valor { font-size: clamp(28px, 5vw, 40px); font-weight: 800; letter-spacing: -.02em; line-height: 1.1; font-variant-numeric: tabular-nums; }
/* Largura FIXA do trilho (2026-09-04, achado do ux-front medindo os 4 estados):
   o bloco de carros e shrink-to-fit dentro do flex, entao a barra herdava a
   largura do TEXTO da legenda -- "Todos prontos" dava trilho de ~143px e
   "856 prontos - 428 ainda na fila" dava ~217px. Barra de proporcao com regua
   elastica engana: o dono troca de periodo, a barra encolhe porque o texto
   encolheu, e ele le queda que nao existiu. min-width no bloco garante que os
   4 estados mecam o mesmo; min() evita estourar em tela ultra-estreita. */
.rl-hero-carros { min-width: min(260px, 100%); }
.rl-hero-barra { height: 8px; border-radius: 4px; background: rgba(255,255,255,.28); width: 100%; max-width: 260px; margin-top: 10px; overflow: hidden; }
.rl-hero-barra-cheia { height: 100%; background: #fff; border-radius: 4px; }
.rl-hero-composicao { font-size: 13px; font-weight: 600; color: #fff; margin-top: 6px; }
.rl-hero-ponto { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 5px; vertical-align: baseline; }
.rl-hero-ponto.cheio { background: #fff; }
.rl-hero-ponto.vazio { border: 1.5px solid rgba(255,255,255,.8); }
.rl-hero-sub { display: flex; gap: 22px; flex-wrap: wrap; align-items: flex-start; border-top: 1px solid rgba(255,255,255,.22); padding-top: 14px; }
.rl-hero-sub .item .valor { font-size: 19px; font-weight: 700; font-variant-numeric: tabular-nums; }
.rl-hero-sub .item .rotulo { font-size: 12px; color: rgba(255,255,255,.88); margin-top: 2px; }
.rl-selo-agora { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: #5A6472; background: #EEF1F5; padding: 2px 6px; border-radius: 4px; margin-left: 4px; }
/* Mobile: protagonistas empilham (lado a lado a 360px a legenda de composição
   não cabe) e o sub vira grid de 3 colunas — com flex-wrap os 3 itens quebravam
   desalinhados. */
@media (max-width: 599px) {
  /* Padding lateral de 24px -> 16px: a 360px isso devolve 16px pro conteúdo, o
     que é a diferença entre a coluna do sub caber ou não (medição do ux-front:
     "R$ 1.234,56" a 19px estoura uma coluna de 97px). */
  .rl-hero { padding: 18px 16px; }
  .rl-hero-topo { flex-direction: column; gap: 14px; }
  /* align-self: stretch (nao auto): o container tem align-items:flex-start, entao
     no modo coluna o divisor com width:auto e sem conteudo colapsava pra 0 e a
     divisoria sumia no mobile. align-self:stretch sozinho NAO resolve: a regra
     base fixa width:1px, e stretch so age quando o tamanho e auto -- por isso
     width:100% explicito. Achado medindo o render (1x1px), nao olhando. */
  .rl-hero-divisor { width: 100%; height: 1px; align-self: stretch; }
  /* align-items: start — "caixinha da equipe" é o único rótulo que quebra em 2
     linhas nessa largura; sem isso a quebra desalinha a base dos 3 itens.
     Valor com clamp porque caixinha acumulada do mês passa de mil real fácil e
     "R$ 1.234,56" a 19px fixo transborda a coluna. Testar SEMPRE com esse valor
     no extremo, não com o R$ 0,00 de um dia devagar. */
  .rl-hero-sub { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; align-items: start; }
  .rl-hero-sub .item .valor { font-size: clamp(15px, 4.2vw, 19px); }
}
/* Peso 600 e mesmo tamanho do rotulo: e um segundo VALOR, nao um rotulo --
   sem isso as duas linhas da caixinha ficam indistinguiveis (achado ux-front). */
.rl-hero-detalhe { font-size: 12px; color: rgba(255,255,255,.88); font-weight: 600; margin-top: 2px; }
/* BUG MEU, achado do QA (2026-09-04): criei essa classe nesta mesma rodada com
   var(--texto-sub) (#4A4A4A, cinza escuro) DENTRO do hero azul -- 1,04:1 de
   contraste na base do gradiente, praticamente invisivel. A correcao de
   contraste desta rodada pegou os 3 rotulos do hero e deixou este de fora, no
   mesmo componente. Mesmo branco a 88% dos outros. */
.rl-hero-indisponivel { font-size: 13px; font-weight: 600; color: rgba(255,255,255,.88); }
/* Erro no lugar de conteudo: precisa PARECER erro (achado do QA -- antes era um
   <p> cinza sem cor nem icone, lia como legenda). */
.rl-erro { border-left: 3px solid var(--alerta); background: #FFF4F4; border-radius: 10px; padding: 16px; }
.rl-erro-titulo { margin: 0; font-weight: 700; color: var(--texto); }
.rl-erro-apoio { margin: 4px 0 0; font-size: 12px; color: var(--texto-sub); }
.rl-erro-btn { margin-top: 12px; min-height: 44px; min-width: 120px; }
/* Apoio do stat: 11px/#6B6B6B = 5,4:1 sobre branco (medido). Diferencia do
   rotulo por tamanho E cor, nao so por tamanho. */
.rl-stat-apoio { font-size: 11px; font-weight: 400; color: #6B6B6B; margin-top: 2px; }

/* Abas do Relatório — nível 2 dentro da tela (a navegação de nível 1, entre
   Fila/Check-in/Caixa/Relatório etc., já é a sidebar/barra inferior do app;
   isso aqui só organiza o QUE tem dentro do Relatório). */
.rl-abas { display: flex; gap: 4px; border-bottom: 1px solid var(--borda); margin-bottom: 16px; overflow-x: auto; }
.rl-aba { background: none; border: none; padding: 12px 4px; margin-right: 22px; font-size: 15px; font-weight: 700; color: var(--texto-sub); cursor: pointer; white-space: nowrap; border-bottom: 2px solid transparent; }
.rl-aba.ativa { color: var(--texto); border-bottom-color: var(--primario); }
.rl-painel-aba { display: none; }
.rl-painel-aba.ativa { display: block; }

/* Card recolhido (Atendimentos do período — é ferramenta de busca, não algo
   pra rolar por cima toda vez, spec Douglas 2026-08-22). */
details.cartao summary { cursor: pointer; font-weight: 700; font-size: 15px; list-style: none; display: flex; align-items: center; justify-content: space-between; }
details.cartao summary::-webkit-details-marker { display: none; }
details.cartao summary::marker { display: none; content: ""; }
.rl-seta { transition: transform 150ms ease; color: var(--texto-sub2); font-size: 13px; }
details.cartao[open] .rl-seta { transform: rotate(90deg); }
.rl-contexto { font-weight: 400; color: var(--texto-sub); font-size: 13px; margin-left: 8px; }
.rl-conteudo-detalhe { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--borda); }

/* Bloco "Pendente" dentro de "Por forma de pagamento" (Douglas 2026-08-29) — âmbar
   de aviso, não vermelho de erro: carro pendente é estado normal do dia a dia (pode
   só estar sendo lavado agora), não é falha. */
.rl-pendente-bloco { border-left: 3px solid var(--aviso); background: #FFFBEB; border-radius: 6px; padding: 10px 12px; margin-bottom: 12px; font-size: 14px; color: #92400E; }
.rl-pendente-bloco summary { min-height: 44px; display: flex; align-items: center; justify-content: space-between; gap: 8px; cursor: pointer; font-weight: 700; list-style: none; }
.rl-pendente-bloco summary::-webkit-details-marker { display: none; }
.rl-pendente-bloco summary::marker { display: none; content: ""; }
.rl-pendente-bloco[open] .rl-seta { transform: rotate(90deg); }
.rl-pendente-bloco .rl-contexto { color: #92400E; opacity: .75; }
.rl-pendente-bloco .rl-conteudo-detalhe { border-top-color: rgba(146, 64, 14, .25); }
.rl-pendente-vazio { border-left: 3px solid var(--borda); background: transparent; color: var(--texto-sub); border-radius: 6px; padding: 10px 12px; margin-bottom: 12px; font-size: 14px; }

/* Rosca — só pro resumo "Pix, dinheiro ou cartão" (ver roscaSimples em
   relatorio.js). Os outros gráficos categóricos (Por porte, Por forma de
   pagamento) usam barra horizontal — ver .linha-h abaixo. */
.rosca-linha { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
.rosca { width: 120px; height: 120px; border-radius: 50%; position: relative; flex-shrink: 0; }
.rosca-centro { position: absolute; inset: 16px; 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: 14px; font-weight: 800; }
.rosca-centro .rotulo { font-size: 10px; color: var(--texto-sub); }
.rosca-legenda { flex: 1; min-width: 150px; 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 .nome { flex: 1; min-width: 0; }
.rosca-item .pct { color: var(--texto-sub); font-size: 12px; }
.rosca-item .valor-r { font-weight: 700; }
/* 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, #FFD066, 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; }
.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) — 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/.escala-horarios (grade de 1 dia por vez,
   toggle presente/falta) removidas em 2026-08-29: a tela de Escala virou a
   grade semanal em escala.js, que não usa mais esse layout. .escala-toggle
   continua (reaproveitado por equipe.js como toggle genérico ativo/inativo).
   .escala-nome e .escala-padrao-* continuam (reaproveitados por escala.js no
   accordion "Horário padrão da semana", mesmo HTML/CSS de antes). */
.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); }

/* 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 */
/* z-index 400 e nao 50: a camera de leitura de placa e position:fixed com z-index 200,
   e o modal ficava ATRAS dela — a saida do estacionamento parou de funcionar quando o
   prompt() nativo (que desenha acima de qualquer conteudo da pagina) virou modal HTML.
   Achado do QA em 2026-09-08. */
.modal-fundo { position: fixed; inset: 0; background: rgba(0,0,0,.6); display: flex; align-items: flex-end; justify-content: center; z-index: 400; }
/* 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. */
/* O padding de baixo era 28px fixo: em iPhone com barra de gestos o último botão do modal
   fica atrás dela. O resto do CSS já trata safe area em 5 lugares, este ficou de fora. */
.modal-caixa { background: var(--bg-card); border-radius: 20px 20px 0 0; padding: 20px; padding-bottom: 28px; padding-bottom: max(28px, calc(env(safe-area-inset-bottom, 0px) + 12px)); 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; }

/* ---------- Equipe & Usuários (redesenho 2026-08-29) ----------
   Segmentado "Equipe"/"Usuários" no topo, cards com foto/iniciais + badges,
   formulário de funcionário em painel lateral (≥900px: 480px dockado na
   direita, igual .modal-caixa em largura) que vira tela cheia sozinho no
   celular (mesmo elemento, width:100% com max-width:480px só entra em jogo
   quando a viewport é mais larga que isso — sem media query extra pra isso).
   Formulário de usuário reaproveita a mesma linguagem visual do .modal-caixa
   só que com z-index acima do drawer, porque abre por cima dele. */
.eq-segmentado { display: inline-flex; background: var(--bg-elevado); border-radius: 999px; padding: 4px; gap: 2px; margin-bottom: 14px; }
.eq-segmento { padding: 9px 20px; min-height: 40px; border-radius: 999px; font-weight: 700; font-size: 14px; color: var(--texto-sub); transition: background var(--transicao), color var(--transicao); }
.eq-segmento:hover { color: var(--texto); }
.eq-segmento.ativo { background: var(--bg-card); color: var(--texto); box-shadow: var(--sombra); }

.eq-toolbar { display: flex; gap: 10px; align-items: center; margin-bottom: 14px; flex-wrap: wrap; }
.eq-toolbar input { flex: 1; min-width: 180px; min-height: 48px; padding: 10px 14px; border-radius: var(--radius-sm); border: 1px solid var(--borda); background: var(--bg-elevado); color: var(--texto); font-size: 15px; }
.eq-toolbar input:focus { outline: none; border-color: var(--azul); }
.eq-toolbar .btn { flex: 0 0 auto; }
.eq-ajuda { color: var(--texto-sub); font-size: 13px; margin: 0 0 14px; }

.eq-lista { display: flex; flex-direction: column; gap: 10px; }
.eq-card { display: flex; align-items: center; gap: 12px; padding: 12px; border: 1px solid var(--borda); border-radius: var(--radius); background: var(--bg-card); cursor: pointer; min-height: 44px; transition: border-color var(--transicao), background var(--transicao); }
.eq-card:hover { border-color: var(--borda-forte); background: var(--bg-elevado); }
.eq-card:focus-visible { outline: 2px solid var(--azul); outline-offset: 2px; }
.eq-card-usuario { justify-content: space-between; }
.eq-card-info { flex: 1; min-width: 0; }
.eq-card-nome { font-weight: 700; font-size: 15px; }
.eq-inativo-tag { color: var(--texto-sub); font-weight: 400; font-size: 13px; }
.eq-card-sub { color: var(--texto-sub); font-size: 13px; margin-top: 2px; }
.eq-card-badges { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 6px; }

/* Avatar circular — foto (background-image via blob, ver equipe.js) ou
   iniciais como fallback sempre presente por baixo (nunca depende só da
   foto carregar). */
.eq-avatar { width: 44px; height: 44px; border-radius: 50%; flex-shrink: 0; background-color: var(--bg-elevado-2); background-size: cover; background-position: center; display: flex; align-items: center; justify-content: center; border: 1px solid var(--borda); }
.eq-avatar-iniciais { font-weight: 700; font-size: 15px; color: var(--texto-sub); transition: opacity var(--transicao); }
.eq-avatar.eq-avatar-com-foto .eq-avatar-iniciais { opacity: 0; }
.eq-avatar-grande { width: 88px; height: 88px; }
.eq-avatar-grande .eq-avatar-iniciais { font-size: 26px; }

/* Badges — contraste 4.5:1+ conferido em cada combinação:
   perfil-gestao (branco/#0A4D8C) >8:1; perfil-op (--texto-sub/--bg-elevado-2)
   ~7.8:1; acesso (branco/--azul) ~4.6:1; pendente (#8A5A00/#FFF4E0) ~5.4:1;
   conta-ativa (#1A1A1A/--primario, mesma combinação do .btn-primario) ~8.5:1;
   conta-inativa = mesma combinação de perfil-op; fora-escala
   (#1B4965/rgba(--azul,.12)) ~8.2:1. */
.badge-perfil-gestao { background: #0A4D8C; color: #fff; }
.badge-perfil-op { background: var(--bg-elevado-2); color: var(--texto-sub); }
.badge-acesso { background: var(--azul); color: #fff; }
.badge-pendente-dados { background: #FFF4E0; color: #8A5A00; border: 1px solid #F2C94C; }
.badge-conta-ativa { background: var(--primario); color: #1A1A1A; }
.badge-conta-inativa { background: var(--bg-elevado-2); color: var(--texto-sub); }
/* fora-escala (2026-08-30, corrigido 2026-08-30 — achado ux-front: ficava
   idêntico ao badge de cargo (perfil-op), os dois lidos como se fossem a
   mesma categoria de informação quando aparecem juntos no card). Tom
   azul-acinzentado (tint de --azul, mesmo padrão de --primario-fraco), não a
   cor de alerta de badge-pendente-dados — é informativo, não pendência — mas
   visualmente distinto do cinza neutro de perfil-op/conta-inativa. */
.badge-fora-escala { background: rgba(46, 122, 181, .12); color: #1B4965; border: 1px solid rgba(46, 122, 181, .35); }

.eq-aviso-pendencia { background: #FFF4E0; color: #8A5A00; border: 1px solid #F2C94C; border-radius: var(--radius-sm); padding: 10px 14px; font-weight: 600; font-size: 14px; margin-bottom: 14px; }

/* Drawer do formulário de funcionário — achado do ux-front (2026-08-29): com
   12+ campos, "Salvar" no fluxo normal do conteúdo saía de tela antes do
   cabeçalho ("Fechar") sumir, em mobile e no desktop de 480px. Vira flex
   column: só `.eq-drawer-scroll` rola, `.eq-drawer-rodape` (com Salvar) fica
   fixo no rodapé, sempre visível — mesmo raciocínio de app shell fixo, só que
   aplicado dentro do drawer. */
.eq-drawer-fundo { position: fixed; inset: 0; background: rgba(0,0,0,.5); z-index: 60; display: flex; justify-content: flex-end; }
.eq-drawer { background: var(--bg-card); width: 100%; max-width: 480px; height: 100%; display: flex; flex-direction: column; overflow: hidden; box-shadow: -8px 0 32px rgba(0,0,0,.28); }
.eq-drawer-scroll { flex: 1; min-height: 0; overflow-y: auto; padding: 20px; }
.eq-drawer-rodape { flex-shrink: 0; padding: 14px 20px calc(14px + env(safe-area-inset-bottom, 0px)); border-top: 1px solid var(--borda); background: var(--bg-card); }
.eq-drawer-topo { display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px; }
.eq-drawer-topo h2 { margin: 0; }
.eq-foto-linha { display: flex; align-items: center; gap: 16px; margin-bottom: 18px; }

.eq-toggle-linha { flex-direction: row !important; align-items: center; justify-content: space-between; }
.eq-toggle-grupo { display: flex; align-items: center; gap: 10px; }
.eq-toggle-grupo span { font-weight: 600; font-size: 14px; min-width: 28px; }

/* Seção "Status" (2026-08-30) — agrupa "Ativo" + "Aparece na Escala", mesmo
   padrão visual de .eq-secao-acesso (h3 + linha divisória acima). */
.eq-secao-status { border-top: 1px solid var(--borda); margin-top: 6px; padding-top: 16px; margin-bottom: 14px; }
.eq-secao-status h3 { margin: 0 0 10px; font-size: 15px; }
.eq-secao-status .eq-ajuda-campo { margin-top: 8px; }

.eq-secao-acesso { border-top: 1px solid var(--borda); margin-top: 6px; padding-top: 16px; }
.eq-secao-acesso h3 { margin: 0 0 10px; font-size: 15px; }
.eq-resumo-acesso { background: var(--bg-elevado); border-radius: var(--radius-sm); padding: 12px 14px; margin-bottom: 12px; font-size: 14px; display: flex; flex-direction: column; gap: 4px; }

.eq-erro-inline { color: var(--alerta); font-size: 13px; font-weight: 600; margin-top: -8px; margin-bottom: 12px; display: block; }
.eq-ajuda-campo { color: var(--texto-sub); font-size: 12px; margin-top: 2px; display: block; }

/* Modal do formulário de usuário — abre POR CIMA do drawer de funcionário
   quando vem de lá (z-index maior), mesma linguagem visual do .modal-caixa. */
.eq-usuario-fundo { position: fixed; inset: 0; background: rgba(0,0,0,.6); z-index: 70; display: flex; align-items: flex-end; justify-content: center; }
@media (min-width: 900px) { .eq-usuario-fundo { align-items: center; } }
.eq-usuario-caixa { background: var(--bg-card); border-radius: 20px 20px 0 0; padding: 20px; padding-bottom: 28px; width: 100%; min-width: 0; max-width: 420px; max-height: 90vh; overflow-y: auto; box-shadow: 0 -8px 32px rgba(0,0,0,.4); }
@media (min-width: 900px) { .eq-usuario-caixa { border-radius: var(--radius-lg); } }
.eq-usuario-nome { color: var(--texto-sub); margin: -6px 0 16px; font-size: 14px; }

/* "Remover acesso ao sistema" — achado do ux-front (2026-08-29): tinha o
   mesmo peso visual (btn-grande, largura 100%) do "Salvar" logo acima, risco
   de toque errado numa ação destrutiva. Vira link de texto pequeno, sem fundo
   preenchido, alinhado à esquerda, com uma borda separando do resto do
   formulário — continua clicável (min-height 36px) mas não compete mais com
   o CTA principal. */
.eq-zona-perigo { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--borda); text-align: left; }
.eq-link-perigo { background: none; border: none; padding: 6px 2px; min-height: 36px; color: var(--alerta); font-size: 13px; font-weight: 600; text-decoration: underline; }
.eq-link-perigo:hover { color: #ff5a5a; }

/* ---- Horus.pedir() — o substituto do prompt() nativo (2026-09-08) --------------
   Nasceu do bug que o Douglas achou: no app, o motivo do valor adicional era pedido por
   `prompt()`, e o padrão de todo o painel era `if (!motivo) return` — não salvava e não
   dizia nada. Reusa .modal-fundo/.modal-caixa/.form-linha/.btn; só o que está aqui é
   novo. Desenho do ux-front. */
.pedir-topo { display: flex; align-items: flex-start; gap: 8px; }
.pedir-topo h2 { flex: 1; min-width: 0; }
.pedir-fechar { width: 44px; height: 44px; margin: -8px -8px 0 0; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; font-size: 22px;
  line-height: 1; color: var(--texto-sub); background: transparent; border: none;
  border-radius: var(--radius-sm); cursor: pointer; }
.pedir-sub { margin: -4px 0 16px; color: var(--texto-sub); font-size: 14px; }
.pedir-ajuda { margin: 0 0 6px; color: var(--texto-sub); font-size: 13px; }

/* O "R$" fica DENTRO do campo, e não no rótulo: a unidade precisa continuar visível
   depois que a pessoa começa a digitar — o placeholder some e o rótulo fica longe. */
.campo-dinheiro { position: relative; display: flex; }
.campo-dinheiro input { flex: 1; padding-left: 44px !important; font-variant-numeric: tabular-nums; }
.campo-prefixo { position: absolute; left: 14px; top: 50%; transform: translateY(-50%);
  color: var(--texto-sub); font-size: 17px; font-weight: 600; pointer-events: none; }

/* O eco é a proteção de verdade contra digitação estranha: mostra o número que VAI ser
   gravado, antes de confirmar. Cobre até o que o parser errar. */
.campo-eco { font-size: 15px; font-weight: 600; color: var(--texto-sub); min-height: 20px; }
.campo-erro { display: flex; align-items: center; gap: 6px; margin: 2px 0 0;
  font-size: 14px; font-weight: 600; color: var(--alerta); }
.campo-erro::before { content: "⚠"; }
.form-linha input[aria-invalid="true"] { border-color: var(--alerta); border-width: 2px; }

.pedir-sugestoes { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
/* Borda em --texto-sub2 e não --borda: --borda contra o card branco dá 1,40:1 e a
   fronteira do controle some (WCAG 1.4.11 pede 3:1 pra não-texto). --texto-sub2 dá 3,36:1. */
.pedir-sugestao { min-height: 44px; padding: 0 16px; border-radius: 999px;
  background: var(--bg-elevado); border: 1px solid var(--texto-sub2);
  color: var(--texto); font-size: 14px; font-weight: 600; cursor: pointer; }
/* Fundo cheio, e não tinta clara: o padrão antigo (--primario-fraco com texto --primario)
   mede 1,88:1 — é o mesmo defeito do botão de forma de pagamento "selecionado", que
   praticamente não muda de aparência. Fundo cheio com #1A1A1A dá 8,43:1. */
.pedir-sugestao[aria-pressed="true"] { background: var(--primario); color: #1A1A1A;
  border-color: var(--primario-escuro); }

/* Rodapé fixo. Medido com o teclado aberto (viewport 360x450, que é o que sobra num
   celular pequeno): o modal tem 482px e o "Registrar sangria" caía atrás do teclado --
   o botão principal não pode depender de rolagem. Precisa ser filho DIRETO de
   .modal-caixa: `sticky` morre sem erro nenhum se qualquer ancestral até o scroller
   tiver overflow != visible. */
.modal-caixa:has(.modal-rodape-fixo) { padding-bottom: 0;
  /* O autoscroll do foco precisa saber que os últimos ~96px estão cobertos pelo rodapé:
     senão ele rola até o campo e para com ele ATRÁS do rodapé fixo. */
  scroll-padding-bottom: 96px; }
/* `--texto-sub2` e não `--borda-forte`: este border-top não é enfeite, é o que diz "tem
   conteúdo passando por baixo". `--borda-forte` composto sobre branco mede 1,75:1 e não
   cumpre essa função (mínimo 3:1 pra não-texto); `--texto-sub2` dá 3,36:1. */
.pedir-rodape, .modal-rodape-fixo { display: flex; gap: 10px; margin-top: 20px;
  position: sticky; bottom: 0; z-index: 1;
  margin-left: -20px; margin-right: -20px;
  padding: 12px 20px max(20px, calc(env(safe-area-inset-bottom, 0px) + 12px));
  background: var(--bg-card); border-top: 1px solid var(--texto-sub2);
  box-shadow: 0 -6px 16px rgba(15, 23, 42, .10); }
.pedir-rodape .btn { flex: 1; min-height: 52px; }
.pedir-rodape .btn-secundario { flex: 0 0 40%; }

.pedir-lista { display: flex; flex-direction: column; gap: 8px; }
.pedir-lista-item { display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  min-height: 56px; padding: 10px 14px; text-align: left;
  background: var(--bg-elevado); border: 1px solid var(--texto-sub2);
  border-radius: var(--radius-sm); cursor: pointer; }
.pedir-lista-item[aria-pressed="true"] { background: var(--primario); border-color: var(--primario-escuro); }
.pedir-lista-item .principal { font-size: 18px; font-weight: 700; letter-spacing: 1px; }
.pedir-lista-item .apoio { font-size: 13px; color: var(--texto-sub); }
.pedir-lista-item[aria-pressed="true"] .apoio { color: #1A1A1A; }
.pedir-vazio { text-align: center; padding: 24px 8px; color: var(--texto-sub); }

/* Horus.mostrar() — resultado, não pergunta. A palavra ("Falta"/"Sobra"/"Bateu certinho")
   carrega a informação e a cor é só reforço: WCAG 1.4.1, não depender de cor. */
.pedir-linhas { display: flex; flex-direction: column; margin: 4px 0; }
.pedir-linha { display: flex; justify-content: space-between; align-items: baseline;
  gap: 12px; padding: 10px 0; font-size: 16px; }
.pedir-linha .rotulo { color: var(--texto-sub); min-width: 0; }
/* tabular-nums: sem isso "R$ 468,00" e "R$ 480,00" não alinham a vírgula, e comparar os
   dois a olho é o ponto inteiro desta tela. */
.pedir-linha .valor { font-weight: 700; white-space: nowrap; font-variant-numeric: tabular-nums; }
.pedir-linha.com-separador { border-top: 1px solid var(--texto-sub2); margin-top: 4px; padding-top: 14px; }
.pedir-linha.destaque .rotulo, .pedir-linha.destaque .valor { font-size: 20px; font-weight: 800; }
.pedir-linha.destaque-ok .rotulo, .pedir-linha.destaque-ok .valor { color: #1E6E3C; }
.pedir-linha.destaque-aviso .rotulo, .pedir-linha.destaque-aviso .valor { color: var(--aviso); }
.pedir-linha.destaque-alerta .rotulo, .pedir-linha.destaque-alerta .valor { color: var(--alerta); }
.pedir-linha.so-texto { justify-content: center; font-size: 20px; font-weight: 800; }
.pedir-linha.so-texto.destaque-ok { color: #1E6E3C; }

/* Toast de sucesso/erro — não existia padrão compartilhado no app ainda (resto
   usa alert() síncrono); fica em document.body direto, acima de tudo. */
.eq-toast-wrap { position: fixed; left: 0; right: 0; bottom: max(16px, env(safe-area-inset-bottom, 0px)); display: flex; flex-direction: column; align-items: center; gap: 8px; z-index: 300; pointer-events: none; padding: 0 16px; }
.eq-toast { pointer-events: auto; max-width: 420px; width: 100%; padding: 12px 16px; border-radius: var(--radius); font-weight: 600; font-size: 14px; box-shadow: 0 4px 20px rgba(0,0,0,.25); opacity: 0; transform: translateY(12px); transition: opacity 200ms ease, transform 200ms ease; }
.eq-toast-visivel { opacity: 1; transform: translateY(0); }
.eq-toast-sucesso { background: #1A1A1A; color: #fff; border-left: 4px solid var(--primario); }
.eq-toast-erro { background: #1A1A1A; color: #fff; border-left: 4px solid var(--alerta); }
/* Achado ux-front 2026-08-30 (medido de verdade: toast ia até y=796, a barra
   inferior fixa .nav-mobile começa em y=761, ~35px de sobreposição) — soma a
   altura da barra (51px) na margem inferior do toast só no breakpoint em que
   ela existe (<900px, mesmo de .nav-mobile), pra ele flutuar acima dela.
   Precisa vir DEPOIS da regra base acima (mesma especificidade — a 1ª
   tentativa ficou antes, no bloco de media query lá em cima, e por isso a
   regra base sempre vencia o empate de especificidade por ordem no arquivo). */
@media (max-width: 899px) {
  .eq-toast-wrap { bottom: calc(51px + max(16px, env(safe-area-inset-bottom, 0px))); }
}

/* Termo de prestação de serviço (2026-08-29) — mesma linguagem visual da seção
   "Acesso ao sistema" logo acima (separador + h3). */
.eq-secao-termo { border-top: 1px solid var(--borda); margin-top: 6px; padding-top: 16px; }
.eq-secao-termo h3 { margin: 0 0 10px; font-size: 15px; }

/* View de impressão do termo — overlay full-screen com o documento formatado
   pra A4, mesma técnica de #recibo-imprimir-wrap (kanban.js): visibility:hidden
   no resto da página no @media print, só o wrap fica visível. Fundo branco de
   propósito (documento pra assinar/imprimir não deve sair no tema escuro). */
.termo-fundo { position: fixed; inset: 0; background: #fff; z-index: 90; overflow-y: auto; }
.termo-topo-acoes { position: sticky; top: 0; background: var(--bg-elevado); padding: 10px 16px; display: flex; gap: 8px; justify-content: flex-end; border-bottom: 1px solid var(--borda); }
.termo-doc { background: #fff; color: #111; max-width: 210mm; margin: 0 auto; padding: 16mm 18mm 12mm; font-family: Georgia, 'Times New Roman', serif; }
.termo-cabecalho { text-align: center; font-weight: 700; font-size: 17px; padding-bottom: 10px; }
/* Linha divisória preta sólida e espessa de propósito (não cinza clara/fina) —
   achado do projeto: traço fino some em fotocópia/2ª via de documento impresso. */
.termo-doc hr.termo-linha { border: none; border-top: 3px solid #111; margin: 0 0 18px; }
.termo-doc h1 { font-size: 15px; text-align: center; text-transform: uppercase; letter-spacing: .03em; margin: 0 0 20px; }
.termo-doc p { line-height: 1.55; font-size: 13px; margin: 0 0 11px; text-align: justify; color: #111; }
/* Linha "{cidade}, {data}." — cidade fica em branco pra preencher à mão.
   Achado do ux-front (2026-08-29): underscores fixos quebravam feio em telas
   estreitas (vírgula solta sozinha na linha de baixo). Vira um espaço em
   branco de largura responsiva (border-bottom, não caractere) que encolhe
   junto com a viewport, então a linha inteira cabe numa só em qualquer
   tamanho de tela/impressão. */
.termo-data-linha { text-align: left !important; }
.termo-cidade-vazia { display: inline-block; width: clamp(70px, 32vw, 220px); border-bottom: 1px solid #111; }
.termo-assinaturas { margin-top: 44px; display: flex; flex-direction: column; gap: 40px; }
.termo-assinatura-linha { border-top: 1px solid #111; width: min(100%, 340px); margin: 0 auto; text-align: center; padding-top: 6px; font-size: 12px; line-height: 1.5; }
.termo-rodape { margin-top: 30px; font-size: 10px; color: #555; display: flex; justify-content: space-between; gap: 12px; }
@media print {
  body * { visibility: hidden; }
  #termo-imprimir-wrap, #termo-imprimir-wrap * { visibility: visible; }
  #termo-imprimir-wrap { position: fixed; inset: 0; background: #fff; }
  #termo-imprimir-wrap .btn, #termo-imprimir-wrap .btn-link { display: none !important; }
}

/* ---------- Escala — grade de MÊS inteiro (2026-08-29, troca a v. anterior
   que era grade semanal — desenho aprovado pelo ux-front). UMA estrutura de
   tabela só (não existem mais 2 estruturas de DOM em paralelo tipo
   desktop/mobile — isso causava um bug real de duplicação numa rodada
   anterior). Técnica "canto congelado" de planilha: coluna Pessoa e
   cabeçalho de dias sticky dentro de um container com overflow-x:auto — só
   esse container rola na horizontal, nunca a página (exceção deliberada à
   regra geral de nunca ter scroll horizontal — tabela densa tipo planilha).
   CSS decide célula rica (≥768px, mostra hora) vs compacta (<768px, só
   cor+ícone) via media query, sem trocar de estrutura no JS. ---------- */
.es-topo { display: flex; justify-content: flex-end; margin-bottom: 12px; }
.es-ajuda { color: var(--texto-sub); font-size: 13px; margin: 0 0 12px; }

/* Esqueleto pulsando (carregando) — mesma paleta neutra do resto do app, sem
   depender de imagem/spinner. */
.es-skeleton { display: flex; flex-direction: column; gap: 8px; }
.es-skeleton-linha { height: 38px; border-radius: var(--radius-sm); background: var(--bg-elevado); animation: es-pulsar 1.2s ease-in-out infinite; }
@keyframes es-pulsar { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }

.es-erro { color: var(--alerta); font-weight: 600; margin-bottom: 10px; }

.es-aviso-cobertura { background: #FFF4E0; color: #8A5A00; border: 1px solid #F2C94C; border-radius: var(--radius-sm); padding: 10px 14px; font-weight: 600; font-size: 14px; margin-bottom: 12px; }
.es-aviso-padrao { background: var(--bg-elevado); color: var(--texto-sub); border: 1px solid var(--borda); border-radius: var(--radius-sm); padding: 10px 14px; font-size: 14px; margin-bottom: 12px; }
.es-icone-aviso { color: var(--aviso); font-size: 10px; vertical-align: top; }

.es-grade-cartao { padding-bottom: 10px; }
.es-grade-nav { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 14px; }
.es-nav-btn { min-width: 44px; flex-shrink: 0; }
.es-semana-info { display: flex; flex-direction: column; align-items: center; gap: 2px; text-align: center; }
.es-semana-info strong { font-size: 15px; text-transform: capitalize; }

/* ---------- Accordion (Horário padrão / Previsão de fila / Tempo médio) —
   <details> nativo: acessível de graça (teclado, leitor de tela), sem exigir
   JS pra abrir/fechar. */
.es-accordion > summary { cursor: pointer; list-style: none; font-family: var(--font-heading), sans-serif; font-weight: 600; font-size: 17px; padding: 2px 0; margin-bottom: 8px; display: flex; justify-content: space-between; align-items: center; min-height: 44px; }
.es-accordion > summary::-webkit-details-marker { display: none; }
.es-accordion > summary::after { content: '▾'; color: var(--texto-sub); transition: transform 150ms ease; }
.es-accordion[open] > summary::after { transform: rotate(180deg); }
.es-accordion > summary:focus-visible { outline: 2px solid var(--azul); outline-offset: 2px; }
/* "Previsão de fila"/"Tempo médio por lavador" (spec: card normal no desktop,
   accordion só no mobile) — ≥900px força tudo visível e desliga o toggle,
   vira card comum; <900px comporta-se como qualquer <details> (fechado por
   padrão, sem o atributo `open`). */
@media (min-width: 900px) {
  .es-accordion-desktop-aberto > summary { pointer-events: none; cursor: default; }
  .es-accordion-desktop-aberto > summary::after { display: none; }
  .es-accordion-desktop-aberto > *:not(summary) { display: block !important; }
}

/* ---------- Grade do mês — canto congelado ---------- */
.es-grade-mes-scroll {
  overflow-x: auto; overflow-y: visible; max-width: 100%;
  border: 1px solid var(--borda); border-radius: var(--radius-sm);
  /* Densidade da célula — sobrescrita no media query mobile abaixo. Uma
     variável só controlada por breakpoint, lida por todas as larguras da
     tabela (nunca duas estruturas de DOM diferentes). */
  --es-col-largura: 78px; --es-col-pessoa-largura: 152px; --es-cel-fonte: 12px;
  /* Scrollbar sempre visível (não a overlay fina que some sem interação em
     alguns navegadores/SOs) — pista clara de que dá pra arrastar na
     horizontal. Fica na classe do CONTAINER, não da grade em si, então
     qualquer tabela que reaproveite esse mesmo wrapper (grade de mês, rodapé
     TRABALHANDO — é o <tfoot> da mesma tabela — e o card "Quantas vezes
     trabalhou cada dia") sai com a mesma pista automaticamente, sem duplicar
     regra em lugar nenhum. Achado ux-front 2026-08-30: a tabela nova cortava
     coluna sem nenhum indício visual de que tinha mais conteúdo pro lado.
     scrollbar-width/scrollbar-color cobrem Firefox; ::-webkit-scrollbar*
     cobre Chromium/Safari. */
  scrollbar-width: thin;
  scrollbar-color: var(--borda-forte) var(--bg-elevado);
}
.es-grade-mes-scroll::-webkit-scrollbar { height: 10px; }
.es-grade-mes-scroll::-webkit-scrollbar-track { background: var(--bg-elevado); }
.es-grade-mes-scroll::-webkit-scrollbar-thumb { background: var(--borda-forte); border-radius: 5px; }
.es-grade-mes-scroll::-webkit-scrollbar-thumb:hover { background: var(--texto-sub2); }
.es-tabela-mes { border-collapse: separate; border-spacing: 0; table-layout: fixed; }
.es-tabela-mes th, .es-tabela-mes td { padding: 0; border-right: 1px solid var(--borda); border-bottom: 1px solid var(--borda); }
.es-tabela-mes thead th { border-top: 1px solid var(--borda); }
.es-tabela-mes th:not(.es-th-pessoa), .es-tabela-mes td:not(.es-td-pessoa) { width: var(--es-col-largura); min-width: var(--es-col-largura); }

/* Coluna Pessoa — sticky à esquerda, fundo sólido + sombra separando da área
   que rola. */
.es-th-pessoa, .es-td-pessoa {
  position: sticky; left: 0; z-index: 2;
  width: var(--es-col-pessoa-largura); min-width: var(--es-col-pessoa-largura); max-width: var(--es-col-pessoa-largura);
  background: var(--bg-card); border-left: 1px solid var(--borda);
  box-shadow: 2px 0 4px rgba(0,0,0,.08);
  text-align: left; padding: 8px 10px !important; font-weight: 600; font-size: 13px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.es-th-pessoa { z-index: 4; background: var(--bg-elevado); font-size: 11px; text-transform: uppercase; color: var(--texto-sub); }
.es-sub-perfil { font-weight: 400; font-size: 10px; color: var(--texto-sub); text-transform: uppercase; white-space: nowrap; }

/* Cabeçalho de dias — sticky no topo dentro do container que rola. */
.es-tabela-mes thead th { position: sticky; top: 0; z-index: 3; background: var(--bg-elevado); }
.es-th-dia { padding: 6px 2px !important; text-align: center; font-size: 11px; font-weight: 700; color: var(--texto-sub); line-height: 1.3; }
/* Abreviação de 3 letras (DOM/SEG/TER/QUA/QUI/SEX/SAB) — achado ux-front 2ª
   rodada: 1 letra só era ambígua (S = Sáb/Seg/Sex, Q = Qua/Qui) sem a moldura
   fechada de 7 colunas que a v. semana tinha. `white-space:nowrap` +
   `letter-spacing` negativo garantem que cabe na coluna estreita do mobile
   sem quebrar linha (conferido a 375px). */
.es-dia-dow { display: block; font-size: 9px; text-transform: uppercase; color: var(--texto-sub2); white-space: nowrap; letter-spacing: -.2px; }
.es-dia-num { display: block; font-size: 13px; white-space: nowrap; }

.es-col-hoje { outline: 2px solid var(--primario); outline-offset: -2px; }
/* Fundo levemente diferente sáb/dom (ajuda a "contar semanas" rolando). */
.es-col-fds { background: var(--bg-elevado); }
.es-th-pessoa.es-col-fds, .es-td-pessoa.es-col-fds { background: var(--bg-card); } /* nunca no congelado */
/* Borda mais grossa a cada 7 colunas — separa semanas visualmente. */
.es-col-sep-semana { border-right: 2px solid var(--borda-forte); }

.es-celula {
  width: 100%; height: 100%; min-height: 44px; display: flex; align-items: center; justify-content: center; gap: 3px;
  background: var(--bg-card); color: var(--texto); font-size: var(--es-cel-fonte); font-weight: 600;
  transition: background var(--transicao), border-color var(--transicao); border: 1px solid transparent; border-radius: 0;
}
.es-celula:hover { background: var(--bg-elevado-2); }
.es-cel-icone { line-height: 1; }
.es-cel-hora { line-height: 1; white-space: nowrap; }
/* Presente (padrão OU editado célula a célula) sempre com a MESMA aparência
   neutra — com revezamento de folga, editar dia a dia é uso normal, não
   exceção; só período menor/falta se destacam (spec Douglas/ux-front). */
.es-cel-vazia { color: var(--texto-sub2); font-weight: 400; }
.es-cel-normal { background: var(--primario-fraco); color: var(--texto); }
.es-cel-pm { background: var(--primario-fraco); border: 1px dashed var(--primario-escuro); }
.es-cel-falta { background: rgba(217,54,54,.12); color: var(--alerta); }
.es-cel-abonada { background: var(--bg-elevado-2); color: var(--texto-sub); }

/* ---------- Rodapé TRABALHANDO — headcount por dia (2026-08-30) ----------
   Linha extra no <tfoot> da mesma tabela da grade, técnica igual à coluna
   Pessoa/cabeçalho de dias (canto congelado): sticky bottom só tem efeito de
   verdade se algum ancestral tiver altura/overflow-y limitados — sem isso cai
   pro fim natural da tabela, o que já é aceitável (spec Douglas). */
.es-tabela-mes tfoot th, .es-tabela-mes tfoot td {
  position: sticky; bottom: 0; z-index: 3; background: var(--bg-elevado);
  border-top: 2px solid var(--borda-forte);
}
.es-tabela-mes tfoot .es-th-trabalhando { z-index: 5; text-align: left; }
.es-headcount-valor {
  display: flex; align-items: center; justify-content: center; min-height: 36px;
  font-size: var(--es-cel-fonte); font-weight: 700; color: var(--texto);
}
/* Classe pronta pro futuro (threshold configurável de "headcount baixo") —
   SEM lógica de ativação nenhuma ainda, nada usa isso hoje (spec Douglas
   2026-08-30: só deixar a classe pronta). */
.escala-headcount-baixo { background: rgba(217,54,54,.12); color: var(--alerta); }

/* ---------- Mobile (<768px): célula compacta — só cor+ícone, sem hora
   escrita; número do dia pequeno no topo da coluna já vem do cabeçalho
   (.es-dia-num). Alvo de toque: a LINHA da pessoa (altura) fica ≥44px mesmo
   com a coluna mais estreita — concessão aceita (errar o toque só abre o dia
   vizinho, sem ação destrutiva). ---------- */
@media (max-width: 767px) {
  /* 38px (não 36px) — folga extra pra abreviação de 3 letras caber sem
     apertar (conferido a 375px de viewport, ainda dentro dos ~34-38px do
     desenho aprovado). */
  .es-grade-mes-scroll { --es-col-largura: 38px; --es-col-pessoa-largura: 96px; --es-cel-fonte: 13px; }
  .es-cel-hora { display: none; }
  .es-th-dia { font-size: 10px; padding: 4px 1px !important; }
  .es-dia-dow { font-size: 8px; letter-spacing: -.4px; }
}

/* ---------- Editor de célula (bottom sheet/modal, 3 cards clicáveis —
   redesenho 2026-08-30 aprovado pelo ux-front, substitui os radio buttons
   antigos: Falta em destaque porque é o toque mais rápido/mais comum do
   fluxo. Falta/Presente, quando NÃO são o estado atual do dia, salvam no
   toque só (sem precisar do botão Salvar no fim) — só Período menor, e
   "editar o card que já é o estado atual", continuam expandindo um painel
   com botão Salvar próprio (fluxo que já existia, sem mudança). ---------- */
.es-editor-caixa { max-width: 420px; }
.es-editor-topo { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; margin-bottom: 14px; }
.es-editor-topo h2 { margin: 0; font-size: 17px; }
.es-editor-erro { background: rgba(217,54,54,.1); color: var(--alerta); border-radius: var(--radius-sm); padding: 10px 12px; font-size: 13px; font-weight: 600; margin-bottom: 12px; }

.es-cards-opcoes { display: flex; flex-direction: column; gap: 10px; margin-bottom: 4px; }
.es-card-opcao {
  display: flex; align-items: center; gap: 12px; width: 100%; min-height: 56px;
  padding: 10px 14px; border-radius: var(--radius); border: 1px solid var(--borda);
  background: var(--bg-elevado); cursor: pointer; text-align: left; font-family: inherit;
  transition: opacity var(--transicao), background var(--transicao);
}
.es-card-opcao:disabled { opacity: .55; cursor: default; }
.es-card-opcao[aria-pressed="true"] { border-color: var(--borda-forte); background: var(--bg-card); box-shadow: inset 0 0 0 1px var(--borda-forte); }
.es-card-opcao:focus-visible { outline: 3px solid var(--azul); outline-offset: 2px; }
.es-card-icone { flex-shrink: 0; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; border-radius: 50%; font-size: 16px; font-weight: 700; background: var(--bg-elevado-2); color: var(--texto-sub); }
.es-card-texto { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.es-card-titulo { font-weight: 700; font-size: 14px; color: var(--texto); }
.es-card-sub { font-size: 12px; color: var(--texto-sub); }
.es-card-badge { display: inline-block; margin-left: 6px; font-size: 11px; font-weight: 700; color: var(--primario-escuro); background: var(--primario-fraco); border-radius: 999px; padding: 1px 8px; vertical-align: middle; }
.es-card-spinner { width: 18px; height: 18px; border-radius: 50%; border: 2px solid rgba(0,0,0,.15); border-top-color: var(--texto-sub); animation: es-spin .7s linear infinite; flex-shrink: 0; }
@keyframes es-spin { to { transform: rotate(360deg); } }
.es-card-erro { color: var(--alerta); font-size: 12px; font-weight: 600; margin: -4px 0 0; padding: 0 2px; }

/* Falta em destaque — mesma cor/alpha que já pinta a célula ✕ de falta na
   grade (.es-cel-falta), contraste ≥4.5:1 já é o mesmo daquela célula
   (reaproveitado, não é cor nova). */
.es-card-opcao-falta { background: rgba(217,54,54,.12); border-color: rgba(217,54,54,.3); }
.es-card-opcao-falta .es-card-icone { background: var(--alerta); color: #fff; }
.es-card-opcao-falta .es-card-titulo { color: var(--alerta); }
.es-card-opcao-falta[aria-pressed="true"] { box-shadow: inset 0 0 0 1px var(--alerta); }
.es-card-icone-normal { background: var(--primario-fraco); color: var(--primario-escuro); }

.es-editor-campos { padding: 2px 2px 10px; display: flex; flex-direction: column; gap: 10px; }
.es-editor-campos label { color: var(--texto-sub); font-size: 13px; display: flex; flex-direction: column; gap: 3px; }
.es-editor-campos input[type="text"] { min-height: 44px; padding: 8px 10px; border-radius: var(--radius-sm); border: 1px solid var(--borda); background: var(--bg-elevado); color: var(--texto); font-size: 14px; }
.es-editor-horarios { display: flex; gap: 10px; }
.es-editor-horarios > div { flex: 1; display: flex; flex-direction: column; gap: 3px; }
.es-editor-horarios label { color: var(--texto-sub); font-size: 12px; }
/* Sem filtro por type: os campos aqui eram <input type="time"> e viraram texto com
   mascara HH:MM em 2026-09-07 (o nativo mostrava "08:00 AM" em navegador em ingles).
   O seletor tinha que mudar NO MESMO commit -- deixado como estava, a regra ficaria
   orfa de verdade e os campos perderiam altura, padding e borda de uma vez. */
.es-editor-horarios input { min-height: 44px; padding: 6px 8px; border-radius: var(--radius-sm); border: 1px solid var(--borda); background: var(--bg-elevado); color: var(--texto); font-size: 14px; }
.es-checkbox-linha { flex-direction: row !important; align-items: center; gap: 8px !important; }
.es-checkbox-linha input { width: 18px; height: 18px; }

/* Toast de "Falta marcada" com ações inline (Desfazer/Adicionar motivo) —
   mesma base visual do .eq-toast genérico (dark, borda de acento), só some
   com o texto/ações num único parágrafo em vez de texto simples. */
.es-toast-falta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
/* Achado ux-front 2026-08-30 (medido: 65×32 e 119×32, 12px abaixo do mínimo)
   — min-height sozinho não bastava porque o botão ficava inline; inline-flex
   + align-items:center garante que o box de verdade cresce pra 44px (texto
   continua do mesmo tamanho, só o alvo de toque fica maior). */
.es-toast-acao { display: inline-flex; align-items: center; background: none; border: none; padding: 10px 2px; min-height: 44px; color: #fff; font-weight: 700; text-decoration: underline; cursor: pointer; font-size: 14px; }
.es-toast-acao:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* ---------- Resumo de desconto ---------- */
.es-resumo-tabela-wrap { overflow-x: auto; }
.es-resumo-tabela { width: 100%; border-collapse: collapse; font-size: 13px; }
.es-resumo-tabela th, .es-resumo-tabela td { padding: 8px 10px; text-align: left; border-bottom: 1px solid var(--borda); white-space: nowrap; }
.es-resumo-tabela th { color: var(--texto-sub); font-size: 11px; text-transform: uppercase; font-weight: 700; }
.es-sem-salario { color: var(--aviso); font-size: 12px; }
.es-lista-detalhe { list-style: none; margin: 6px 0 0; padding: 0; font-size: 12px; color: var(--texto-sub); white-space: normal; }
.es-lista-detalhe li { padding: 3px 0; border-bottom: 1px dashed var(--borda); }
.es-lista-detalhe li:last-child { border-bottom: none; }

/* ---------- Quantas vezes trabalhou cada dia (2026-08-30) ----------
   Mesma técnica de canto congelado da grade de mês (.es-grade-mes-scroll +
   .es-tabela-mes, reaproveitados sem inventar padrão novo) — só a coluna
   TOTAL e o padding das células numéricas (aqui não tem o botão .es-celula
   por dentro) são específicos deste card. */
.es-diassemana-tabela td:not(.es-td-pessoa), .es-diassemana-tabela th:not(.es-th-pessoa) {
  text-align: center; padding: 8px 4px !important; font-weight: 600; font-size: 13px;
}
.es-diassemana-tabela thead th.es-diassemana-total-header,
.es-diassemana-tabela tbody td.es-diassemana-total {
  background: var(--primario-fraco); font-weight: 700; color: var(--texto);
}

/* ---------- View imprimível (A4 paisagem) — mesma técnica de
   #recibo-imprimir-wrap/#termo-imprimir-wrap: overlay full-screen +
   window.print() + @media print escondendo tudo, exceto o wrap. Página
   nomeada (`page:`) pra não afetar o @page padrão (retrato) usado por
   recibo/termo quando eles imprimem noutra hora. */
@page horus-escala-imp { size: A4 landscape; margin: 10mm; }
.es-imp-fundo { position: fixed; inset: 0; background: #fff; z-index: 90; overflow-y: auto; page: horus-escala-imp; }
.es-imp-topo-acoes { position: sticky; top: 0; background: var(--bg-elevado); padding: 10px 16px; display: flex; gap: 8px; justify-content: flex-end; border-bottom: 1px solid var(--borda); }
.es-imp-doc { background: #fff; color: #111; padding: 10mm 14mm; }
/* 2 quinzenas = 2 páginas (2026-08-29, grade de mês inteiro: 31 colunas não
   cabem legíveis numa A4 paisagem só) — page-break entre elas, nunca depois
   da última (senão imprime uma 3ª folha em branco). */
.es-imp-doc:not(:last-child) { page-break-after: always; }
.es-imp-cabecalho { display: flex; align-items: center; gap: 14px; margin-bottom: 10px; }
.es-imp-logo { height: 40px; }
.es-imp-cabecalho h1 { font-size: 16pt; margin: 0; color: #111; text-transform: capitalize; }
.es-imp-cabecalho p { font-size: 10pt; margin: 2px 0 0; color: #444; }
.es-imp-aviso { font-size: 11pt; font-weight: 700; border: 2px solid #111; border-radius: 4px; padding: 6px 10px; margin: 0 0 10px; }
/* Bordas grossas pretas de propósito (convenção do projeto): traço fino/cinza
   some na fotocópia/2ª via de um documento impresso na loja. */
.es-imp-tabela { width: 100%; border-collapse: collapse; table-layout: fixed; }
.es-imp-tabela th, .es-imp-tabela td { border: 3px solid #111; padding: 6px 4px; text-align: center; color: #111; }
.es-imp-tabela thead th { font-size: 10pt; font-weight: 700; }
.es-imp-tabela th:first-child { width: 13%; }
.es-imp-nome { text-align: left; font-size: 11pt; font-weight: 700; padding-left: 8px !important; }
.es-imp-normal { font-size: 11pt; font-weight: 700; }
.es-imp-pm { font-size: 11pt; font-weight: 700; border-style: dashed !important; }
.es-imp-falta { font-size: 16pt; font-weight: 800; }
.es-imp-motivo { font-size: 8pt; font-weight: 400; }
.es-imp-vazia { color: #777; font-weight: 400; }
.es-imp-legenda { font-size: 9pt; color: #333; margin-top: 10px; }
@media print {
  body * { visibility: hidden; }
  #es-imprimir-wrap, #es-imprimir-wrap * { visibility: visible; }
  #es-imprimir-wrap { position: fixed; inset: 0; background: #fff; }
  #es-imprimir-wrap .btn, #es-imprimir-wrap .btn-link { display: none !important; }
}

/* ===== Cobrar agora / selo de pagamento no card (2026-09-04) =====
   Desenho do ux-front. Dois eixos que nunca se misturam: ETAPA (borda + botão
   principal, como sempre foi) e DINHEIRO (selo + faixa + botão secundário, novo).
   Cores fixas de propósito, não `--primario`: o laranja da marca sobre branco dá ~2:1
   e não passa em texto (achado do QA nesta mesma semana, ver CHANGELOG 2026-09-04). */
/* Preenchimento SÓLIDO, não fundo claro: #E8F5E9 contra o card #EEF0F3 dá 1,015:1 --
   na prática não existia pílula nenhuma, era só texto verde, e o selo é a 1ª camada do
   "não cobrar 2x" (tem que ser varrido com o olho antes do toque). Sólido também não
   depende do fundo do card, então sobrevive a troca de token e vale igual no Flutter. */
.card-selo-pagamento { background: #2E7D32; color: #FFFFFF;
  border-radius: 999px; padding: 3px 10px; font-size: 12px; font-weight: 700; white-space: nowrap; }
.card-selo-pagamento.selo-faturado { background: #0D47A1; color: #FFFFFF; }

/* O botão principal nunca teve preenchimento (`.btn` sem `.btn-primario`), e o fundo
   default empata com o card. Enquanto ele era filho único isso passava; com o
   "Cobrar agora" ao lado, a ação SECUNDÁRIA ficou visualmente mais forte que a
   principal -- o inverso do que esta entrega protege (achado do ux-front no print).
   Cor por etapa, como o app Flutter já faz. As 3 já existem no sistema e foram
   medidas contra o card real (#EEF0F3): texto branco >= 4,5:1 e fundo >= 3:1. */
/* ATENÇÃO, os dois âmbares são de propósito -- não "unifique":
   a BORDA ESQUERDA do card é #F0A800 (código de cor: precisa ser viva pra varrer o
   quadro de longe, e não tem texto em cima), enquanto o BOTÃO é #B45309 (superfície com
   texto branco em cima: precisa ser escura pra dar 5,02:1). Mesma família, funções
   diferentes -- é o que o Material faz com 500 pra acento e 700/800 pra botão
   preenchido. Trocar o botão pelo âmbar da borda derruba o contraste pra 1,78:1. */
.card-os .btn-avancar { color: #FFFFFF; background: #607D8B; }
.card-os[data-status="AGUARDANDO"]  .btn-avancar { background: var(--aviso); } /* 5,02:1 / 4,40:1 */
.card-os[data-status="EM_EXECUCAO"] .btn-avancar { background: var(--azul); }  /* 4,60:1 / 4,03:1 */
.card-os[data-status="PRONTO"]      .btn-avancar { background: #2E7D32; }      /* 5,13:1 / 4,49:1 */

.card-pago-faixa { background: #E8F5E9; color: #1B5E20; border-radius: 6px;
  padding: 6px 10px; font-size: 13px; font-weight: 600; margin: 6px 0 2px; }

/* 48px de alvo e 8px de folga do botão de cima: a pessoa usa isso em pé, com a mão
   molhada, e um toque errado aqui cobra o carro errado. */
/* O card NAO tem fundo branco: e --bg-elevado (#EEF0F3). Todo contraste aqui foi
   medido contra ESSE fundo, nao contra #fff -- sobre branco os numeros sao outros e
   a borda neutra passava sem passar. */
.btn-cobrar { min-height: 48px; margin-top: 8px;
  background: #FFFFFF; color: #1B5E20; border: 2px solid #2E7D32; font-weight: 700; }
.btn-cobrar:hover { background: #F1F8E9; }
/* Em PRONTO o botão principal já é verde cheio — aqui o secundário vira neutro pra
   não virar dois botões com o mesmo peso disputando o toque. */
/* WCAG 1.4.11 pede 3:1 pro limite do componente, e num botao de contorno a borda E o
   componente. Medido sobre o fundo REAL do card (#EEF0F3): #B0BEC5 = 1,67:1 e
   #78909C = 2,93:1, os dois reprovam. #607D8B = 3,83:1. */
.btn-cobrar.btn-cobrar-neutro { color: #37474F; border-color: #607D8B; }
.btn-cobrar.btn-cobrar-neutro:hover { background: #ECEFF1; }

.card-sem-permissao-pagto { color: var(--texto-sub); font-size: 13px; margin-top: 8px; }
/* 16px de folga antes da linha de "cancelar" (acao destrutiva, pede motivo): com um
   botao a mais empilhado o dedo desce e encontrava o cancelar colado -- medido 0px. */
.card-linha-baixo { margin-top: 16px; }

.kanban-aviso { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: #E8F5E9; color: #1B5E20; border: 1px solid #A5D6A7; border-radius: 8px;
  padding: 10px 14px; margin: 0 0 12px; font-weight: 600; }
.kanban-aviso-acao { background: none; border: none; color: #1B5E20; font-weight: 700;
  text-decoration: underline; cursor: pointer; min-height: 44px; padding: 0 4px; font-size: inherit; }
.pg-subtitulo { color: var(--texto-sub); font-size: 14px; margin: -6px 0 12px; }
.coluna-vazia { color: var(--texto-sub); font-size: 13px; text-align: center; padding: 18px 8px; margin: 0; }

/* ---------- Dias que fogem do normal (2026-09-06) ----------
   Cartao por dia, um toque grava. Alvo minimo 48px em todo botao: quem usa esta em
   pe, no celular, com cliente esperando. Nada depende so de cor -- todo estado leva
   icone + a palavra escrita. */
/* Cores proprias do bloco, escopadas de proposito: --texto-sub2 (3,08:1 sobre o
   cinza do cartao), --alerta (4,25:1) e --azul (4,22:1) reprovam WCAG aqui, mas
   trocar o token global obrigaria o QA a revarrer o painel inteiro. Escopado e 1
   rodada; global e 3. Os tokens globais ficam como divida separada. */
#exc-bloco {
  --exc-rotulo: #5F6B7A;      /* 4,97:1 sobre #f4f5f7, 5,43:1 sobre #ffffff */
  --exc-alerta-txt: #C62828;  /* 5,15:1 sobre #f4f5f7 */
  --exc-azul-txt: #1F6499;    /* 5,76:1 sobre #f4f5f7 */
}
.exc-folha { --exc-rotulo: #5F6B7A; --exc-alerta-txt: #C62828; --exc-azul-txt: #1F6499; }
.exc-apoio { color: var(--texto-sub); font-size: 13px; margin: -6px 0 14px; }
.exc-grupo { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .08em; color: var(--exc-rotulo); margin: 18px 0 8px; }
.exc-grupo:first-child { margin-top: 0; }
.exc-cartao { border: 1px solid var(--borda); border-radius: var(--radius); padding: 14px; margin-bottom: 10px; background: var(--bg); }
.exc-quando { font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--exc-rotulo); }
/* Observacao no limite dos 60 caracteres pode ser UMA palavra so: sem isto o cartao
   estoura a largura da tela e a previa -- que existe pra ele LER o texto antes de
   publicar -- corta no meio da palavra (achado do QA, 2026-09-06). */
.exc-nome, .exc-previa, .exc-estado { overflow-wrap: anywhere; }
.exc-nome { font-size: 17px; font-weight: 700; margin: 2px 0 8px; }
.exc-estado { font-size: 13.5px; font-weight: 700; display: flex; align-items: center; gap: 6px; margin-bottom: 12px; }
.exc-estado-pendente { color: var(--aviso); }
.exc-estado-fechado  { color: var(--exc-alerta-txt); }
.exc-estado-especial { color: var(--exc-azul-txt); }
.exc-estado-normal   { color: #1B7A3D; }
/* Prova de que funcionou: o texto publico que aquele dia gera, dentro do proprio
   cartao -- em vez de salvar e ir conferir no site. */
.exc-previa { background: var(--bg-card); border: 1px dashed var(--borda-forte); border-radius: var(--radius-sm); padding: 10px 12px; font-size: 13.5px; line-height: 1.45; margin-bottom: 12px; }
.exc-previa-rotulo { display: block; font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--exc-rotulo); margin-bottom: 4px; }
.exc-previa-nota { display: block; font-size: 12px; color: var(--exc-rotulo); margin-top: 6px; }
.exc-acoes { display: flex; gap: 8px; }
.exc-acoes .btn { flex: 1; }
/* No eixo vertical, flex:1 + basis 0 pode travar o botao em 48px e cortar um rotulo
   de 2 linhas ("Abre em horario diferente" em 320px, com fonte de sistema). */
.exc-acoes-col { flex-direction: column; }
.exc-acoes-col .btn { flex: none; }
.exc-btn { width: 100%; }
.exc-btn-largo { width: 100%; margin-top: 6px; }
.exc-link { background: none; border: none; color: var(--exc-azul-txt); font-size: 14px; font-weight: 600; min-height: 48px; cursor: pointer; text-decoration: underline; }
/* "1 toque grava" so funciona se o toque der sinal: sem isto o dono toca, a tela nao
   muda por 2-3s no 3G do patio, ele toca de novo e acha que travou.
   Estes sao os IRMAOS travados enquanto grava -- inativos de verdade. */
.exc-cartao button:disabled, .exc-folha button:disabled { opacity: .55; cursor: default; }
/* OCUPADO nao e DESABILITADO. "Salvando..." e a unica prova de que o toque pegou; com
   opacity .55 sobre branco o botao primario cai de 8,54:1 pra ~2,6:1 e fica ilegivel
   ao sol -- justo quando ele precisa ser lido. Por isso o botao tocado usa
   aria-disabled (que NAO tira o foco) em vez de disabled, e fica opaco 1.
   Vem depois da regra :disabled de proposito -- mesma especificidade, ganha a ultima. */
.exc-cartao button[data-ocupado], .exc-folha button[data-ocupado] { opacity: 1; cursor: progress; }
.exc-erro { color: var(--exc-alerta-txt); font-size: 13px; margin-top: 6px; }
.exc-erro:empty { display: none; }
.exc-vazio { color: var(--texto-sub); font-size: 14px; margin: 0 0 10px; }
.exc-esqueleto { height: 132px; background: linear-gradient(90deg, var(--bg-elevado) 25%, var(--bg-elevado-2) 50%, var(--bg-elevado) 75%); background-size: 400% 100%; animation: horus-exc-brilho 1.3s linear infinite; }
@keyframes horus-exc-brilho { to { background-position: -400% 0; } }
@media (prefers-reduced-motion: reduce) { .exc-esqueleto { animation: none; } }

/* Folha do horario especial: sobe de baixo no celular, vira caixa centrada no desktop. */
.exc-fundo { position: fixed; inset: 0; background: rgba(0,0,0,.6); display: flex; align-items: flex-end; justify-content: center; z-index: 60; }
/* Com interactive-widget=resizes-content, o teclado do Android encolhe o viewport e
   uma folha `fixed; bottom:0` de altura fixa SOBE inteira -- o topo (titulo e o X)
   vaza pra fora sem rolagem possivel. Medida: a folha da 514px em 390x844, e o
   teclado come ~380px. Solucao: coluna flex, o corpo rola por dentro e as acoes
   nunca saem da tela. */
.exc-folha {
  background: var(--bg-card); width: 100%; max-width: 480px;
  display: flex; flex-direction: column;
  max-height: 100vh;   /* fallback: navegador sem dvh descarta a linha de baixo e ficaria SEM teto nenhum */
  max-height: 100dvh;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  padding: 18px 16px 18px;
  padding: 18px 16px calc(18px + env(safe-area-inset-bottom, 0px));
}
/* Os tres filhos sao IRMAOS de proposito: so o corpo rola, por isso as acoes nunca
   precisam de sticky (sticky sem ancestral rolavel = relative, seria inerte).
   min-height:0 parece inutil e NAO e: sem ele o flex item nao encolhe abaixo do
   conteudo, o corpo para de rolar, a folha cresce e Salvar/Cancelar saem da tela.
   Se um dia .exc-folha-acoes for pra dentro do corpo, ai sim vira caso de sticky. */
.exc-folha-corpo { overflow-y: auto; flex: 1 1 auto; min-height: 0; }
.exc-folha-topo, .exc-folha-acoes { flex: none; }
@media (min-width: 561px) { .exc-fundo { align-items: center; } .exc-folha { border-radius: var(--radius-lg); } }
.exc-folha-topo { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; margin-bottom: 16px; font-size: 16px; }
.exc-fechar { background: none; border: none; font-size: 20px; color: var(--texto-sub); min-width: 48px; min-height: 48px; cursor: pointer; }
.exc-horas { display: flex; gap: 10px; }
.exc-horas .form-linha { flex: 1; }
.exc-contador { font-size: 12px; color: var(--exc-rotulo); text-align: right; }
.exc-horas-dica { font-size: 12.5px; color: var(--exc-rotulo); margin: -8px 0 14px; line-height: 1.4; }
.exc-contador-fim { font-weight: 800; color: var(--aviso); }
.exc-alerta { font-size: 12.5px; color: var(--aviso); line-height: 1.4; margin: 6px 0 0; }
/* Dica (o rascunho ainda nao da pra publicar) e' diferente de ERRO (ele tentou e nao
   deu): quem nao mexeu em nada nao errou nada. */
.exc-folha-dica { display: block; font-size: 12.5px; color: var(--exc-rotulo); margin-top: 6px; }
.exc-aviso-ja-marcado { font-size: 13px; color: var(--aviso); font-weight: 600; line-height: 1.4; margin-top: 2px; }
.exc-previa-folha { margin-top: 4px; }
.exc-folha-acoes { display: flex; gap: 10px; margin-top: 16px; }
/* Folga sob a barra de abas fixa: sem isso o ultimo cartao fica embaixo dela. */
#exc-bloco { padding-bottom: 24px; }
.exc-folha-acoes .btn { flex: 1; }
/* Regiao viva so pra leitor de tela -- nao ocupa espaco e nao pode usar display:none
   (o leitor ignoraria). */
.exc-sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* Container com tabindex="-1" nao ganha contorno sozinho: sem isto, quem enxerga nao
   ve pra onde o foco pulou depois de um erro.
   :focus, nao :focus-visible -- foco PROGRAMATICO num tabindex="-1" nao satisfaz a
   heuristica do :focus-visible (medido: outline-style ficava `none`), e este elemento
   so recebe foco por codigo, entao nao ha risco de piscar contorno em clique. */
.exc-erro:focus { outline: 2px solid var(--exc-alerta-txt); outline-offset: 3px; border-radius: var(--radius-sm); }
/* Cartao recebe foco por codigo depois de salvar (o botao que tinha o foco deixa de
   existir). :focus, nao :focus-visible -- foco programatico nao satisfaz a heuristica. */
.exc-cartao:focus { outline: 2px solid var(--azul); outline-offset: 2px; }


/* Fechamentos anteriores do caixa. A divergência é o motivo da tela existir: ela leva
   peso e cor própria, o resto é apoio. Achado do QA em 2026-09-08 (a observação do
   fechamento era gravada e nunca exibida por tela nenhuma).

   Cores medidas sobre #ffffff (o fundo do item), não sobre o --bg da página: a primeira
   versão usava `var(--fundo-card)`, token que NÃO EXISTE neste CSS (o certo é --bg-card),
   então o item ficava transparente e caía no #f4f5f7 da página — onde --alerta dá 4,25:1
   e reprova. Achado do ux-front em 2026-09-08.

   E o vermelho de "Faltou" é #B02525 (6,69:1), não o --alerta #D93636 do botão "Fechar
   caixa" logo acima: cinco selos na mesma cor do botão principal competem com ele por
   atenção — é subordinado a ele, não concorrente. */
.cx-hist-titulo { margin-top: 24px; margin-bottom: 10px; }
.cx-hist { display: flex; flex-direction: column; gap: 8px; list-style: none; margin: 0; padding: 0; }
.cx-hist-item {
  background: var(--bg-card); border: 1px solid var(--borda);
  border-radius: 10px; padding: 10px 12px;
}
.cx-hist-linha { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.cx-hist-dif { font-weight: 700; white-space: nowrap; font-variant-numeric: tabular-nums; }
.cx-hist-dif.ok { color: var(--texto-sub); font-weight: 600; }   /* 8,86:1 */
.cx-hist-dif.sobra { color: var(--aviso); }                      /* #b45309 = 5,02:1 */
.cx-hist-dif.falta { color: var(--alerta-escuro); }              /* 6,69:1 */
.cx-hist-sub { color: var(--texto-sub); font-size: 13px; margin-top: 2px; }
.cx-hist-obs {
  margin-top: 6px; padding-left: 10px; border-left: 3px solid var(--borda-forte);
  color: var(--texto); font-size: 14px;
}
.cx-hist-carregando, .cx-hist-erro { color: var(--texto-sub); margin-top: 20px; }
.cx-hist-erro .btn-link { margin-left: 8px; }

/* Confirmação de descarte DENTRO do modal — antes era um confirm() nativo, que é o
   diálogo que esta entrega existe pra tirar. Achado do QA em 2026-09-08.
   O fundo é hex explícito: a primeira versão usava `var(--fundo-aviso, ...)`, e esse
   token não existe — valia o fallback, o que ninguém tinha medido. #FEF6E7 com o texto
   --texto #1A1A1A dá 16,4:1. */
.pedir-descartar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap; margin-bottom: 12px; padding: 10px 12px;
  background: #FEF6E7; border: 1px solid var(--aviso); border-radius: 10px;
  color: var(--texto);
}
.pedir-descartar-acoes { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.pedir-descartar .btn { min-height: 44px; }

/* O eco pode quebrar em duas linhas com valor longo ("Vai lançar R$ 1.234.567,89.") e
   empurrar o layout 18px a cada tecla. Uma linha só, cortada com reticências. */
.campo-eco { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }


/* Caixinha da equipe no relatório (2026-09-20). A tabela de resumo continua tabela no
   celular — são números curtos e a comparação entre colunas é o ponto. Já a lista de cada
   gorjeta vira bloco empilhado: com rolagem lateral, "quem deu" e o valor ficariam fora da
   tela ao mesmo tempo, e é justamente o par que o Douglas quer ler junto. Desenho do
   ux-front. */
.rl-cx-sub { color: var(--texto-sub); font-size: 12px; margin-top: -6px; }
.rl-cx-nota { color: var(--texto-sub); font-size: 12px; margin-top: 8px; }
.rl-cx-vazio { color: var(--texto-sub); font-size: 14px; margin-top: 8px; line-height: 1.5; }
/* --texto-sub (#4A4A4A, 9:1), não --texto-sub2 (#838d9c, 3,2:1 — reprova em texto). */
.rl-cx-fraco { color: var(--texto-sub); }
.rl-cx-tabela .num, .rl-cx-itens .num { text-align: right; font-variant-numeric: tabular-nums; }
.rl-cx-tabela tfoot th, .rl-cx-tabela tfoot td { font-weight: 700; border-bottom: none; }
.rl-cx-liq { display: block; color: var(--texto-sub); font-size: 11px; font-weight: 400; }
.rl-cx-detalhe { margin-top: 12px; }
.rl-cx-detalhe summary { min-height: 44px; padding: 10px 0; }

@media (max-width: 599px) {
  /* Cada gorjeta vira um bloco. O rótulo vem de `data-rotulo`, que é texto fixo de
     cabeçalho — não é dado do cliente viajando escondido no HTML. */
  .rl-cx-itens thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .rl-cx-itens, .rl-cx-itens tbody, .rl-cx-itens tr, .rl-cx-itens td { display: block; width: 100%; }
  .rl-cx-itens tr { padding: 10px 0; border-bottom: 1px solid var(--borda); }
  .rl-cx-itens td { border: none; padding: 1px 0; white-space: normal; }
  .rl-cx-itens td.num { text-align: left; }
  .rl-cx-itens td[data-rotulo="Data"] { color: var(--texto-sub); font-size: 12px; }
  .rl-cx-itens td[data-rotulo="Quem deu"] { font-size: 15px; font-weight: 700; }
  .rl-cx-itens td[data-rotulo="Forma"] { color: var(--texto-sub); font-size: 13px; }
  .rl-cx-itens td[data-rotulo="Valor"] { font-size: 16px; font-weight: 700; margin-top: 2px; }
  .rl-cx-liq { display: inline; margin-left: 6px; }
}


/* Revisao do ux-front em 20/09/2026. */

/* 1: o liquido e a resposta do cartao — era a ultima celula da ultima coluna, do mesmo
   tamanho de tudo. A tabela abaixo passa a ser o detalhamento. */
.rl-cx-destaque { margin: 10px 0 14px; }
.rl-cx-valor { font-size: 28px; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }
.rl-cx-rotulo { color: var(--texto-sub); font-size: 13px; margin-top: 2px; }
.rl-cx-comp { color: var(--texto-sub); font-size: 13px; margin-top: 6px; font-variant-numeric: tabular-nums; }
@media (min-width: 600px) { .rl-cx-valor { font-size: 32px; } }

/* 3: a 1280px a linha percorria ~1030px ate o ultimo valor e o olho perdia a linha. */
.rl-cx-tabela { max-width: 760px; }
.rl-cx-itens { max-width: 900px; }

/* 4: coluna de dinheiro com algarismo proporcional nao alinha a virgula. */
.rl-cx-tabela td, .rl-cx-tabela th, .rl-cx-itens td, .rl-cx-itens th { font-variant-numeric: tabular-nums; }

/* 6: a linha do total tinha o mesmo peso das outras. */
.rl-cx-tabela tfoot th, .rl-cx-tabela tfoot td { font-weight: 700; border-bottom: none; border-top: 1px solid var(--borda); }

/* 8: placa e o dado, "(sem cadastro)" e ressalva. */
.rl-cx-ressalva { font-size: 12px; }

/* 9: o reset do app.css tira o outline padrao; sem isto o summary some pra quem navega
   por Tab. Medido com Tab, nao presumido. */
.rl-cx-detalhe summary:focus-visible { outline: 2px solid var(--azul); outline-offset: 2px; border-radius: 6px; }

@media (max-width: 480px) {
  /* Mesmo sem a coluna Taxa a tabela media 338px num cartao de ~328px uteis e ainda
     cortava "Líquido". O padding lateral de 10px x 8 celulas era o que sobrava: 6px
     devolve ~32px e a tabela passa a caber. Medido, nao estimado. */
  .rl-cx-tabela th, .rl-cx-tabela td { padding-left: 6px; padding-right: 6px; }
  .rl-cx-tabela { font-size: 12px; }

  /* 2: a coluna Taxa sai no celular — o total de taxa ja esta no destaque do topo, e era
     ela que empurrava "Líquido" (o numero que a equipe leva pra casa) pra fora da tela.
     O `.tabela-wrap` continua como rede de seguranca, mas deixa de ser o plano A:
     rolagem lateral sem pista visual quase ninguem descobre. */
  .rl-cx-taxa { display: none; }
}

/* Aviso de lavagem grátis no check-in (2026-09-27, pedido do Douglas: "preciso
   que avise de fato bem grande na hora que ler a placa ou colocar o telefone
   do cliente"). Antes era um <div> de 13px em cinza com um checkbox solto de
   ~20px — informação de dinheiro escondida no meio da tela.
   Verde #2E7D32 com texto branco = 5,13:1, o mesmo par já usado em
   .card-selo-pagamento; legível no sol do pátio. */
.gratis-aviso { background: #2E7D32; color: #fff; border-radius: var(--radius);
  margin: 12px 0; overflow: hidden; box-shadow: 0 2px 8px rgba(46,125,50,.25); }
.gratis-aviso-topo { display: flex; gap: 12px; padding: 16px 16px 10px; align-items: flex-start; }
.gratis-aviso-icone { font-size: 32px; line-height: 1; }
.gratis-aviso-titulo { font-size: 19px; font-weight: 800; line-height: 1.2; }
.gratis-aviso-sub { font-size: 14px; margin-top: 4px; line-height: 1.35; }

/* A linha INTEIRA marca/desmarca: o operador toca de luva molhada, e mirar num
   quadradinho de 20px com luva não funciona. 56px é o piso prático. */
.gratis-toggle { display: flex; align-items: center; gap: 12px; min-height: 56px;
  padding: 10px 16px; width: 100%; box-sizing: border-box; cursor: pointer;
  background: rgba(255,255,255,.14); color: #fff; margin: 0; }
.gratis-toggle input { width: 26px; height: 26px; flex: 0 0 26px; accent-color: #fff; margin: 0; }
.gratis-toggle:focus-within { outline: 2px solid #fff; outline-offset: -3px; }
.gratis-toggle-texto { font-size: 16px; font-weight: 700; }
.gratis-toggle-valor { font-size: 13px; font-weight: 400; }

/* Contador (7/10) continua discreto: é informação de acompanhamento, não de ação. */
.gratis-contador { font-size: 13px; color: var(--texto-sub); margin: 6px 0; }

/* Selo de cortesia na ficha do cliente e na lista. Reusa o par de cor que já
   passa contraste; o antigo (#25D366 sobre #25D36622) dava ~1,8:1. */
.selo-cortesia { display: inline-block; background: #2E7D32; color: #fff;
  font-size: 12px; font-weight: 700; padding: 3px 10px; border-radius: 999px; }

/* A pastilha selecionada do painel (.chip.ativo) usa --primario #F0A800 como
   TEXTO sobre um fundo do mesmo amarelo a 12% — medido: 1,0:1, ou seja,
   ilegível. É dívida antiga e aparece em várias telas; aqui eu corrijo só as
   desta tela pra não mexer no visual do painel inteiro sem revisão.
   #8A5A00 sobre o mesmo fundo passa de 4,5:1. */
#ct-prazos .chip.ativo { color: #8A5A00; border-color: #8A5A00; font-weight: 700; }

/* Os motivos são frases, não rótulos curtos: alinhadas à esquerda a lista fica
   varrível de cima pra baixo. `.btn` centraliza por text-align, então
   justify-content sozinho não resolve. */
#ct-motivos .btn { text-align: left; }
