/* Marca Arco-Íris: azul-marinho primário, arco-íris só como acento.
   Ver docs/design/branding.md. */
:root {
  --brand-navy: #1f3d72;
  --brand-navy-deep: #0f2b56;
  --ink: #1e2a3a;
  --muted: #63707f;
  --texto-desabilitado: #8a95a3;
  --surface: #ffffff;
  --surface-alt: #f4f6fa;
  --border: #d9e0ea;

  --rb-red: #fb5b43;
  --rb-amber: #fdae18;
  --rb-green: #21a877;
  --rb-blue: #1978c2;
  --rb-violet: #5c50d6;
  --bubble: #9cd2f5; /* dots do logo — ver docs/design/branding.md; reservado, ainda sem uso funcional na UI */

  /* --ok e --busy escurecidos (auditoria de acessibilidade, 2026-09-14): os
     tons antigos passavam em 4,5:1 só em branco puro (ou nem isso, no caso
     do --busy) — sobre o fundo das próprias pills que eles colorem (mais
     escuro que branco) ficavam abaixo do mínimo. --busy reaproveita o tom
     que `.pill-fat-parcial` já usava isolado; --ok é um verde mais escuro
     da mesma família, testado contra as duas pills de fundo mais claras do
     sistema (medido: ≥4,46:1 no pior caso do antigo valor, ≥5,17:1 nestes). */
  --ok: #12703a;
  --busy: #8a5a00;
  --danger: #c0392b;

  /* Tons de fundo claro pra pill/badge de status (auditoria de theming:
     existiam 2 verdes quase-iguais e 3 vermelhos quase-iguais espalhados
     pelo CSS, cada um digitado à mão em vez de reusar — deriva por cópia,
     não por decisão. Um só de cada agora. */
  --tint-ok: #e7f5ee;
  --tint-danger: #fdeae7;
  /* Fundo quase-branco com leve tom de marca, usado nos inputs "em foco de
     edição" da grade de preços/histórico — também repetido sem token. */
  --tint-input-leve: #fbfdff;
  /* Hover mais escuro dos dois contextos que já usavam esse escurecimento à
     mão (menu lateral sobre --brand-navy-deep; botões navy no corpo da
     página) — cada um com seu próprio tom, não force os dois a ficarem
     idênticos sem o dono ter pedido. */
  --hover-sidebar: #23406a;
  --hover-navy: #16305c;

  /* Tintas funcionais */
  --tint-busy: #fdf0dc;
  --tint-navy: #e6eefb;
  /* Bordas funcionais */
  --border-danger: #e6bcb6;
  --border-ok: #c9e9d6;
  /* Hover perigo */
  --hover-danger: #a5342a;
  /* Texto inativo */
  --traco-vazio: #c2cad6;

  /* Paleta "sobre-navy" da barra lateral — existia, mas nunca tinha nome
     (achado de theming): 6 tons picados à mão pra texto/ícone sobre
     --brand-navy-deep, sem token nenhum. Dois tons quase idênticos (a
     poucos pontos de diferença) usados em lugares diferentes por
     coincidência viraram um só, --on-navy-media. */
  --on-navy-forte: #eaf0f7;
  --on-navy-media: #c7d4e2;
  /* --on-navy-icone: exclusivamente decorativo (4.23:1, < 4.5:1 para texto).
     Para texto informativo sobre navy, usar --on-navy-media (7.06:1). */
  --on-navy-icone: #8fa6bd;
  --on-navy-borda: #33507a;

  /* Escala de espaçamento — 8 degraus nomeados pelos valores mais
     FREQUENTES de padding/margin/gap do arquivo inteiro (mesmo método da
     escala de texto: âncora no que já dominava, não um grid "limpo"
     imposto). Só declarações de UM valor foram trocadas por token
     (`padding: var(--space-sm);`) — atalhos com vários valores (`padding: 10px 14px;`)
     ficaram como estavam, pra não arriscar um remapeamento errado num
     valor que hoje só existe misturado a outro na mesma regra. Valores
     "ímpares" que também se repetem bastante (7px, 9px, 5px, 3px, 14px,
     11px) ficaram de fora de propósito — não há vizinho óbvio pra eles no
     grid sem mudar a densidade visual de algo que pode ter sido escolhido
     à mão por caber certo ali. */
  --space-3xs: 2px;
  --space-2xs: 4px;
  --space-xs: 6px;
  --space-sm: 8px;
  --space-md: 10px;
  --space-lg: 12px;
  --space-xl: 16px;
  --space-2xl: 20px;

  --sidebar-w: 292px;

  /* Escala de cantos — 4 passos cobrem o sistema inteiro (controle pequeno →
     painel/modal); pílula é caso à parte (999px), não faz parte da escala. */
  --radius-sm: 6px;
  --radius-md: 8px;
  --radius-lg: 12px;

  /* Profundidade real: cartão/painel flutua sobre --surface-alt com sombra
     suave (offset + blur, nunca halo sem deslocamento); modal já usava
     algo parecido — aqui isso vira token pra toda "camada 2" do app. */
  --shadow-card: 0 1px 2px rgba(15, 43, 86, .05), 0 4px 14px rgba(15, 43, 86, .06);
  /* Camada 3 — modal e toast já usavam o mesmo valor, sem compartilhar
     variável nenhuma; um só nome pros dois agora. */
  --shadow-modal: 0 4px 12px rgba(0, 0, 0, 0.08);
  /* Anel de foco — mesmo valor já usado na regra global de :focus abaixo;
     nomeado aqui só pra documentar, não porque outro lugar reusa. */
  --shadow-focus: 0 0 0 3px rgba(31, 61, 114, 0.35);
  /* Dropdowns flutuantes (⚙ Configurações e combobox de seleção múltipla) —
     valores parecidos mas não iguais; nomeados em vez de forçar os dois a
     ficarem idênticos sem o dono ter pedido isso. */
  --shadow-dropdown-forte: 0 8px 28px rgba(15, 43, 86, .18);
  --shadow-dropdown: 0 8px 24px rgba(15, 43, 86, .15);
  /* Gaveta do menu no celular. */
  --shadow-drawer: 0 0 40px rgba(0, 0, 0, .35);

  /* Tipografia por PAPEL — seção "Tipografia" de docs/design/ui.md. Um
     token por papel, não por tamanho: elemento novo escolhe o papel que
     cumpre, nunca um valor em rem/px. */
  --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --fs-caixa-alta: .75rem;    /* 12px — texto em caixa alta (selo, cabeçalho de tabela, rótulo de KPI), chip e contador */
  --fs-apoio: .8125rem;       /* 13px — rótulo de campo, ajuda, legenda, data, rodapé */
  --fs-corpo: .875rem;        /* 14px — todo texto de leitura: célula, botão, menu, aviso */
  --fs-subtitulo: 1rem;       /* 16px — título de card, modal e seção */
  --fs-titulo: 1.25rem;       /* 20px — título da tela e da Ficha */
  --fs-destaque: 2.25rem;     /* 36px — número-destaque do Dashboard */
  /* Valor digitado num controle (input/select/textarea). Igual ao corpo,
     mas 16px em tela de toque (fim do arquivo): abaixo disso o Safari do
     iPhone/iPad dá zoom na página ao tocar no campo. */
  --fs-controle: var(--fs-corpo);
  /* Altura de botão e campo — seção "Componentes" de docs/design/ui.md.
     Padrão: formulário, modal, filtro, barra de ações. Compacta: dentro de
     linha de tabela/lista e na paginação. As duas viram 44px em tela de
     toque (fim do arquivo) — o mínimo de alvo de toque. */
  --altura-controle: 40px;
  --altura-compacta: 32px;
  --ls-caixa-alta: .04em;     /* espaçamento único de todo texto em caixa alta */

  font-family: var(--font-sans);
  /* 100% = o tamanho que a pessoa escolheu no navegador (16px por padrão);
     os tokens em rem acompanham quem aumentou a fonte. */
  font-size: 100%;
  color: var(--ink);
}

* { box-sizing: border-box; }
body { margin: 0; background: var(--surface-alt); font-size: var(--fs-corpo); line-height: 1.45; }
h1, h2, h3, h4, h5 { line-height: 1.2; }
button { font: inherit; cursor: pointer; }
/* Todo controle: mesma família, tamanho e peso — nunca herda do rótulo em
   volta nem cai na fonte padrão do navegador (Arial/monospace). Regra de
   componente mexe em borda/espaço, não em fonte. */
input, select, textarea {
  font-family: inherit;
  font-size: var(--fs-controle);
  font-weight: 400;
  line-height: 1.3;
}
/* Aparência de todo campo (texto, número, data, hora, lista, área de texto).
   :where() = especificidade zero: a regra do componente só diz largura e
   layout, e o que for de verdade diferente (destaque, somente leitura). */
:where(input:not([type="checkbox"], [type="radio"], [type="file"], [type="range"], [type="color"]), select, textarea, .moeda-campo, .multi-select > summary) {
  box-sizing: border-box;
  min-height: var(--altura-controle);
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
}
:where(textarea) { padding: 10px 12px; }
/* Compacto: campo dentro de linha de tabela/lista e na paginação. */
:is(table.grid td, .tabela-rodape, .hist-edit, .item-conta-linha, .ficha-campo, .ficha-retida-linha)
  :is(input:not([type="checkbox"], [type="radio"], .moeda-input), select),
:is(table.grid td, .hist-edit, .item-conta-linha) .moeda-campo {
  min-height: var(--altura-compacta);
  padding: 0 8px;
}
input[type="checkbox"], input[type="radio"] {
  accent-color: var(--brand-navy);
  width: 18px;
  height: 18px;
  margin: 0;
  flex: 0 0 auto;
}
td.num, th.num { font-variant-numeric: tabular-nums; }
b, strong { font-weight: 600; }
[hidden] { display: none !important; }

/* Foco consistente em todo o app — antes só existia (fraco, quase
   invisível) para os campos da Ficha Única e dos modais; o resto caía no
   contorno azul padrão do navegador. Um só anel, forte o bastante pra
   navegação por teclado, em todo campo de texto/select/textarea. */
input:not([type="checkbox"]):not([type="radio"]):not(.moeda-input):focus,
select:focus,
textarea:focus,
.moeda-campo:focus-within {
  outline: none;
  border-color: var(--brand-navy);
  box-shadow: var(--shadow-focus);
}

.rainbow {
  height: 4px;
  background: linear-gradient(
    90deg,
    var(--rb-red) 0 20%,
    var(--rb-amber) 20% 40%,
    var(--rb-green) 40% 60%,
    var(--rb-blue) 60% 80%,
    var(--rb-violet) 80% 100%
  );
}

/* --- gate (abertura) --- */
.gate {
  max-width: 466px; /* logo de 400px + 32px de respiro e 1px de borda de cada lado */
  margin: 12vh auto;
  padding: 32px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  text-align: center;
}
.gate-logo { width: 400px; max-width: 100%; height: auto; margin: 0 auto 12px; }
.gate p { color: var(--muted); margin: 0 0 20px; }
.gate .btn { width: 100%; margin: 8px 0; }

.login-form { display: flex; flex-direction: column; gap: 14px; text-align: left; }
.login-form .gate-logo { margin-bottom: var(--space-2xs); }
.login-form .campo { display: flex; flex-direction: column; gap: var(--space-2xs); font-size: var(--fs-apoio); font-weight: 600; color: var(--muted); }

.login-form .modal-actions { margin-top: var(--space-2xs); }
.login-form .btn { width: 100%; }

/* --- layout --- */
.layout {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  min-height: calc(100vh - 4px);
}

.sidebar {
  background: var(--brand-navy-deep);
  color: var(--on-navy-forte);
  padding: 16px 12px;
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
  min-height: 0;
  /* Vale no modo gaveta (position: fixed com top/bottom): se a lista não
     couber na altura da tela, rola aqui dentro. No desktop a coluna do grid
     cresce com o conteúdo e quem rola é a página — que é o esperado lá. */
  overflow-y: auto;
}
.brand { padding: 4px 2px 14px; text-align: center; position: relative; }
.brand img { width: 253px; max-width: 100%; height: auto; }
.menu-fechar {
  display: none;
  align-items: center;
  justify-content: center;
  position: absolute;
  top: 0;
  right: 0;
  width: 36px;
  height: 36px;
  border: 0;
  border-radius: var(--radius-md);
  background: rgba(255, 255, 255, .1);
  color: var(--on-navy-forte);
  cursor: pointer;
}
.menu-overlay { display: none; }

.menu-toolbar { display: flex; gap: var(--space-xs); padding: 0 4px; }
.menu-toolbar button {
  flex: 1;
  min-height: var(--altura-compacta);
  padding: 0 8px;
  font-size: var(--fs-apoio);
  background: transparent;
  color: var(--on-navy-media);
  border: 1px solid var(--on-navy-borda);
  border-radius: var(--radius-sm);
}
.menu-toolbar button:hover { background: var(--hover-sidebar); }

/* `min-height: 0` é o que faz o `overflow-y` valer: sem ele o padrão
   `min-height: auto` do flex impede o item de encolher, a lista cresce e
   estoura a sidebar em vez de rolar. */
.menu { display: flex; flex-direction: column; gap: var(--space-3xs); overflow-y: auto; min-height: 0; }
.brand { flex: 0 0 auto; }
.menu-toolbar { flex: 0 0 auto; }
.menu-parent, .menu summary {
  list-style: none;
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: 10px 12px;
  border-radius: var(--radius-md);
  color: var(--on-navy-forte);
  font-weight: 600;
  background: transparent;
  border: 0;
  width: 100%;
  text-align: left;
}
.menu-parent svg, .menu summary svg { flex: 0 0 auto; color: var(--on-navy-icone); }
.menu summary::-webkit-details-marker { display: none; }
/* Sem seta fixa: o cabeçalho inteiro já é o clique (é a única razão de a
   seta existir — nunca foi ela o alvo). Isso deixa o ícone do grupo na
   mesma régua do ícone dos filhos, em vez de um `1em` de seta empurrando só
   o pai pra direita. Um indicador discreto aparece só no hover/foco, sem
   ocupar espaço em repouso — pista pra quem interage, não decoração pra
   quem só olha. */
.menu summary { position: relative; padding-right: 26px; cursor: pointer; }
.menu summary::after {
  content: "▸";
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--on-navy-icone);
  opacity: 0;
  transition: opacity .12s;
}
.menu summary:hover::after, .menu summary:focus-visible::after { opacity: 1; }
.menu details[open] > summary::after { transform: translateY(-50%) rotate(90deg); }
.menu-parent:hover, .menu summary:hover { background: var(--hover-sidebar); }
/* 12px a mais que o padding do pai (12px) — um recuo igual pra todo filho,
   não um efeito colateral de largura de caractere como a seta antiga. */
.menu ul { list-style: none; margin: 2px 0 6px; padding: 0 0 0 12px; }
.menu li button {
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--space-md);
  text-align: left;
  padding: 8px 12px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--on-navy-media);
  font-size: var(--fs-corpo);
}
.menu li button svg { flex: 0 0 auto; color: var(--on-navy-icone); }
.menu li button:hover { background: var(--hover-sidebar); color: var(--surface); }
.menu li button.active { background: var(--rb-blue); color: var(--surface); }
.menu li button.active svg { color: var(--surface); }

/* --- área principal --- */
.main { display: flex; flex-direction: column; min-width: 0; }
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-xl);
  padding: 14px 24px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.topbar-left { display: flex; align-items: center; gap: var(--space-lg); min-width: 0; }
.menu-toggle {
  display: none;
  font-size: 1.2rem;
  line-height: 1;
  padding: 6px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
  color: var(--brand-navy);
}
.screen-title { margin: 0; font-size: var(--fs-titulo); letter-spacing: -.01em; color: var(--brand-navy); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.topbar-right { display: flex; align-items: center; gap: var(--space-lg); flex: 0 1 auto; flex-wrap: wrap; justify-content: flex-end; }
.btn-backup {
  display: inline-flex;
  align-items: center;
  box-sizing: border-box;
  min-height: var(--altura-controle);
  padding: 0 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
  color: var(--brand-navy);
  font-size: var(--fs-corpo);
  white-space: nowrap;
}
.btn-backup:hover { background: var(--surface-alt); }
button.btn-backup, .btn-backup { cursor: pointer; }

.topo-usuario {
  font-size: var(--fs-corpo);
  color: var(--brand-navy);
  font-weight: 600;
  white-space: nowrap;
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* menu da engrenagem (⚙) */
.config-drop { position: relative; }
.config-drop > summary {
  list-style: none;
  display: inline-flex;
  align-items: center;
  padding: 0 10px;
  font-size: 1rem; /* glifo ⚙, não texto */
  user-select: none;
}
.config-drop > summary::-webkit-details-marker { display: none; }
.config-drop[open] > summary { background: var(--surface-alt); }
.config-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  z-index: 25;
  min-width: 190px;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: var(--shadow-dropdown-forte);
  overflow: hidden;
}
.config-menu button {
  display: flex;
  align-items: center;
  gap: 9px;
  text-align: left;
  padding: 10px 14px;
  border: 0;
  background: none;
  font: inherit;
  color: var(--brand-navy);
  cursor: pointer;
}
.config-menu button svg { flex: 0 0 auto; color: var(--muted); }
.config-menu button:hover { background: var(--surface-alt); }
.config-sep { margin: 0; border: 0; border-top: 1px solid var(--border); }
.config-versao {
  padding: 7px 14px 9px;
  font-size: var(--fs-apoio);
  user-select: text;
}

.content {
  padding: 24px;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--space-2xl);
  /* Era um teto fixo de 1600px — resolvia o problema antigo (lista
     crescendo sem limite, tabela sobrando espaço morto do lado dela dentro
     do próprio card), mas num monitor bem largo (2560px+) o teto virou o
     problema oposto: sobrava uma faixa enorme e vazia dos DOIS lados do
     card, fora dele (achado do dono, 2026-09-15, telas reais). O motivo do
     teto original não se aplica mais aqui — cada tabela/card já preenche
     100% do espaço que o pai dá (`table.grid`/`.tela-lista` testados nesta
     sessão, sem sobra interna), e o caso do mestre-detalhe de Lançar OS
     (lista+ficha) tem sua própria trava (`.tela-lista` a 980px dentro de
     `.lancar-os-layout`, ficha redimensionável) — não depende mais deste
     teto. 95vw só entra como rede de segurança pra telas realmente
     absurdas (>5800px de largura); em qualquer monitor real, o card cresce
     pra usar o espaço que tem. */
  max-width: 95vw;
  margin: 0 auto;
  width: 100%;
}
.stub {
  padding: 24px;
  background: var(--surface);
  border: 1px dashed var(--border);
  border-radius: var(--radius-lg);
}
.muted { color: var(--muted); }

/* --- cards, formulários --- */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  padding: var(--space-2xl);
  flex: 1 1 480px;
  min-width: 0;
}
/* Subtítulo (ui.md, Tipografia): título de card, modal e seção — tamanho e cor
   num lugar só; cada regra abaixo só cuida do próprio espaço */
.card h2,
.form-inline.sub h3,
.modal-head h2,
.fatura-head h3,
.fatura-compensacao > h3,
.backlog-secao-titulo { font-size: var(--fs-subtitulo); color: var(--brand-navy); }
.card h2 { margin: 0 0 14px; }

.form-inline { flex: 0 1 420px; }
.form-inline.wide { flex-basis: 480px; }
.form-inline label { display: block; font-size: var(--fs-apoio); font-weight: 600; color: var(--ink); margin-bottom: var(--space-lg); }
.form-inline label small { display: block; margin-top: var(--space-2xs); font-size: var(--fs-apoio); font-weight: 400; }
.form-inline input[type="text"],
.form-inline input[type="date"],
.form-inline input[type="time"],
.form-inline input[type="number"],
.form-inline select,
/* Campo "digite X para confirmar" (ex.: apagar todo o histórico de preços) —
   estava sem classe nenhuma reconhecida (`input-comum` não existe em lugar
   nenhum do sistema), então caía no estilo cru do navegador. Junta na regra
   compartilhada em vez de duplicar (CLAUDE.md: mudança de padrão se faz no
   lugar compartilhado, nunca tela a tela). */
.confirmacao-digitacao input[type="text"] {
  display: block;
  width: 100%;
  margin-top: var(--space-2xs);
}
.form-inline fieldset {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  margin: 0 0 12px;
  padding: 8px 12px 12px;
}
.form-inline legend { font-size: var(--fs-apoio); font-weight: 600; color: var(--muted); padding: 0 4px; }
/* Texto da opção, não rótulo: corpo e peso normal mesmo dentro de um campo. */
.check { display: flex; align-items: center; gap: 5px; margin: 6px 0; font-size: var(--fs-corpo); font-weight: 400; }
.check input[type="checkbox"] { margin: 0; }
.check.inline { display: inline-flex; margin: 2px 7px 2px 0; }
.check.disabled { color: var(--muted); }

.lista-select { display: flex; gap: var(--space-xs); margin-top: var(--space-2xs); align-items: stretch; }
.lista-select select {
  flex: 1;
  min-width: 0; /* encolhe no celular em vez de empurrar o "Gerenciar" pra fora */
  margin-top: 0;
}
.lista-select button { flex: 0 0 auto; white-space: nowrap; }

.form-inline .sufixo { display: flex; align-items: center; gap: var(--space-xs); margin-top: var(--space-xs); font-size: var(--fs-corpo); flex-wrap: wrap; }
.form-inline .sufixo input { margin-top: 0; width: 72px; }
.form-inline .sufixo.tempo-ref select { margin-top: 0; width: auto; }

/* flex-shrink: 0 — dentro de um painel em coluna com altura limitada (Ficha
   da OS), o min-height deixava o erro encolher para uma linha e o texto
   vazava por cima dos botões */
.form-erro { color: var(--danger); font-size: var(--fs-corpo); margin: 0 0 10px; min-height: 1.1em; flex-shrink: 0; }
/* Aviso: caixa colorida de mensagem, um par texto+fundo por status (seção
   "Cores"). Uma classe só para todo aviso — acabou form-aviso,
   veredito-atraso, aviso-ok e ficha-status-nota. */
.aviso { margin: 0 0 10px; padding: 10px 14px; border-radius: var(--radius-md); font-size: var(--fs-corpo); }
.aviso-sucesso { background: var(--tint-ok); color: var(--ok); }
.aviso-atencao { background: var(--tint-busy); color: var(--busy); }
.aviso-erro { background: var(--tint-danger); color: var(--danger); }
.aviso-info { background: var(--tint-navy); color: var(--brand-navy); }

.campo-senha { position: relative; display: block; }
.campo-senha input { width: 100%; padding-right: 40px; box-sizing: border-box; }
/* seletor forte o bastante pra vencer `.gate button` na tela de login */
.campo-senha .senha-olho {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  width: auto;
  margin: 0;
  display: flex;
  align-items: center;
  padding: var(--space-xs);
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--muted);
  cursor: pointer;
}
.campo-senha .senha-olho:hover { color: var(--brand-navy); background: none; }
.form-actions { display: flex; gap: var(--space-sm); flex-wrap: wrap; }
/* Distância da ação destrutiva em relação às demais na coluna de ações de
   tabela — reduz o risco de toque errado numa ação irreversível (Excluir),
   sem precisar de um menu à parte. Numa barra de ações de modal, descola
   do Salvar/Emitir. */
table.grid td.acoes > .btn-perigo { margin-left: var(--space-sm); }
.modal-actions > .btn-perigo { margin-left: auto; }

.confirmacao > p { margin: 0 0 4px; color: var(--ink); }

/* --- Matriz de preços (pop-up) --- */
.matriz-precos > p { margin: 6px 0 12px; font-size: var(--fs-corpo); }
.matriz-precos .table-wrap { max-height: 56vh; overflow: auto; }
.matriz-precos table.grid th { position: sticky; top: 0; z-index: 2; background: var(--surface-alt); }
.matriz-barra { display: flex; align-items: flex-end; gap: var(--space-xl); flex-wrap: wrap; }
.matriz-barra-fim { margin-left: auto; }

/* --- multi-select (combobox de checkboxes) --- */
.filtro > .multi-select { align-self: stretch; }
/* Fica dentro do rótulo do filtro: volta ao corpo/peso normal. O resumo
   fechado é o "valor" do controle, no mesmo tamanho dos selects ao lado. */
.multi-select { position: relative; font-size: var(--fs-corpo); font-weight: 400; }
.multi-select > summary {
  list-style: none; cursor: pointer; user-select: none;
  font-size: var(--fs-controle); color: var(--ink);
  display: flex; align-items: center; gap: var(--space-sm); min-width: 150px; max-width: 230px;
}
.multi-select > summary::-webkit-details-marker { display: none; }
.multi-select > summary::after { content: "▾"; margin-left: auto; color: var(--muted); flex: 0 0 auto; }
.multi-select[open] > summary::after { content: "▴"; }
/* O resumo agora mostra o(s) nome(s) selecionado(s), não só a contagem —
   pode crescer mais que "2 de 3"; trunca em vez de esticar a caixa do
   filtro (min-width:0 é o que deixa um item flex encolher abaixo do
   próprio conteúdo). */
.multi-select .ms-resumo { color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
/* `.ms-lista`, não `.multi-select .ms-lista`: ao abrir, o combobox move a
   lista pra fora do `.multi-select` (portal em `<body>`, ver
   `_multi-select.ts`/`registrarPortalFlutuante`) pra escapar do `overflow`
   de um modal — um seletor de descendente aqui perderia essa caixa (sem
   fundo, borda, sombra, `max-height`/rolagem) assim que ela saísse do DOM do
   combobox. z-index 60, acima do `.modal-overlay` (50): flutuando com um
   modal aberto atrás, senão o overlay translúcido ficava por cima da lista e
   bloqueava o clique nos checkboxes (achado do dono, 2026-09-24). */
.ms-lista {
  position: absolute; z-index: 60; margin-top: var(--space-2xs); min-width: 200px;
  max-height: 260px; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md);
  box-shadow: var(--shadow-dropdown); padding: var(--space-xs);
}
/* linha de "Marcar todos / Nenhum" e cada item — compartilhados pelos dois
   formatos de seleção (combobox e painel) */
.ms-acoes { display: flex; gap: var(--space-lg); padding: 4px 4px 6px; border-bottom: 1px solid var(--border); margin-bottom: var(--space-2xs); }
.ms-item { display: flex; align-items: center; gap: var(--space-xs); padding: 5px 4px; font-size: var(--fs-corpo); cursor: pointer; }
.ms-item:hover { background: var(--surface-alt); border-radius: 4px; }

/* --- painel de seleção múltipla, sempre visível (ex.: abrir faturas em massa) --- */
.selecao-campo .selecao-campo-cab {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-sm);
  margin-bottom: var(--space-2xs);
}
.selecao-campo .selecao-campo-cab > span:first-child { font-size: var(--fs-apoio); font-weight: 600; color: var(--ink); }
.selecao-contador { font-size: var(--fs-apoio); color: var(--muted); white-space: nowrap; }
.selecao-painel {
  border: 1px solid var(--border); border-radius: var(--radius-md); overflow: hidden;
  background: var(--surface);
}
.selecao-busca-linha { padding: var(--space-sm); border-bottom: 1px solid var(--surface-alt); }
.selecao-busca { width: 100%; margin: 0; color: var(--ink); }
.selecao-painel .ms-acoes { padding: 8px 10px 6px; margin: 0; border-color: var(--surface-alt); }
.selecao-painel .ms-item input { accent-color: var(--brand-navy); }
.selecao-lista { max-height: 184px; overflow-y: auto; padding: var(--space-2xs); }
.selecao-vazia { margin: 8px 6px; }

.export-detalhe[hidden] { display: none; }

/* --- Importação: prévia em matriz --- */
.import-previa .table-wrap { max-height: 40vh; overflow: auto; margin-top: var(--space-xs); }
.import-previa th.import-col-off,
.import-previa td.import-col-off { color: var(--muted); background: repeating-linear-gradient(45deg, transparent, transparent 6px, rgba(0,0,0,.03) 6px, rgba(0,0,0,.03) 12px); }
.import-erro td { color: var(--danger); }

/* --- Botões: criados só por botao() em ui.ts (seção "Componentes" de
   docs/design/ui.md). A aparência vem da variante, nunca de type="submit".
   Hover dos de contorno = navy cheio (mesma família do primário). A única
   cor fora do navy é o vermelho de --danger, e só nas variantes de perigo. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  box-sizing: border-box;
  min-height: var(--altura-controle);
  padding: 0 16px;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  font-size: var(--fs-corpo);
  line-height: 1.2;
  white-space: nowrap; /* rótulo nunca quebra; quem quebra é a barra (flex-wrap) */
}
.btn svg { flex: 0 0 auto; }
.btn:disabled { opacity: .45; cursor: default; }
.btn-primario { background: var(--brand-navy); border-color: var(--brand-navy); color: var(--surface); }
.btn-primario:hover:not(:disabled) { background: var(--hover-navy); border-color: var(--hover-navy); }
.btn-secundario { background: var(--surface); border-color: var(--brand-navy); color: var(--brand-navy); }
.btn-secundario:hover:not(:disabled) { background: var(--brand-navy); color: var(--surface); }
/* Ação destrutiva (Excluir, Reabrir, Apagar). */
.btn-perigo { background: var(--surface); border-color: var(--border-danger); color: var(--danger); }
.btn-perigo:hover:not(:disabled) { background: var(--tint-danger); border-color: var(--danger); }
/* Só o botão que confirma uma ação destrutiva (abrirConfirmacao). */
.btn-perigo-solido { background: var(--danger); border-color: var(--danger); color: var(--surface); }
.btn-perigo-solido:hover:not(:disabled) { background: var(--hover-danger); border-color: var(--hover-danger); }
/* Compacto: pedido na criação ou, sozinho, nos mesmos contextos em que o
   campo fica compacto (regra de campo compacto, mais acima) — botão e campo
   lado a lado têm sempre a mesma altura (ex.: o "Gerenciar" ao lado do
   motivo de retenção). */
.btn-compacto,
:is(table.grid td, .tabela-rodape, .tabela-pager, .hist-edit, .item-conta-linha, .ficha-campo, .ficha-retida-linha)
  .btn:not(.btn-link, .btn-registro) {
  min-height: var(--altura-compacta);
  padding: 0 10px;
}
/* Link de ação (Histórico, Marcar Todos) e link de registro (nº da OS que
   abre a ficha): texto sublinhado, sem caixa. */
.btn-link,
.btn-registro {
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--brand-navy);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.btn-link { font-size: var(--fs-apoio); }
.btn-link:hover { color: var(--hover-navy); }
.btn-registro { font-weight: 600; }
.btn-registro.ativa { color: var(--ink); text-decoration: none; }

/* --- campo rotulado numa linha horizontal (rótulo em cima + controle) ---
   É o padrão do sistema para filtro (`.filtro`, na barra) e para campo dentro
   de uma linha de inclusão (`.campo-inline`, no `.lista-add`). Mesma regra
   para os dois: um controle nunca fica sem rótulo numa linha dessas. */
.filtro,
.campo-inline {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  font-size: var(--fs-apoio);
  font-weight: 600;
  color: var(--muted);
}
.filtro > select,
.filtro > input,
.campo-inline > select,
.campo-inline > input {
  color: var(--ink);
  margin: 0;
}
/* data não estica: a caixa tem largura própria e igual em toda tela */
.filtro > input[type="date"],
.campo-inline > input[type="date"] { width: 10.5em; }

/* --- barra de filtros + botão novo --- */
.barra-filtros {
  flex-basis: 100%;
  display: flex;
  align-items: flex-end;
  gap: 14px;
  flex-wrap: wrap;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  padding: 12px 16px;
}
.barra-filtros-fim { margin-left: auto; display: flex; align-items: flex-end; gap: var(--space-sm); flex-wrap: wrap; }

/* lista de cadastro: barra de filtros + busca + tabela no mesmo card */
.tela-lista {
  flex-basis: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  padding: var(--space-xl);
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
}
.tela-lista > * { flex: 0 0 auto; }
.tela-lista .barra-filtros {
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  padding: 0;
}
.tela-lista .lista-vazia { margin: 0; }

.busca-lista { display: flex; }
.busca-lista input {
  flex: 1 1 auto;
  max-width: 360px;
  color: var(--ink);
}
/* --- campos de horário (prazo previsto manual da OS) --- */
.prazo-manual-campos { display: flex; align-items: center; gap: var(--space-xs); flex-wrap: wrap; font-size: var(--fs-corpo); margin-top: var(--space-xs); }
.prazo-manual-campos input,
.prazo-manual-campos select {
  margin: 0;
}
.prazo-manual-campos input[type="number"] { width: 56px; }
.prazo-manual-campos input[type="time"] { width: auto; }
.prazo-manual-campos select { width: auto; }

.form-inline.sub { flex-basis: 100%; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border); }
.form-inline.sub h3 { margin: 0 0 10px; }

/* --- tabelas --- */
th {
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--ls-caixa-alta);
}
/* Coluna ordenável põe o texto num <button>, e o navegador zera o
   text-transform de botão — sem isto o cabeçalho ordenável saía em frase
   normal, ao lado dos outros em caixa alta. */
th button { text-transform: inherit; letter-spacing: inherit; }

/* Unidade de medida é minúscula mesmo dentro de caixa alta: "PESO (kg)". */
.unidade { text-transform: none; }
.tabela-paginada { flex: 0 0 100%; min-width: 0; }
.tabela-paginada .table-wrap { flex: 0 0 auto; width: 100%; }
.tabela-rodape {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-lg);
  flex-wrap: wrap;
  margin-top: var(--space-md);
  font-size: var(--fs-corpo);
}

.tabela-pager { display: flex; align-items: center; gap: var(--space-sm); }
.table-wrap { flex: 1 1 480px; min-width: 0; overflow-x: auto; }
table.grid {
  border-collapse: collapse;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  width: 100%;
  min-width: 480px;
}
table.grid th, table.grid td {
  text-align: left;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-corpo);
  white-space: nowrap;
}
table.grid th {
  background: var(--surface-alt);
  color: var(--muted);
  font-size: var(--fs-caixa-alta);
  text-transform: uppercase;
  letter-spacing: var(--ls-caixa-alta);
}
table.grid tr:last-child td { border-bottom: 0; }
table.grid tr.inativo td { color: var(--muted); }
/* Linha de total (tfoot) — parte da própria tabela, não uma legenda solta
   abaixo dela. Borda mais forte separa das linhas normais; fundo e negrito
   fazem o mesmo papel de destaque que o cabeçalho já usa, sem inventar cor
   nova. */
table.grid tfoot td {
  background: var(--surface-alt);
  color: var(--ink);
  font-weight: 600;
  border-top: 2px solid var(--border);
  font-variant-numeric: tabular-nums;
}
/* Achado de colorize: "Ativo"/"Inativo" em texto puro em 5 telas de
   cadastro, sem cor própria na célula (só a linha inteira meio-apagada
   quando inativo, regra acima). --ok já é a cor de "estado bom" em todo o
   sistema (pill-situacao-fechado, hist-preco-atual); --muted é literalmente
   a MESMA cor que tr.inativo já usa — nenhuma cor nova em nenhum dos dois. */
.estado-ativo { color: var(--ok); font-weight: 600; }
.estado-inativo { color: var(--muted); }
/* A célula de ações continua CÉLULA (nada de display:flex num <td>: ele
   deixa de ser table-cell, perde a altura da linha e a borda de baixo sai
   desalinhada das vizinhas). Os botões são inline-flex: alinha à direita no
   fluxo normal, sem quebrar linha, com o respiro na margem. */
table.grid td.acoes {
  overflow: visible;
  white-space: nowrap;
  text-align: right;
}
table.grid td.acoes > * { vertical-align: middle; }
table.grid td.acoes > * + * { margin-left: var(--space-xs); }
table.grid-fixa td.acoes { overflow: visible; }
/* A coluna de ações é uma coluna comum: numa tabela larga ela rola junto com o
   resto (não fica grudada à direita). Vale em qualquer resolução. */

/* ordenação + redimensionamento */
table.grid-fixa { table-layout: fixed; }
table.grid-fixa td {
  overflow: hidden;
  text-overflow: ellipsis;
}
table.grid th { position: relative; }
th .th-rotulo { display: inline-block; }
/* Coluna ordenável é <button> de verdade agora (teclado) — reseta a
   aparência nativa de botão pra ficar idêntica ao <span> de antes. */
button.th-rotulo {
  border: 0;
  background: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  text-align: left;
}
th.ord .th-rotulo { cursor: pointer; user-select: none; }
th.ord .th-rotulo:hover, th.ord .th-rotulo:focus-visible { color: var(--brand-navy); }
th.ord .th-rotulo:focus-visible { outline: none; }
th .th-seta { font-size: .8em; color: var(--brand-navy); }
th .th-resize {
  position: absolute;
  top: 0;
  right: 0;
  width: 9px;
  height: 100%;
  cursor: col-resize;
}
th .th-resize:hover, th .th-resize:focus-visible { box-shadow: inset -3px 0 0 var(--rb-blue); }
th .th-resize:focus-visible { outline: none; }
table.grid td input[type="text"] { width: 120px; }
/* Célula, não flex (mesmo motivo de td.acoes): campo e histórico lado a lado no fluxo. */
table.grid td.preco-cliente { white-space: nowrap; }
table.grid td.preco-cliente > * { vertical-align: middle; }
table.grid td.preco-cliente > * + * { margin-left: var(--space-xs); }
table.grid td.preco-cliente input { width: 96px; border-color: var(--brand-navy); background: var(--tint-input-leve); text-align: right; }

/* Input padronizado para as matrizes (Nova OS style) */
table.grid td input[type="number"] {
  width: 80px;
  margin: 0;
  color: var(--ink);
  text-align: right;
  font-variant-numeric: tabular-nums;
  transition: border-color var(--trans-r) ease, box-shadow var(--trans-r) ease;
}
table.grid td input[type="number"]:focus {
  outline: none;
  border-color: var(--brand-navy);
  box-shadow: var(--shadow-focus);
}
table.grid td input[type="number"]:disabled {
  background: var(--surface-alt);
  color: var(--texto-desabilitado);
}

/* --- caixa de texto financeira (padrão do sistema) --- */
/* Desenho (altura, borda, raio, fundo) vem da regra base de campo. */
.moeda-campo { display: inline-flex; align-items: center; gap: 5px; }
.moeda-prefixo { color: var(--muted); font-size: var(--fs-corpo); user-select: none; }
.moeda-input {
  border: 0 !important; background: transparent !important; outline: none;
  padding: 0 !important; margin: 0 !important; min-height: 0;
  text-align: right; width: 90px;
}
/* "0,00" cinza-claro (placeholder, sem preço definido) tem que ser
   inconfundível com "0,00" preto (preço real igual a zero) — o padrão do
   navegador sozinho é sutil demais numa tabela de preços. */
.moeda-input::placeholder { color: var(--muted); font-style: italic; opacity: 1; }
.form-modal .moeda-campo,
.fatura-ajuste-form .moeda-campo,
.campo > .moeda-campo { width: 100%; }
.campo > .moeda-campo { margin-top: var(--space-2xs); }
.form-modal .moeda-input,
.campo > .moeda-campo .moeda-input { flex: 1; width: auto; }
table.grid td .moeda-campo .moeda-input { width: 78px; }
.hist-edit .moeda-input { width: 78px; }

/* --- modal --- */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(15, 43, 86, 0.4);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  /* dvh, não vh: no tablet/celular a barra do navegador some/aparece e o vh
     fica maior que a área visível — o modal (e os botões) caía fora da tela.
     `overflow-y: auto` é a rede: modal muito alto, rola a camada toda.
     A linha `vh` fica de fallback para navegador sem `dvh`. */
  padding: 8vh 16px 16px;
  padding: 6dvh 16px 6dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
  z-index: 50;
}
.modal-box {
  background: var(--surface);
  border-radius: var(--radius-lg);
  /* A barra de ações grudada no rodapé (mais abaixo) é um retângulo reto
     que sangra até a borda — sem isso ela cobre o cantinho arredondado do
     modal-box e o canto aparece quadrado (mais visível à esquerda, porque
     a barra de rolagem "disfarça" o canto direito). */
  overflow: hidden;
  width: 100%;
  max-height: 84vh;
  max-height: calc(100dvh - 12dvh);
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow-modal);
  /* `.modal-resize` (canto) ancora em `position: absolute` nele — precisa
     de um ancestral posicionado mesmo antes do 1º arrasto/redimensionamento
     (quando `caixa.style.position` ainda não virou "fixed" via JS). */
  position: relative;
}
.modal-padrao { max-width: 460px; }
.modal-largo { max-width: 760px; }
.modal-amplo { max-width: min(1180px, 95vw); }
.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
  /* Arrastável (ver openModal em ui.ts) — exceto o botão fechar, que já tem
     seu próprio cursor/handler. */
  cursor: move;
  user-select: none;
}
/* Feedback visual durante o arrasto — leve, só pra confirmar que "pegou". */
.modal-box.modal-arrastando { opacity: .92; box-shadow: var(--shadow-modal), 0 0 0 2px var(--rb-blue); }
.modal-resize {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 22px;
  height: 22px;
  /* só a largura: a altura do modal segue o conteúdo (ver `openModal`) */
  cursor: ew-resize;
  touch-action: none;
}
.modal-resize::after {
  content: "";
  position: absolute;
  right: 5px;
  bottom: 5px;
  width: 10px;
  height: 10px;
  border-right: 3px solid var(--border);
  border-bottom: 3px solid var(--border);
  border-bottom-right-radius: 3px;
  transition: border-color .15s;
}
.modal-resize:hover::after,
.modal-resize:focus-visible::after {
  border-color: var(--rb-blue);
}
.modal-resize:focus-visible { outline: none; }
.modal-head h2 { margin: 0; }
/* min-width/height 44px (achado de acessibilidade — auditoria de toque):
   ícone de 16px + 4px de padding só dava ~24px, abaixo do alvo mínimo, em
   todo × de modal do sistema. */
.modal-x { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; border: 0; background: transparent; color: var(--muted); padding: var(--space-2xs); border-radius: var(--radius-sm); }
.modal-x:hover { background: var(--surface-alt); color: var(--ink); }
/* `scrollbar-gutter: stable` reserva o espaço da barra de rolagem sempre — assim
   o conteúdo do modal não "pula" quando a barra aparece (ao adicionar coletas
   no Cliente, por ex.). Navegador sem suporte cai no comportamento antigo. */
.modal-body {
  padding: 16px 20px;
  overflow-y: auto;
  scrollbar-gutter: stable;
  /* dentro do flex-column do .modal-box: precisa poder encolher pra rolar */
  flex: 1 1 auto;
  min-height: 0;
}
.modal-actions { margin-top: var(--space-xl); display: flex; align-items: center; justify-content: flex-end; gap: var(--space-sm); flex-wrap: wrap; }

/* Barra de ações do modal fica colada no rodapé enquanto o conteúdo rola —
   assim os botões nunca somem embaixo da dobra (tablet/celular com a barra do
   navegador ocupando altura). Só quando é o último bloco do conteúdo. */
.modal-body > * > .modal-actions:last-child,
.modal-body > .modal-actions:last-child {
  position: sticky;
  bottom: -16px;
  margin: 16px -20px -16px;
  padding: 12px 20px;
  background: var(--surface);
  border-top: 1px solid var(--border);
}

/* --- campo rotulado (rótulo em cima + controle), padrão do sistema --- */
.campo,
.form-modal > label {
  display: block;
  font-size: var(--fs-apoio);
  font-weight: 600;
  color: var(--ink);
  margin-bottom: var(--space-lg);
}
.campo small,
.form-modal > label small { display: block; margin: 2px 0 4px; font-size: var(--fs-apoio); font-weight: 400; }
/* O rótulo é o texto solto dentro do <label>; o que vem junto dele (lista,
   sufixo "dias", botão, bloco de opções) volta ao corpo e ao peso normal.
   Exceção: filtro de seleção múltipla traz o rótulo num <span> (regra abaixo). */
:is(.campo, .form-modal > label, .form-inline label, .filtro, .campo-inline)
  > :not(input, select, textarea, small, .campo-rotulo, .campo-obrigatorio, .multi-select) {
  font-size: var(--fs-corpo);
  font-weight: 400;
}
.filtro > span:first-child { font-size: var(--fs-apoio); font-weight: 600; }
/* Rótulo recua (pequeno, maiúsculo, mudo) pra abrir espaço pro valor, que
   passa a ser o elemento de maior peso visual do campo — antes os dois
   competiam no mesmo tamanho/cor. */
.campo-rotulo {
  display: block;
  margin-bottom: 5px;
  font-size: var(--fs-apoio);
  font-weight: 600;
  color: var(--muted);
}
.campo-obrigatorio { color: var(--danger); }
/* `grupoCampos()`: um rótulo para vários controles — o fieldset some, fica o
   visual de `.campo` */
.campo-grupo { border: 0; padding: 0; margin-inline: 0; min-width: 0; }
.campo-grupo > legend.campo-rotulo { padding: 0; }
.campo > input,
.campo > select,
.campo > textarea,
.form-modal > label > input,
.form-modal > label > select {
  display: block; width: 100%; margin-top: var(--space-2xs); color: var(--ink);
}
.campo > input[type="checkbox"] { display: inline-block; width: auto; }
.campo > textarea { min-height: 80px; }
/* Select com texto longo (ex.: rótulo de rotina no formulário de OS) elide
   em vez de estourar a largura do campo. */
.campo > select,
.form-modal > label > select {
  text-overflow: ellipsis;
  padding-right: 30px;
}

.form-modal .lista-select { margin-top: var(--space-2xs); }
.form-modal .sufixo { display: inline-flex; align-items: center; gap: var(--space-xs); margin-top: var(--space-xs); font-size: var(--fs-corpo); }
.form-modal .sufixo input { width: 72px; margin-top: 0; }
.rota-checks { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: var(--space-2xs); }
.rota-checks .check { margin: 0; }

.paradas-editor { border: 1px solid var(--border); border-radius: var(--radius-md); padding: 10px 12px 12px; margin: 0 0 12px; }
.paradas-editor legend { font-size: var(--fs-apoio); color: var(--muted); padding: 0 4px; font-weight: 600; }
.paradas-vazio { margin: 4px 0 8px; font-size: var(--fs-corpo); }
.prazo-padrao { margin-top: var(--space-lg); padding-top: var(--space-md); border-top: 1px dashed var(--border); font-size: var(--fs-corpo); }
.prazo-padrao strong { display: block; color: var(--brand-navy); }

/* Grade semanal da Rotina de Coleta e Devolução (_paradas-editor.ts):
   linhas = horários, colunas = dias, célula alterna vazio → Coletar →
   Devolver → Ambos. */
.paradas-grade { display: grid; grid-template-columns: 64px repeat(7, minmax(0, 1fr)); gap: var(--space-2xs); margin: 8px 0; }
.paradas-grade .pg-h { text-align: center; font-size: var(--fs-caixa-alta); font-weight: 600; letter-spacing: var(--ls-caixa-alta); color: var(--muted); text-transform: uppercase; }
.paradas-grade .pg-hora { display: flex; align-items: center; justify-content: flex-end; gap: var(--space-2xs); padding-right: var(--space-xs); font-size: var(--fs-apoio); color: var(--muted); font-variant-numeric: tabular-nums; }
/* 44px (achado de acessibilidade — auditoria de toque): era 32px, e essa
   grade é justamente a que mais faz sentido usar num tablet (Tab S9/Tab
   A12) montando a rotina semanal do cliente. Bate com `.parada-cel` ao
   lado, que já usava 44px. */
.paradas-grade .pg-rm { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; border: 0; background: none; color: var(--muted); font: inherit; font-size: 1rem; /* glifo ×, não texto */ line-height: 1; cursor: pointer; padding: 0 2px; }
.paradas-grade .pg-rm:hover { color: var(--danger); }
.parada-cel { border: 1px solid var(--border); border-radius: var(--radius-sm); min-height: 44px; background: var(--surface); color: var(--traco-vazio); font: inherit; font-size: var(--fs-caixa-alta); font-weight: 600; cursor: pointer; }
.parada-cel-coletar { background: var(--tint-danger); color: var(--danger); border-color: var(--border-danger); }
.parada-cel-devolver { background: var(--tint-ok); color: var(--ok); border-color: var(--border-ok); }
.parada-cel-ambos { background: linear-gradient(180deg, var(--tint-danger) 0 50%, var(--tint-ok) 50% 100%); color: var(--ink); border-color: var(--border-danger); }
.paradas-add-hora { display: flex; align-items: center; gap: var(--space-sm); margin: 4px 0 2px; }

.paradas-legenda { display: flex; flex-wrap: wrap; gap: 14px; margin-top: var(--space-md); font-size: var(--fs-apoio); color: var(--muted); }
.paradas-legenda span { display: flex; align-items: center; gap: var(--space-xs); }
.paradas-legenda i { width: 22px; height: 14px; border-radius: 4px; border: 1px solid var(--border); }

.lista-editavel { list-style: none; margin: 0 0 14px; padding: 0; }
.lista-editavel li { display: flex; align-items: center; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid var(--border); }
/* linha em edição: o formulário empilhado ocupa a linha inteira */
.lista-editavel li.cat-fin-editando { display: block; padding: 12px 0 4px; }
.lista-editavel li.cat-fin-editando .modal-actions { margin-top: var(--space-2xs); }

/* subtítulo dentro de um modal-formulário (ex.: "Nova categoria") */
.form-modal-sub {
  margin: 6px 0 10px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  font-size: var(--fs-corpo);
  color: var(--brand-navy);
}
.lista-add { display: flex; gap: var(--space-sm); align-items: flex-end; flex-wrap: wrap; }
.lista-add > input { flex: 1; min-width: 140px; color: var(--ink); }
/* o campo rotulado e a caixa de dinheiro entram na linha com a mesma altura
   dos `<input>` soltos — senão a linha fica com três alturas diferentes */
.lista-add > .campo-inline { flex: 0 0 auto; }

.lista-add .form-erro { flex-basis: 100%; }

/* --- histórico de preços (modal do Tipo de Peça) --- */
.hist-wrap { display: flex; flex-direction: column; }
.hist {
  border-top: 1px solid var(--border);
  margin: 4px -20px 0;
  padding: 14px 20px 0;
}
/* subtítulo dentro do Cliente aberto: o mesmo micro-rótulo do h5 */
.hist h5, .cliente-detalhe > h6 {
  margin: 0 0 8px; font-size: var(--fs-caixa-alta); font-weight: 600;
  text-transform: uppercase; letter-spacing: var(--ls-caixa-alta); color: var(--muted);
}
.cliente-detalhe > h6 { margin-top: var(--space-md); }
.hist .mini-vazio { margin: 0; font-size: var(--fs-corpo); }
table.mini { border-collapse: collapse; width: 100%; font-size: var(--fs-corpo); }
table.mini th, table.mini td { text-align: left; padding: 7px 4px; border-bottom: 1px solid var(--border); }
table.mini th { font-size: var(--fs-caixa-alta); text-transform: uppercase; letter-spacing: var(--ls-caixa-alta); color: var(--muted); font-weight: 600; }
table.mini tr:last-child td { border-bottom: 0; }
table.mini .r { text-align: right; }
table.mini .num { font-variant-numeric: tabular-nums; }
table.mini tr.antiga td { color: var(--muted); }

/* --- itens da conta a pagar --- */
.itens-conta-editor {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  margin: 0 0 12px;
  min-width: 0;
  width: 100%;
}
.itens-conta-editor legend {
  font-size: var(--fs-apoio);
  color: var(--muted);
  padding: 0 4px;
  font-weight: 600;
}
.itens-conta-linhas {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin-bottom: var(--space-sm);
}
.item-conta-linha {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  flex-wrap: nowrap;
  background: var(--surface-alt);
  padding: 6px 8px;
  border-radius: var(--radius-sm);
  font-size: var(--fs-corpo);
  overflow-x: auto;
  min-width: 0;
}
.item-conta-linha select {
  flex: 2 1 140px;
  min-width: 120px;
  color: var(--ink);
}
.item-conta-linha .item-unidade {
  width: 60px;
  flex: 0 0 60px;
  color: var(--ink);
}
.item-conta-linha .item-qtd {
  width: 70px;
  flex: 0 0 70px;
  color: var(--ink);
  text-align: right;
}
.item-conta-linha .moeda-campo {
  flex: 1 1 100px;
  min-width: 90px;
  width: auto;
}
.item-conta-linha .moeda-input {
  width: 70px;
}
.item-conta-linha .item-subtotal {
  min-width: 75px;
  text-align: right;
  font-weight: 600;
  color: var(--brand-navy);
  font-size: var(--fs-corpo);
}
.itens-conta-resumo {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 6px 4px 0;
  font-size: var(--fs-corpo);
  color: var(--muted);
  border-top: 1px dashed var(--border);
  margin-top: var(--space-xs);
}
.itens-conta-resumo b {
  color: var(--ink);
}

.hist .pill-ok {
  display: inline-block; font-size: var(--fs-caixa-alta); font-weight: 600;
  padding: 2px 9px; border-radius: 999px; background: var(--tint-ok); color: var(--ok);
}
.hist .pill-mut {
  display: inline-block; font-size: var(--fs-caixa-alta); font-weight: 600;
  padding: 2px 9px; border-radius: 999px; background: var(--surface-alt); color: var(--muted);
}
.hist-edit { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-xs); justify-content: flex-end; }

/* --- Lançar OS --- */
/* Responde à largura do próprio container, não à do viewport — importante
   porque agora o mesmo `.grid-2` aparece tanto num modal largo quanto no
   painel estreito (460px) da Ficha Única ao lado da lista. */
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 0 14px; }
.grid-2 > * { min-width: 0; }

/* --- Ficha Única (Fase 6): linha-comanda de um Tipo de Peça --- */
.ficha-tabela { display: flex; flex-direction: column; gap: var(--space-sm); }
/* --- Peças da Ficha por categoria (variação C do protótipo, 2026-09-29) ---
   Cada categoria recolhível com o resumo no cabeçalho — ver "Grupo
   recolhível" no ui.md. Recuo do cabeçalho = recuo do corpo + recuo da
   linha-comanda: o nome da categoria começa onde começam "PEÇA" e os nomes
   das peças, e a seta (mesma caixa da .ficha-caret) fica na coluna delas. */
.ficha-categorias-barra { justify-content: space-between; }
.ficha-categorias-acoes { display: flex; gap: var(--space-md); }
.ficha-categorias { display: flex; flex-direction: column; gap: var(--space-sm); }
.ficha-categoria { border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface); }
.ficha-categoria-cab {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-sm) calc(var(--space-md) * 2);
  /* +1px: a borda da linha-comanda, para a seta cair no mesmo pixel da dela */
  padding-right: calc(var(--space-md) * 2 + 1px);
  cursor: pointer;
}
.ficha-categoria-cab h4 {
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: var(--space-sm);
  font-size: var(--fs-apoio);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--ls-caixa-alta);
  /* --ink, não o navy dos títulos: um nível abaixo de COLETA/FECHAMENTO
     (navy), não compete com eles */
  color: var(--ink);
}
.ficha-categoria-cab h4 small { font-weight: 400; text-transform: none; letter-spacing: 0; color: var(--muted); }
/* botão com cara de título — mesmo recurso do button.th-rotulo: herda a
   fonte do <h4> (exceção documentada no ui.md, Tipografia) */
.ficha-categoria-titulo {
  border: 0;
  background: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
}
.ficha-categoria-titulo:focus-visible { outline: none; box-shadow: var(--shadow-focus); border-radius: var(--radius-sm); }
.ficha-categoria-numeros { font-size: var(--fs-apoio); color: var(--muted); font-variant-numeric: tabular-nums; text-align: right; }
/* mesma caixa da .ficha-caret (borda, recuo, altura, fonte), sem o fundo:
   o caractere cai exatamente na coluna das setas das peças */
.ficha-categoria-seta {
  display: inline-flex;
  align-items: center;
  min-height: var(--altura-compacta);
  padding: 0 8px;
  border: 1px solid transparent;
  font-size: var(--fs-apoio);
  color: var(--muted);
}
.ficha-categoria-corpo { padding: 0 var(--space-md) var(--space-md); display: flex; flex-direction: column; gap: var(--space-sm); }
/* caixa alta e espaçamento vêm da regra de todos os pill-* */
.pill-categoria {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: var(--fs-caixa-alta);
  font-weight: 600;
  white-space: nowrap;
}
.pill-categoria-neutro { background: var(--surface-alt); color: var(--muted); }
.pill-categoria-atencao { background: var(--tint-busy); color: var(--busy); }
.pill-categoria-ok { background: var(--tint-ok); color: var(--ok); }
@media (max-width: 640px) {
  /* os números descem para uma linha própria, abaixo do título */
  .ficha-categoria-cab { grid-template-columns: minmax(0, 1fr) auto auto; }
  .ficha-categoria-numeros { grid-column: 1 / -1; grid-row: 2; text-align: left; }
}
.ficha-linha-tipo {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
}
.ficha-linha-cab {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) repeat(3, minmax(0, 0.9fr)) minmax(0, 1fr);
  gap: var(--space-sm);
  align-items: center;
  padding: var(--space-sm) var(--space-md);
}
.ficha-peca-nome { font-size: var(--fs-corpo); font-weight: 600; }
/* Quantidades da linha-comanda: zero fica vazio e o "0" é só a dica, que
   some ao clicar — a pessoa digita sem apagar nada antes. */
.ficha-linha-cab input:focus::placeholder { color: transparent; }
/* Cabeçalho da tabela de peças: mesmo tratamento de table.grid th (padrão do
   sistema para cabeçalho de coluna) — antes usava <b> cru, peso/caixa/cor
   destoando de toda tabela do app. */
.ficha-linha-titulo {
  padding-top: 0;
  padding-bottom: var(--space-xs);
}
.ficha-linha-titulo > span {
  font-size: var(--fs-caixa-alta);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--ls-caixa-alta);
  color: var(--muted);
}
.ficha-campo { min-width: 0; }
.ficha-campo input[type="number"] {
  width: 100%;
  margin: 0;
  color: var(--ink);
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.ficha-campo input[type="number"]:disabled { background: var(--surface-alt); color: var(--texto-desabilitado); }
.ficha-campo-recebida input { background: var(--surface-alt); }
.ficha-campo-retida { display: flex; align-items: center; gap: var(--space-2xs); }
.ficha-campo-retida input { flex: 1 1 auto; min-width: 0; }
.ficha-caret {
  flex: 0 0 auto;
  appearance: none;
  border: 1px solid var(--border);
  background: var(--surface-alt);
  color: var(--muted);
  border-radius: var(--radius-md);
  min-height: var(--altura-compacta);
  padding: 0 8px;
  font-size: var(--fs-apoio);
  cursor: pointer;
}
.ficha-caret:hover { border-color: var(--brand-navy); color: var(--brand-navy); }
.ficha-caret[aria-expanded="true"] { background: var(--brand-navy); border-color: var(--brand-navy); color: var(--surface); }
.ficha-caret-alerta { border-color: var(--busy); color: var(--busy); }
/* Mesma cor que a nota/seta de divergência já usam nesta tela — só quando
   a divergência conferida é > 0 (achado de colorize: contagem vinha em
   negrito sem cor nenhuma, mesmo com um vizinho já usando --busy pra
   sinalizar a mesma coisa). */
.num-divergencia { color: var(--busy); }
.ficha-detalhe {
  overflow: hidden;
  max-height: 0;
  opacity: 0;
  transition: opacity .22s ease, transform .22s ease;
}
.ficha-detalhe.aberto {
  max-height: 420px;
  opacity: 1;
  padding: 10px 12px 12px;
  border-top: 1px dashed var(--border);
  background: var(--surface-alt);
}
@media (prefers-reduced-motion: reduce) { .ficha-detalhe { transition: none; } }
.ficha-motivo-divergencia label {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  font-size: var(--fs-apoio);
  color: var(--busy);
  font-weight: 600;
  margin: 0 0 8px;
}
.ficha-motivo-divergencia select { border-color: var(--busy); }
.ficha-retidas-bloco { display: flex; flex-direction: column; gap: var(--space-xs); align-items: flex-start; }
.ficha-retida-linha { display: flex; align-items: center; gap: var(--space-xs); flex-wrap: wrap; }
.ficha-retida-linha select { flex: 1; min-width: 100px; }
.ficha-retida-linha input[type="number"] {
  width: 76px;
  color: var(--ink);
  text-align: right;
}
.ficha-rodape {
  display: flex;
  justify-content: space-between;
  gap: var(--space-md);
  flex-wrap: wrap;
  font-size: var(--fs-apoio);
  color: var(--muted);
  margin-top: var(--space-sm);
}
.ficha-rodape-origem { display: flex; flex-direction: column; gap: var(--space-xs); }
.ficha-origem-backlog { color: var(--brand-navy); }
.ficha-origem-backlog.alerta { color: var(--busy); }
.ficha-composicao-retidas { color: var(--ink); }
.ficha-backlog-hotel { color: var(--ink); }
.contagem-total .ficha-composicao-retidas { display: block; margin-top: var(--space-xs); }
.ficha-situacao-retencao { display: flex; flex-direction: column; gap: var(--space-xs); }
/* recusas do "Fechar OS" que não são de uma peça, antes do clique (#84) */
.ficha-aviso-geral {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  margin-top: var(--space-sm);
  font-size: var(--fs-apoio);
}
/* Linha de situação com ícone (ui.md "Avisos") */
.situacao-icone { display: inline-flex; align-items: flex-start; gap: var(--space-xs); }
.situacao-icone svg { flex-shrink: 0; margin-top: 2px; }
.situacao-alerta { color: var(--busy); font-weight: 600; }
.situacao-ok { color: var(--ok); }
.ficha-utilitarios { display: flex; gap: var(--space-sm); flex-wrap: wrap; }

@media (max-width: 640px) {
  .ficha-linha-cab { grid-template-columns: 1fr 1fr; }
  .ficha-peca-nome { grid-column: 1 / -1; }
}

/* --- Ficha Única (Fase 6): painel --- */
.ficha-painel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  padding: 20px 22px;
  display: flex;
  flex-direction: column;
}
.ficha-painel > .ficha-cab { padding-bottom: 18px; }
/* Aviso de situação e erro vêm depois da última seção (os totais do
   Fechamento): sem gap na coluna, encostavam no texto de cima. */
.ficha-painel > .aviso { margin-top: var(--space-xl); }
.ficha-painel > .form-erro:not(:empty) { margin-top: var(--space-md); }
.ficha-cab { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-md); }
.ficha-cab > div:first-child { min-width: 0; }
.ficha-cab h2 { margin: 0; font-size: var(--fs-titulo); font-weight: 700; color: var(--brand-navy); letter-spacing: -.01em; }
.ficha-cab p { margin: 3px 0 0; font-size: var(--fs-apoio); overflow-wrap: break-word; font-variant-numeric: tabular-nums; }
.ficha-cab-acoes { display: flex; align-items: center; gap: var(--space-sm); flex: 0 0 auto; }
/* Ritmo deliberado: mais espaço ACIMA do título de seção do que abaixo dele
   até o primeiro campo — o título "puxa" a seção seguinte, não "empurra" a
   anterior. */
.ficha-secao { display: flex; flex-direction: column; gap: var(--space-sm); padding-top: 28px; border-top: 1px solid var(--border); }
.ficha-secao:first-of-type { padding-top: 0; border-top: none; }
.ficha-secao > h3, .ficha-secao-cab > h3 {
  margin: 0 0 6px;
  font-size: var(--fs-apoio);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--ls-caixa-alta);
  color: var(--brand-navy);
  display: flex;
  align-items: center;
  gap: 7px;
}
/* Cor com função, não decoração: cada etapa da OS usa a cor da própria faixa
   arco-íris do topo, na mesma ordem — um ponto, não uma barra (evita o
   clichê de "card com risco colorido na lateral"). Ponto vem DEPOIS do
   texto (::after) de propósito: antes (::before) empurrava "COLETA" pra
   direita e desalinhava do resto do formulário — texto sempre começa
   exatamente onde os outros rótulos da tela começam. */
.ficha-secao > h3::after, .ficha-secao-cab > h3::after {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex: 0 0 auto;
}
.ficha-secao:nth-of-type(1) > h3::after { background: var(--rb-blue); }
.ficha-secao:nth-of-type(2) .ficha-secao-cab > h3::after { background: var(--rb-green); }
.ficha-secao-cab { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-md); flex-wrap: wrap; }
.ficha-nota-bloqueio { font-size: var(--fs-apoio); color: var(--muted); font-style: italic; }
.ficha-acoes { display: flex; align-items: center; gap: var(--space-sm); flex-wrap: wrap; padding-top: var(--space-lg); border-top: 1px solid var(--border); }

.pill-situacao { display: inline-block; font-size: var(--fs-caixa-alta); font-weight: 600; padding: 2px 9px; border-radius: 999px; white-space: nowrap; }
.pill-situacao-novo { background: var(--surface-alt); color: var(--muted); }
.pill-situacao-lancado { background: var(--surface-alt); color: var(--muted); }
.pill-situacao-fechado { background: var(--tint-ok); color: var(--ok); }
/* Reaberta (ADR-0024): mesmo tom de "precisa de atenção" que `.pill-fat-parcial`
   já usa pra Conta parcialmente paga — nem erro (--danger), nem repouso limpo
   (--ok), é um estado que espera uma ação do operador. */
.pill-situacao-reaberta { background: var(--tint-busy); color: var(--busy); }
.pill-situacao-faturado { background: var(--tint-navy); color: var(--brand-navy); }
.pill-situacao-cancelado { background: var(--tint-danger); color: var(--danger); }

/* --- Ficha Única (Fase 6): layout mestre-detalhe de Lançar OS ---
   Lista + ficha sempre lado a lado, sem modal (ver comentário no topo de
   lancar-os.ts) — a ficha nunca esconde a lista, só divide a largura com
   ela. No celular (media query abaixo) empilha, ficha depois da lista. */
.lancar-os-layout { display: flex; flex-basis: 100%; min-width: 0; gap: var(--space-sm); align-items: flex-start; }
.lancar-os-layout > .tela-lista { flex: 1 1 auto; min-width: 0; }
.lancar-os-layout > .ficha-painel {
  /* Largura RELATIVA ao layout: lista e ficha dividem a tela inteira em
     qualquer monitor (antes, teto fixo de 980px na lista e 880px na ficha
     deixavam metade de um 4K vazia — achado do dono, 2026-09-28). A
     proporção vem da divisória (painelRedimensionavel em ui.ts, 50% por
     padrão); o clamp() garante 460px de ficha e 480px de lista. */
  flex: 0 0 clamp(460px, var(--painel-p, 50%), calc(100% - 480px));
  position: sticky;
  top: 16px;
  max-height: calc(100vh - 32px);
  overflow-y: auto;
}
.painel-resize {
  flex: 0 0 12px;
  align-self: stretch;
  cursor: col-resize;
  position: relative;
  touch-action: none;
}
.painel-resize::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 4px;
  bottom: 4px;
  width: 3px;
  transform: translateX(-50%);
  border-radius: 999px;
  background: var(--border);
  transition: background .15s;
}
.painel-resize:hover::after,
.painel-resize.arrastando::after {
  background: var(--rb-blue);
}
.painel-resize:focus-visible { outline: none; }
.painel-resize:focus-visible::after {
  background: var(--rb-blue);
  box-shadow: var(--shadow-focus);
}

/* 900px era o corte aqui também até a auditoria de adapt (dispositivos
   reais) medir de verdade: a 900-1180px de viewport, o layout lado a lado
   "cabia" tecnicamente mas a lista ficava com ~250-350px contra uma tabela
   que precisa de ~832px — pior que empilhar. 1200px é o ponto onde a
   lista, JÁ empilhada (largura cheia, sem dividir com a ficha), acomoda a
   tabela sem cortar coluna (medido: content ≈860px aos 1200px de viewport
   vs os 832px que a tabela pede). Tablet em paisagem (Tab S9 1280px, Tab
   A12 1340px) continua lado a lado — decisão do dono — só a faixa que já
   estava quebrada antes passou a empilhar. */
@media (max-width: 1200px) {
  .lancar-os-layout { flex-direction: column; }
  .lancar-os-layout > .tela-lista { width: 100%; }
  .lancar-os-layout > .ficha-painel { flex-basis: auto; width: 100%; position: static; max-height: none; }
  /* Empilhado não tem o que dividir — arrastar na vertical não faz sentido. */
  .painel-resize { display: none; }
}

/* --- Faturamento --- */
.pill-fat {
  display: inline-block; font-size: var(--fs-caixa-alta); font-weight: 600; padding: 2px 9px;
  border-radius: 999px;
}
.pill-fat-rascunho { background: var(--surface-alt); color: var(--muted); }
.pill-fat-emitida { background: var(--tint-navy); color: var(--brand-navy); }
/* Faltava desde o ADR-0023: a Fatura já calculava "reaberta" certo, só o
   pill nunca ganhou cor — caía sem `background`/`color` nenhum. */
.pill-fat-reaberta { background: var(--tint-busy); color: var(--busy); }
.pill-fat-paga { background: var(--tint-ok); color: var(--ok); }
/* Situação de Pagamento de uma Conta (#16) — reusa a pílula do Faturamento. */
.pill-fat-pendente { background: var(--surface-alt); color: var(--muted); }
.pill-fat-parcial { background: var(--tint-busy); color: var(--busy); }
.pill-fat-quitada { background: var(--tint-ok); color: var(--ok); }
/* Log de Auditoria (#42). */
tr.linha-erro td { background: var(--tint-danger); }
pre.json-cru { background: var(--surface-alt); padding: var(--space-lg); border-radius: var(--radius-sm); overflow-x: auto; font-size: var(--fs-apoio); max-height: 60vh; }
/* Resumo do mês nas Retiradas Pessoais (#17). */
.retiradas-resumo { margin: 10px 0; }
.retiradas-resumo p { margin: 2px 0; }
/* Dia de Vencimento no cadastro do Cliente (#40). Era só ".dia-venc { width }"
   — o próprio <label> nunca tinha display:block, então "Dia de Vencimento"
   e o sufixo "vence dia" corriam juntos na mesma linha, sem espaço. */
.campo-venc { display: block; margin-bottom: var(--space-lg); }
.campo-venc .dia-venc { width: 5.5em; }
.fatura-head { margin-bottom: var(--space-lg); }
.fatura-head h3 { margin: 0 0 4px; display: inline-block; margin-right: var(--space-sm); }
.fatura-periodo { margin-top: var(--space-md); }
.fatura-periodo .campo { margin-bottom: 0; }
table.fatura-linhas { width: 100%; }
table.fatura-linhas th.r, table.fatura-linhas td.num { text-align: right; }
tr.fatura-linha-ajuste td { color: var(--muted); font-size: var(--fs-corpo); padding-top: 3px; padding-bottom: 3px; }
/* caixa de subformulário dentro do detalhe da Fatura (Ajuste, Compensação) */
.fatura-subform { padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius-md); }
.fatura-ajuste-form {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-md);
  margin: 12px 0;
}
.fatura-ajuste-form .campo { margin: 0; flex: 1 1 130px; }
.fatura-ajuste-form .campo:first-child { flex: 2 1 180px; }
table.fatura-totais { width: 100%; max-width: 320px; margin-left: auto; margin-top: var(--space-lg); }
table.fatura-totais td { padding: 4px 4px; border: 0; }
table.fatura-totais td.r { text-align: right; }
tr.fatura-total td { border-top: 1px solid var(--border); padding-top: var(--space-sm); font-size: var(--fs-subtitulo); }
/* --- Planilha de Fechamento --- */
/* grupo de exportação: uma linha abaixo da tabela, largura toda */
.planilha-export {
  margin-top: var(--space-xl); display: flex; align-items: center; gap: var(--space-lg); flex-wrap: wrap;
}
.planilha-formato { flex-direction: row; align-items: center; gap: var(--space-sm); }
.planilha-formato > select { flex: 0 0 auto; min-width: 170px; }
.planilha-export .modal-actions { margin-top: 0; margin-left: auto; }

.planilha-sub { margin: 0 0 12px; font-size: var(--fs-corpo); }
/* `padding-right` — não o `padding` de `table.mini` (4px, usada em telas com
   ela sem rolagem) — dá um respiro entre os números da última coluna e a
   barra de rolagem vertical, que sem isso ficava colada nos totais. */
.planilha .table-wrap { max-height: 56vh; overflow: auto; padding-right: 10px; }

/* colunas iguais: table-layout: fixed + <col> de 92px (larguras vêm do
   colgroup no _planilha.ts). Sobrando espaço, crescem igual; faltando, rola. */
table.planilha-tab { width: 100%; table-layout: fixed; }
table.planilha-tab th, table.planilha-tab td {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
table.planilha-tab th.r, table.planilha-tab td.r { text-align: right; }
/* nome do Tipo quebra quando a coluna aperta */
table.planilha-tab tr.planilha-cab-tipos th {
  white-space: normal; line-height: 1.15; vertical-align: middle; word-break: break-word;
}
table.planilha-tab tbody td:first-child { white-space: normal; }
.planilha-marca { display: block; font-size: var(--fs-caixa-alta); line-height: 1.1; }

table.planilha-tab tr.planilha-cab-cat th {
  text-align: center; font-weight: 600; font-size: var(--fs-caixa-alta); letter-spacing: var(--ls-caixa-alta);
  text-transform: uppercase; color: var(--muted); border-bottom: 1px solid var(--border);
}
table.planilha-tab tr.planilha-cab-cat th:first-child,
table.planilha-tab tr.planilha-cab-cat th:last-child { border-bottom: 0; }

table.planilha-tab thead th { position: sticky; top: 0; background: var(--surface-alt); z-index: 1; }
table.planilha-tab thead tr:last-child th { top: 22px; }
table.planilha-tab tfoot td { border-top: 1px solid var(--border); }
tr.planilha-total td { font-weight: 600; }
tr.planilha-ajuste td { color: var(--muted); font-style: italic; }
/* "Valor unitário" com mais de um preço (`unitarios`): um por linha, sem quebrar */
.planilha-precos { display: inline-flex; flex-direction: column; align-items: flex-end; white-space: nowrap; }
/* relavagem (fora dos totais) e compensação (conta) — ver `linhaCinza` */
tr.planilha-linha-cinza td { background: var(--surface-alt); color: var(--muted); }
tr.planilha-geral td { background: var(--brand-navy); color: var(--surface); }
tr.planilha-geral td b { color: var(--surface); }

.fatura-hist { margin-top: var(--space-lg); font-size: var(--fs-corpo); }
.fatura-hist summary { cursor: pointer; color: var(--brand-navy); }
.fatura-hist ul { margin: 6px 0 0; padding-left: 18px; color: var(--muted); }
/* Compensação de Peças (ADR-0031): seção aberta pelo botão da barra de ações */
.fatura-compensacao {
  display: flex; flex-direction: column; gap: var(--space-md);
  margin-top: var(--space-lg); padding-top: var(--space-lg); border-top: 1px solid var(--border);
}
.fatura-compensacao > h3 { margin: 0; }
/* a base de 480px de `.table-wrap` (pensada para linha) viraria altura nesta coluna */
.fatura-compensacao > .table-wrap { flex: 0 0 auto; }
.fatura-compensacao-form { display: flex; flex-direction: column; gap: var(--space-md); }
.fatura-compensacao-form .campo { margin: 0; }
.fatura-compensacao-os { display: flex; flex-wrap: wrap; gap: var(--space-md); align-items: flex-end; }
.fatura-compensacao-os > .campo { flex: 0 1 150px; }
.fatura-compensacao-os > .campo:last-child { flex: 1 1 240px; }
.fatura-compensacao-dica { margin: 0; font-size: var(--fs-apoio); }
.fatura-compensacao-dica:empty { display: none; }
.fatura-compensacao-pecas { display: flex; flex-direction: column; gap: var(--space-sm); margin-top: var(--space-2xs); }
.fatura-compensacao-peca { display: grid; grid-template-columns: minmax(0, 1fr) 110px auto; gap: var(--space-sm); align-items: center; }
.pill-urgente {
  display: inline-block; margin-left: var(--space-sm); font-size: var(--fs-caixa-alta); font-weight: 600;
  padding: 2px 9px; border-radius: 999px;
  background: var(--tint-danger); color: var(--danger);
}
/* Cinza (var(--muted)) até a auditoria de colorize: "urgente" (irmã, acima)
   já usa vermelho funcional, mas "relavagem" não tinha cor nenhuma — agora
   usa a MESMA cor que "relavagem" já tem no gráfico e nos totalizadores do
   Dashboard (preto/var(--ink)), não uma cor nova. */
.pill-relavagem {
  display: inline-block; margin-left: var(--space-sm); font-size: var(--fs-caixa-alta); font-weight: 600;
  padding: 2px 9px; border-radius: 999px;
  background: var(--surface-alt); color: var(--ink);
}
/* Regra 1 da capitalização (docs/design/ui.md): TODO selo de estado é caixa
   alta, aplicada aqui — o texto no código fica em regra 2, para leitor de
   tela e copiar/colar. Pega qualquer classe "pill-*": selo novo já nasce
   em caixa alta, sem precisar ser lembrado numa lista. */
[class^="pill-"], [class*=" pill-"] {
  text-transform: uppercase;
  letter-spacing: var(--ls-caixa-alta);
}
.prazo-vencido { color: var(--danger); font-weight: 600; }
.os-cel { display: flex; align-items: center; gap: 0; }
.os-cod { display: block; font-size: var(--fs-apoio); font-variant-numeric: tabular-nums; margin-top: 1px; }
.contagem-filtros { display: flex; gap: var(--space-lg); flex-wrap: wrap; align-items: flex-end; margin: 6px 0 8px; }
/* Filtros dentro do modal de Lançar OS: alinhar visualmente com .campo */
.form-modal .contagem-filtros .filtro { color: var(--ink); gap: 0; }
.form-modal .contagem-filtros .filtro > select { margin-top: var(--space-2xs); }
.contagem-busca-label { display: block; font-size: var(--fs-apoio); font-weight: 600; color: var(--muted); margin-bottom: var(--space-2xs); }
.contagem-busca-input { min-width: 180px; }
.contagem-total { margin: 10px 0 0; font-size: var(--fs-corpo); color: var(--muted); }
.contagem-total b { color: var(--ink); font-variant-numeric: tabular-nums; }

.dev-tipos { max-height: 46vh; overflow-y: auto; margin: 4px 0 0; }
.dev-tipo { border: 1px solid var(--border); border-radius: var(--radius-md); padding: 10px 12px; margin-bottom: var(--space-md); }
.dev-cab { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-md); font-size: var(--fs-corpo); }
.dev-linha { display: flex; align-items: flex-end; gap: 14px; flex-wrap: wrap; margin-top: var(--space-sm); }
.dev-linha label { display: flex; flex-direction: column; gap: 3px; font-size: var(--fs-apoio); font-weight: 600; color: var(--muted); margin: 0; }
.dev-linha input {
  color: var(--ink);
  margin: 0;
}
.dev-linha input[type="number"] { width: 92px; text-align: right; }
/* Saldo inicial negativo (ADR-0019) — dica de quanto digitar pra zerar,
   calculada com a mesma conta que o comando usa pra validar. */
.backlog-inicial-nota { display: block; margin-top: var(--space-xs); color: var(--danger); }
.backlog-alerta { display: inline-flex; align-items: center; color: var(--danger); }
/* Motivo de "Registrar perda" desabilitado em texto visível, não só title
   (achado da crítica: hover-only não chega a toque nem a botão desabilitado
   focado por teclado). */
.backlog-acao-desabilitada { display: inline-flex; align-items: center; gap: var(--space-xs); }

/* --- "Precisa de atenção" (topo da tela de Backlog) --- */
/* Recolhível (<details>): o título com a contagem é o botão; começa fechado. */
.backlog-atencao-cab {
  display: flex; align-items: center; gap: var(--space-md);
  list-style: none; cursor: pointer; user-select: none;
  min-height: var(--altura-compacta);
}
.backlog-atencao-cab::-webkit-details-marker { display: none; }
.backlog-atencao-cab::after { content: "▾"; margin-left: auto; color: var(--muted); transition: transform .15s; }
.backlog-atencao:not([open]) .backlog-atencao-cab::after { transform: rotate(-90deg); }
.backlog-atencao[open] > .backlog-atencao-cab { margin-bottom: var(--space-sm); }
.backlog-atencao-cab h2 { margin: 0; }
.backlog-atencao-contagem {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; padding: 0 6px; border-radius: 999px;
  background: var(--surface-alt); color: var(--muted);
  font-size: var(--fs-caixa-alta); font-weight: 600;
}
.backlog-atencao-item {
  display: flex; align-items: center; gap: var(--space-lg);
  padding: var(--space-md) 0; border-top: 1px solid var(--border);
}
.backlog-atencao-item:first-of-type { border-top: 0; }
.backlog-atencao-txt { flex: 1 1 auto; display: flex; flex-direction: column; gap: 2px; min-width: 0; }

/* --- Situação de uma linha do Histórico do Backlog (aberto/devolvido/perda) --- */
.pill-backlog {
  display: inline-flex; align-items: center; padding: 2px 9px;
  border-radius: 999px; font-size: var(--fs-caixa-alta); font-weight: 600;
}
.pill-backlog-aberto { background: var(--surface-alt); color: var(--muted); }
/* Entrada no Backlog (ADR-0030): peça indo para reprocesso — par Retrabalho. */
.pill-backlog-entrada { background: var(--surface-alt); color: var(--ink); }
.pill-backlog-devolvido { background: var(--tint-ok); color: var(--ok); }
.pill-backlog-perda { background: var(--tint-danger); color: var(--danger); }
/* Peça do Backlog reprocessada e retida de novo noutra OS (ADR-0025). */
.pill-backlog-retida { background: var(--tint-navy); color: var(--brand-navy); }
/* Separa "Backlog por Cliente" do "Histórico do Backlog". */
.backlog-separador { border: 0; border-top: 1px solid var(--border); margin: var(--space-xl) 0 0; }
.backlog-hist-motivo-saida { font-size: var(--fs-apoio); margin-top: 2px; }

/* Cabeçalho das seções "Tudo no backlog" e "Histórico do backlog" — mesmo
   tamanho/cor de `.card h2`, mas sem o card em volta (a matriz e a tabela já
   têm a própria borda). */
.backlog-secao-titulo { margin: 18px 0 2px; }

/* --- Backlog inicial (matriz editável, `_backlog-inicial-form.ts`) ---
   Reaproveita `.matriz-precos`, mas aqui a nota abaixo dos filtros descreve a
   MATRIZ (o que preencher), não os combos — por isso fica mais colada na
   tabela do que neles, ao contrário do ritmo genérico de `.matriz-precos > p`
   (legenda solta, na Matriz de Preços que só lê). */
.backlog-inicial > p { margin-top: var(--space-lg); margin-bottom: var(--space-sm); }
/* Categoria fecha o bloco de identidade da linha (Tipo de Peça + Categoria);
   tudo à direita é dado por Hotel — uma divisória marca a virada, só faz
   sentido em modo tabela (abaixo de 900px a linha vira card empilhado). */
@media (min-width: 901px) {
  .backlog-inicial table.grid th:nth-child(2),
  .backlog-inicial table.grid td:nth-child(2) {
    border-right: 1px solid var(--border);
  }
}
/* Toda célula da matriz é editável — é a única razão da tela existir —,
   então ganha o mesmo aviso visual de "é aqui que se digita" que a Matriz de
   Preços já usa por Hotel (`td.preco-cliente`), em vez do input neutro de
   filtro genérico. */
.backlog-inicial table.grid td input[type="number"] {
  border-color: var(--brand-navy);
  background: var(--tint-input-leve);
}
.hist-edit .hist-data { margin-right: auto; }
.hist-input { width: 90px; border-color: var(--brand-navy); text-align: right; }
.hist-data { border-color: var(--brand-navy); }
.hist-acao { display: inline-flex; align-items: center; gap: var(--space-sm); }
.hist-erro { flex-basis: 100%; text-align: right; color: var(--danger); font-size: var(--fs-apoio); }

.cliente-row {
  display: flex; align-items: center; gap: var(--space-md); padding: 9px 0;
  border-bottom: 1px solid var(--border); font-size: var(--fs-corpo);
}
.cliente-row:last-child { border-bottom: 0; }
.hist .cliente-nome { font-weight: 600; }
.hist .cliente-val { margin-left: auto; font-variant-numeric: tabular-nums; }
/* Cliente aberto: vigências do preço próprio (editáveis) + linha do tempo */
.cliente-detalhe { padding-bottom: var(--space-md); border-bottom: 1px solid var(--border); }
.cliente-detalhe:last-child { border-bottom: 0; }
.cliente-detalhe > .cliente-row { border-bottom: 0; }

.hist-tl { list-style: none; margin: 2px 0 10px; padding: 6px 0 0 4px; }
.hist-tl li {
  position: relative; padding: 0 0 12px 18px; border-left: 2px solid var(--border);
}
.hist-tl li:last-child { border-left-color: transparent; padding-bottom: var(--space-3xs); }
.hist-tl li::before {
  content: ""; position: absolute; left: -6px; top: 3px; width: 10px; height: 10px;
  border-radius: 50%; background: var(--border); border: 2px solid var(--surface);
}
.hist-tl li.vig::before { background: var(--ok); }
.hist-tl-top { display: flex; align-items: baseline; gap: var(--space-sm); }
.hist-tl-top b { font-size: var(--fs-corpo); color: var(--ink); font-variant-numeric: tabular-nums; }
.hist-tl-date { font-size: var(--fs-apoio); color: var(--muted); }
.hist-tl-src { display: block; font-size: var(--fs-apoio); color: var(--muted); margin-top: 1px; }
.hist-tl-vazio { border-left: 0; padding-left: 0; color: var(--muted); font-size: var(--fs-corpo); }
.hist-tl-vazio::before { display: none; }
.hist-modal .hist-tl { margin: 0; }

/* --- Cronograma de Coleta/Devolução --- */
/* `.content` normalmente só cresce até a altura do próprio conteúdo — aqui
   (só quando a tela marca `.cronograma-content`, no cleanup ela desmarca) ele
   vira uma coluna que ocupa o espaço vertical que sobrar em `.main`, e repassa
   isso para o card e para a grade dentro dele. Cada nível precisa de
   `min-height: 0` — senão o flex não deixa o de baixo encolher/rolar. */
.content.cronograma-content {
  flex: 1 1 auto; flex-direction: column; flex-wrap: nowrap; align-items: stretch; min-height: 0;
}
.cronograma-content > .tela-lista { flex: 1 1 auto; min-height: 0; }
/* `.tela-lista > *` (regra geral, acima) fixa os filhos em flex:0 0 auto —
   esta precisa ser mais específica para vencer só na grade. Sem `flex-grow`
   de propósito: a grade não estica além do próprio conteúdo (senão sobra um
   vão vazio entre ela e a legenda) — só encolhe e rola, quando não couber. */
.cronograma-content .cronograma-table-wrap {
  flex: 0 1 auto; min-height: 0; max-height: none; overflow-y: auto;
}
table.cronograma {
  border-collapse: collapse; width: 100%; background: var(--surface); min-width: 900px;
  border: 1px solid var(--border);
}
table.cronograma th, table.cronograma td {
  border-bottom: 1px solid var(--border); border-right: 1px solid var(--border); padding: 6px 10px;
}
table.cronograma th:last-child, table.cronograma td:last-child { border-right: 0; }
table.cronograma tr:last-child td, table.cronograma tr:last-child th { border-bottom: 0; }
table.cronograma thead th {
  background: var(--surface-alt); color: var(--muted); font-size: var(--fs-caixa-alta);
  text-transform: uppercase; letter-spacing: var(--ls-caixa-alta); font-weight: 600; text-align: center; padding: 10px 8px;
  position: sticky; top: 0; z-index: 2;
}
table.cronograma thead th.cronograma-hcol { text-align: left; left: 0; z-index: 3; }
table.cronograma tbody th {
  background: var(--surface-alt); color: var(--muted); font-size: var(--fs-apoio);
  font-variant-numeric: tabular-nums; text-align: right; font-weight: 400; white-space: nowrap;
  position: sticky; left: 0; z-index: 1;
}
table.cronograma tbody tr:nth-child(even) td { background: var(--surface-alt); }
.cronograma-cel { vertical-align: top; }
.cronograma-chip {
  display: block; border-radius: var(--radius-sm); padding: 3px 7px; font-size: var(--fs-caixa-alta);
  font-weight: 600; line-height: 1.3; margin-bottom: 3px;
}
.cronograma-chip:last-child { margin-bottom: 0; }
.cronograma-chip-coleta { background: var(--tint-danger); color: var(--danger); }
.cronograma-chip-devolucao { background: var(--tint-ok); color: var(--ok); }
.cronograma-legenda { display: flex; gap: 18px; align-items: center; flex-wrap: wrap; font-size: var(--fs-corpo); color: var(--muted); margin-bottom: var(--space-lg); }
.cronograma-export { margin-top: var(--space-lg); }
.cronograma-legenda-item { display: flex; align-items: center; gap: var(--space-xs); }
.cronograma-legenda-dot { width: 10px; height: 10px; border-radius: 3px; flex: 0 0 auto; }
.cronograma-legenda-dot.coleta { background: var(--danger); }
.cronograma-legenda-dot.devolucao { background: var(--ok); }

/* --- importar / exportar preços --- */
.form-modal textarea {
  display: block; width: 100%; margin-top: var(--space-2xs); resize: vertical;
}
.form-modal input[type="file"] { display: block; margin-top: var(--space-2xs); }
.import-dica { margin: -6px 0 12px; font-size: var(--fs-apoio); }
.import-previa { margin: 2px 0; max-height: 220px; overflow-y: auto; border: 1px solid var(--border); border-radius: var(--radius-md); padding: 8px 10px; }
.import-previa:empty { display: none; }
.import-previa > p { margin: 0 0 6px; }
.import-previa .mini td { padding: 5px 4px; }
.import-previa tr.import-erro td { color: var(--busy); }

/* seleção de categorias/peças no export */
.fld-sub { display: block; font-size: var(--fs-corpo); margin: 4px 0; color: var(--ink); }
.export-sel-acoes { display: flex; flex-wrap: wrap; gap: var(--space-lg); margin: 2px 0 8px; }
.export-arvore {
  border: 1px solid var(--border); border-radius: var(--radius-md); padding: 6px 4px;
  max-height: 240px; overflow-y: auto; margin-bottom: 14px;
}
.export-cat + .export-cat { border-top: 1px solid var(--border); margin-top: var(--space-3xs); padding-top: var(--space-3xs); }
.export-cat-h { display: flex; align-items: center; gap: 7px; padding: 6px 8px; font-weight: 600; font-size: var(--fs-corpo); color: var(--brand-navy); }
.export-peca { display: flex; align-items: center; gap: 7px; padding: 4px 8px 4px 30px; font-size: var(--fs-corpo); color: var(--ink); }
.export-arvore input[type="checkbox"] { width: auto; margin: 0; flex: 0 0 auto; }
.export-sem-preco { border: 1px solid var(--border); border-radius: var(--radius-md); padding: 2px 12px 10px; margin: 0 0 4px; }
.export-sem-preco legend { font-size: var(--fs-apoio); font-weight: 600; color: var(--muted); padding: 0 4px; }
.export-sem-preco .check { margin: 6px 0 0; }

/* --- toasts (avisos no rodapé) --- */
.toast-area {
  position: fixed;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column-reverse;
  align-items: center;
  gap: var(--space-sm);
  z-index: 120;
  pointer-events: none;
  width: max-content;
  max-width: 92vw;
}
.toast {
  pointer-events: auto;
  cursor: pointer;
  position: relative;
  max-width: 440px;
  padding: 11px 16px 11px 38px;
  border-radius: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 1px solid var(--border);
  box-shadow: var(--shadow-modal);
  font-size: var(--fs-corpo);
  line-height: 1.35;
  color: var(--ink);
}
.toast::before {
  position: absolute;
  left: 13px;
  top: 11px;
  font-weight: 700;
  font-size: var(--fs-corpo);
}
.toast-ok { border-left-color: var(--ok); }
.toast-ok::before { content: "✓"; color: var(--ok); }
.toast-erro { border-left-color: var(--danger); color: var(--danger); }
.toast-erro::before { content: "!"; color: var(--danger); }
.toast-saindo { opacity: 0; transform: translateY(6px); }

/* --- Dashboard (gráfico de Coletadas/Devolvidas/Relavagem, issue #23) --- */
.dashboard-totais {
  flex-basis: 100%;
  display: flex;
  align-items: stretch;
  gap: 32px;
  flex-wrap: wrap;
}
.dashboard-total-item { display: flex; flex-direction: column; gap: var(--space-2xs); justify-content: center; }
.dashboard-total-rotulo { display: flex; align-items: center; gap: var(--space-xs); font-size: var(--fs-caixa-alta); font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: var(--ls-caixa-alta); }
.dashboard-total-rotulo svg { flex: 0 0 auto; }
/* O número é o motivo desta tela existir — maior e com a cor funcional da
   própria série no gráfico logo abaixo (não decoração: mesma legenda). O
   rótulo continua discreto de propósito — se os dois gritassem, nenhum
   seria o ponto forte. */
.dashboard-total-valor {
  font-size: var(--fs-destaque);
  font-weight: 700;
  letter-spacing: -.01em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--brand-navy);
  white-space: nowrap;
}
/* separa um indicador do outro — `border-left` no item, não um `<span>` à
   parte, pra não sobrar uma barra órfã quando a linha quebra (tela estreita). */
.dashboard-total-item + .dashboard-total-item { border-left: 1px solid var(--border); padding-left: var(--space-2xl); }
.dashboard-grafico-card { flex-basis: 100%; }
.grafico-legenda { display: flex; gap: var(--space-xl); flex-wrap: wrap; margin: 0 0 14px; font-size: var(--fs-corpo); }
.grafico-legenda-item { display: inline-flex; align-items: center; gap: var(--space-xs); }
.grafico-legenda-cor { display: inline-block; width: 12px; height: 12px; border-radius: 3px; }
/* Legenda clicável (Dashboard): cada item mostra/oculta a própria série. A
   oculta fica na legenda, apagada e riscada, para poder voltar. */
.grafico-legenda-botao {
  border: 1px solid transparent;
  background: none;
  padding: 2px var(--space-sm);
  margin: -2px calc(var(--space-sm) * -1);
  border-radius: var(--radius-sm);
  color: var(--ink);
  font: inherit;
  cursor: pointer;
}
.grafico-legenda-botao:hover { border-color: var(--border); }
.grafico-legenda-botao:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
.grafico-legenda-botao[aria-pressed="false"] { color: var(--muted); text-decoration: line-through; }
.grafico-legenda-botao[aria-pressed="false"] .grafico-legenda-cor { opacity: .3; }
.grafico-barras { max-width: 100%; }
.grafico-barras.grafico-com-rolagem { overflow-x: auto; }
.grafico-barras svg { display: block; }

@media (prefers-reduced-motion: no-preference) {
  .toast { animation: toast-entra .18s ease-out; }
  .toast-saindo { transition: opacity .3s ease, transform .3s ease; }
}
@keyframes toast-entra {
  from { opacity: 0; transform: translateY(12px); }
}

/* A folha para PDF/impressão é montada num <iframe> isolado por
   `imprimirCanvas` (`_folha-canvas.ts`), com o próprio `@page { margin: 0 }`
   lá dentro — nada de esconder o app por `@media print` aqui. */

/* --- responsivo ---
   O menu vira gaveta por LARGURA (tela estreita) ou por ALTURA (celular
   deitado: 915×412 passa dos 900px de largura, mas não tem altura pro menu
   fixo). Por isso as duas condições. */
@media (max-width: 900px), (max-height: 560px) {
  .layout { grid-template-columns: 1fr; }
  .sidebar {
    position: fixed;
    top: 4px;
    bottom: 0;
    left: 0;
    width: min(84vw, var(--sidebar-w));
    transform: translateX(-100%);
    transition: transform .2s ease;
    z-index: 40;
    box-shadow: var(--shadow-drawer);
  }
  .layout.menu-aberto .sidebar { transform: translateX(0); }
  .layout.menu-aberto .menu-overlay {
    display: block;
    position: fixed;
    inset: 4px 0 0 0;
    background: rgba(15, 43, 86, .4);
    z-index: 30;
  }
  .menu-fechar { display: flex; }
  .menu-toggle { display: block; }
}
/* Achado de acessibilidade: era a única transição de transform (não só
   opacidade/cor) do sistema sem essa guarda — o slide da gaveta inteira é
   o gatilho mais comum de desconforto vestibular entre as animações do app. */
@media (prefers-reduced-motion: reduce) {
  .sidebar { transition: none; }
}

/* Tela baixa (celular deitado): devolve altura pra lista do menu. */
@media (max-height: 560px) {
  .sidebar { padding: 10px 12px; gap: var(--space-sm); }
  .brand { padding: 2px 2px 8px; }
  .brand img { width: 150px; }
  .menu-toolbar { display: none; }
  .modal-overlay { padding: 2vh 12px 12px; padding: 2dvh 12px 2dvh; }
  .modal-box { max-height: 94vh; max-height: calc(100dvh - 4dvh); }
}

/* Alvo de toque do menu (independente do card de tabela, que agora troca a
   900px — ver bloco abaixo). Os ajustes de table-layout/overflow que
   viviam aqui viraram letra morta: abaixo de 900px a tabela já é
   `display:block`/grade de card, não `<table>` de verdade, então
   table-layout/overflow de célula não têm mais efeito. */
@media (max-width: 700px) {
  .menu li button { min-height: 40px; display: flex; align-items: center; }
  .menu-parent, .menu summary { min-height: 42px; display: flex; align-items: center; }
}

@media (max-width: 560px) {
  .content { padding: 14px; }
  .topbar { padding: 10px 14px; }
  .btn-backup { padding: 0 10px; }
  .topbar-right { gap: var(--space-sm); }
  .topo-usuario { display: none; }
  /* filtros e busca ocupam a linha inteira — alvos de toque decentes */
  .barra-filtros { gap: var(--space-md); }
  .barra-filtros > .filtro { flex: 1 1 100%; }
  .barra-filtros-fim { margin-left: 0; width: 100%; }
  .barra-filtros-fim > * { flex: 1 1 auto; }
  .busca-lista input { max-width: none; }
}
/* Breakpoint alinhado ao do menu (900px, ver acima) — abaixo dele a
   navegação já virou gaveta/mobile, então a tabela também troca pra card;
   duas larguras de "modo mobile" diferentes (menu em 900, tabela em 600)
   era a raiz do tablet (820px) ficar preso num meio-termo ruim: menu já
   em modo celular, tabela ainda em modo desktop com rolagem horizontal. */
@media (max-width: 900px) {
  table.grid, table.grid thead, table.grid tbody, table.grid tfoot, table.grid th, table.grid td, table.grid tr {
    display: block;
  }
  /* table.grid tem min-width:480px como regra de base (pro modo tabela de
     verdade, no desktop) — em modo card isso forçava a linha inteira a
     ficar mais larga que a tela num celular de 390px, e o valor à direita
     (com justify-content:space-between) ia parar fora da área visível,
     sem rolagem nenhuma avisando que tinha mais coisa ali. */
  /* Em modo card quem tem contorno é cada linha: a borda/fundo da tabela
     de computador em volta de todos os cards virava um segundo contorno. */
  table.grid { min-width: 0; border: 0; border-radius: 0; background: none; }
  table.grid thead { display: none; }
  table.grid tbody tr:last-child, table.grid tfoot tr:last-child { margin-bottom: 0; }
  table.grid tr {
    border: 1px solid var(--border);
    margin-bottom: var(--space-lg);
    border-radius: var(--radius-lg);
    padding: var(--space-lg);
    background: var(--surface);
    /* Grade de 2 colunas — no tablet (820px) sobra largura de sobra pra um
       card de celular de coluna só, então cada linha vira duas colunas de
       "rótulo: valor" lado a lado em vez de uma pilha comprida. Em celular
       de verdade (@media 560px abaixo) volta pra coluna única. min-width:0
       nos itens da grade evita o mesmo estouro de largura, dessa vez via
       conteúdo mínimo implícito de uma célula (ex.: os dois botões de
       ação) — sem isso a grade toda cresce pra caber a célula mais larga. */
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px 16px;
    min-width: 0;
  }
  table.grid td {
    border-bottom: none;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: baseline;
    gap: 2px 10px;
    font-size: var(--fs-corpo);
    min-width: 0;
  }
  /* Célula com valor de mais de uma linha (ex.: data + "prazo ..." embaixo,
     na coluna Coleta e Prazo) — sem isso a segunda linha ficava espremida
     e cortada na grade de 2 colunas do tablet. Cai pra linha de baixo em
     vez de clipar. */
  table.grid td > span:last-child { flex: 1 1 auto; min-width: 0; text-align: right; }
  /* Coluna de ações ocupa a largura toda — botões não cabem espremidos na
     metade de uma grade de 2 colunas. */
  table.grid td.acoes { grid-column: 1 / -1; }
  /* Linha de total (linhaTotalTabela em ui.ts): o rótulo ("Total · N
     contas") também ocupa a largura toda, mesmo motivo da coluna de ações —
     e o <td> de preenchimento (colspan, sem conteúdo) simplesmente some no
     card em vez de deixar um espaço em branco sobrando na grade. */
  table.grid tfoot td.linha-total-rotulo { grid-column: 1 / -1; }
  table.grid tfoot td:empty { display: none; }
  /* Rótulo da coluna (de data-th, escrito por tabelaPaginada em ui.ts) —
     sem isso um número como "4" ou "130" fica solto, sem dizer o que é.
     Célula sem data-th (coluna de ações: os próprios botões já dizem o que
     fazem) não ganha rótulo — attr() vazio não gera conteúdo. */
  table.grid td[data-th]::before {
    content: attr(data-th);
    flex: 0 0 auto;
    font-size: var(--fs-caixa-alta);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--ls-caixa-alta);
    color: var(--muted);
  }
}
@media (max-width: 560px) {
  /* Celular de verdade: uma coluna só, senão rótulo+valor+rótulo+valor
     lado a lado fica apertado demais pra ler. */
  table.grid tr { grid-template-columns: 1fr; }
}

/* --- Cor de texto dos controles (docs/design/ui.md, "Cores") -----------
   Valor digitado ou escolhido = texto principal (--ink), em formulário e em
   filtro. Ausência de valor (placeholder, "dd/mm/aaaa", "--:--", "Nenhum", "—") =
   texto secundário (--muted), para um campo preenchido nunca parecer vazio.
   Desabilitado = --texto-desabilitado. Fica no fim do arquivo de propósito:
   é a base de todo controle, e os casos de ausência precisam vencer as
   regras de .campo/.filtro que definem a cor do valor. */
input, select, textarea { color: var(--ink); }
::placeholder { color: var(--muted); opacity: 1; }
select:has(> option:checked[data-vazio]),
input:is([type="date"], [type="time"])[data-vazio],
.multi-select .ms-resumo.ms-vazio { color: var(--muted); }
/* Desabilitado vence ausência: a lista travada com "—" também fica desabilitada. */
:is(input, select, textarea):disabled,
select:disabled:has(> option:checked[data-vazio]),
input:is([type="date"], [type="time"])[data-vazio]:disabled { color: var(--texto-desabilitado); }

/* Tela de toque (iPhone/iPad e afins): controle com menos de 16px faz o
   Safari dar zoom na página ao tocar no campo. */
@media (pointer: coarse) {
  :root { --fs-controle: 1rem; --altura-controle: 44px; --altura-compacta: 44px; }
  .btn-link, .btn-registro, .check, .ms-item,
  label:has(> input[type="checkbox"], > input[type="radio"]) { min-height: 44px; }
  .btn-link, .btn-registro { display: inline-flex; align-items: center; }
}
