:root {
  color-scheme: light;
  --surface-1: #fcfcfb;
  --page: #f9f9f7;
  --text-primary: #0b0b0b;
  --text-secondary: #52514e;
  --text-muted: #898781;
  --gridline: #e1e0d9;
  --baseline: #c3c2b7;
  --border: rgba(11, 11, 11, 0.10);

  --series-1: #2a78d6; /* coleta */
  --series-2: #eb6834; /* embarque */

  --status-good: #0ca30c;
  --status-warning: #fab219;
  --status-serious: #ec835a;
  --status-critical: #d03b3b;
}

@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;
    --surface-1: #1a1a19;
    --page: #0d0d0d;
    --text-primary: #ffffff;
    --text-secondary: #c3c2b7;
    --text-muted: #898781;
    --gridline: #2c2c2a;
    --baseline: #383835;
    --border: rgba(255, 255, 255, 0.10);

    --series-1: #3987e5;
    --series-2: #d95926;

    --status-good: #0ca30c;
    --status-warning: #fab219;
    --status-serious: #ec835a;
    --status-critical: #e66767;
  }
}

* { box-sizing: border-box; }

[hidden] { display: none !important; }

body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  background: var(--page);
  color: var(--text-primary);
}

.app { min-height: 100vh; }

.topbar {
  display: flex;
  align-items: center;
  gap: 32px;
  padding: 14px 24px;
  background: var(--surface-1);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 10;
}

.brand { font-weight: 600; font-size: 16px; }
.brand-sub { color: var(--text-muted); font-weight: 400; }

/* Selo do espelho: discreto enquanto está tudo em dia, visível quando não
   está. Recessivo de propósito — o normal é o espelho estar fresco, e um aviso
   que grita todo dia deixa de ser lido no dia em que importa. */
.espelho-selo {
  margin-left: auto;
  font-size: 12px;
  color: var(--text-muted);
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 6px;
  /* Sem isto o selo era intransigente: em dia de aviso longo ("dados de há 11
     min · 40 linha(s) atrás do SAGI") ele somava 254px, nada na barra podia
     encolher e a PÁGINA inteira ganhava rolagem lateral em tela de tablet. A
     bolinha nunca encolhe; o texto cede antes de empurrar o documento. */
  min-width: 0;
}
.espelho-selo::before { flex: none; }
/* O selo não entra no rateio do encolhimento — as abas rolam, ele não tem para
   onde ir. Sem isto, "dados de há 6 min" virava "dados d…" em 820px só porque a
   barra estava apertada, e é uma informação de 17 caracteres. O teto de 30vw é
   para o caso patológico (aviso longo em tela estreita): aí ele corta com
   reticências, com o texto inteiro no title, em vez de empurrar a página. */
.espelho-selo { flex-shrink: 0; }
.selo-texto { overflow: hidden; text-overflow: ellipsis; max-width: 30vw; }
.espelho-selo::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--status-good);
}
.espelho-selo.atrasado { color: var(--status-warning); }
.espelho-selo.atrasado::before { background: var(--status-warning); }
.espelho-selo.parado { color: var(--status-critical); font-weight: 500; }
.espelho-selo.parado::before { background: var(--status-critical); }

/* A rolagem das abas não é só do celular: sete abas mais o selo mais o botão
   de sair não cabem em 820px tampouco. `min-width: 0` é o que permite ao item
   flex encolher abaixo do próprio conteúdo — sem ele a barra só sabia crescer. */
.tabs {
  display: flex;
  gap: 4px;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.tabs::-webkit-scrollbar { display: none; }

.tab {
  border: none;
  background: transparent;
  color: var(--text-secondary);
  padding: 8px 14px;
  border-radius: 8px;
  font-size: 14px;
  cursor: pointer;
}
.tab:hover { background: var(--page); }
.tab.active { background: var(--series-1); color: white; }

.content { padding: 24px; max-width: 1200px; margin: 0 auto; }

.panel { display: none; }
.panel.active { display: block; }

.coming-soon {
  padding: 60px 0;
  text-align: center;
  color: var(--text-muted);
  font-size: 15px;
}

.filters {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: 16px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 16px;
  margin-bottom: 20px;
}

.filter-group {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.filter-group.grow { flex: 1; min-width: 200px; }

.filter-group label {
  font-size: 12px;
  color: var(--text-muted);
}

.checkbox-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  color: var(--text-primary);
  padding: 7px 0;
  cursor: pointer;
  white-space: nowrap;
}
.checkbox-label input { width: 16px; height: 16px; cursor: pointer; }

.filter-group select,
.filter-group input {
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--page);
  color: var(--text-primary);
  font-size: 14px;
}

.state-msg {
  text-align: center;
  padding: 40px;
  color: var(--text-muted);
}
.state-msg.error { color: var(--status-critical); }

.kpi-row {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr 1fr;
  gap: 12px;
  margin-bottom: 20px;
}

.stat-tile {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 16px;
  display: flex;
  align-items: center;
  gap: 12px;
}
.stat-tile.hero { flex-direction: column; align-items: flex-start; justify-content: center; }

/* A grade padrão tem cinco colunas, com a primeira maior — desenhada para o
   "1 destaque + 4 números" de Compras e Vendas. O Fiscal tem quatro números do
   mesmo peso (média, total, parcelamento, último mês): nenhum é o destaque, e
   com cinco colunas sobrava uma vazia.

   Dentro de um min-width de propósito. Escrita solta, esta regra tem id e por
   isso vencia por especificidade a regra de duas colunas dos 900px para baixo —
   os quatro cartões continuavam lado a lado no celular e o terceiro saía
   cortado fora da tela. */
@media (min-width: 901px) {
  #panel-fiscal .kpi-row { grid-template-columns: repeat(4, 1fr); }
  #panel-fiscal .stat-tile.hero .stat-value { font-size: 26px; }
}

.stat-label {
  font-size: 12px;
  color: var(--text-muted);
}
.stat-value {
  font-size: 28px;
  font-weight: 600;
  font-variant-numeric: proportional-nums;
}
.stat-tile.hero .stat-value { font-size: 34px; }
.stat-sub { font-size: 12px; color: var(--text-secondary); margin-top: 4px; }

.stat-icon {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-weight: 700;
  color: white;
  flex-shrink: 0;
}
.stat-icon.good { background: var(--status-good); }
.stat-icon.info { background: var(--series-1); }
.stat-icon.warning { background: var(--status-warning); color: #3a2900; }
.stat-icon.critical { background: var(--status-critical); }

.section-title {
  font-size: 16px;
  margin: 32px 0 16px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
}
.section-sub {
  font-size: 13px;
  color: var(--text-muted);
  margin: -8px 0 16px;
}

.chart-card, .table-card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 16px 20px;
  margin-bottom: 20px;
}

.chart-header, .table-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
}
.chart-header h3, .table-header h3 { margin: 0; font-size: 15px; }

.legend { display: flex; gap: 16px; }
.legend-item { font-size: 13px; color: var(--text-secondary); display: flex; align-items: center; gap: 6px; }
.swatch { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }

.chart { width: 100%; overflow-x: auto; }
.chart svg { display: block; }

.bar-group:hover rect { opacity: 0.85; }
.bar-tooltip {
  position: absolute;
  background: var(--text-primary);
  color: var(--surface-1);
  font-size: 12px;
  padding: 6px 10px;
  border-radius: 6px;
  pointer-events: none;
  white-space: nowrap;
  transform: translate(-50%, -110%);
  z-index: 20;
}

.table-count { font-size: 12px; color: var(--text-muted); }
.table-header-right { display: flex; align-items: center; gap: 14px; }

/* ---- Custos tab: parameters panel ---- */
.param-card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 16px 20px;
  margin-bottom: 20px;
}
.param-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}
.param-header h3 { margin: 0; font-size: 15px; }

.btn-link {
  border: none;
  background: transparent;
  color: var(--series-1);
  font-size: 13px;
  cursor: pointer;
  padding: 4px 8px;
}
.btn-link:hover { text-decoration: underline; }

.granularidade-toggle { display: flex; gap: 4px; }
.btn-toggle {
  border: 1px solid var(--border);
  background: var(--page);
  color: var(--text-secondary);
  font-size: 12px;
  padding: 5px 12px;
  border-radius: 6px;
  cursor: pointer;
}
.btn-toggle.active { background: var(--series-1); color: white; border-color: var(--series-1); }

.param-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 12px;
}
.param-item { display: flex; flex-direction: column; gap: 2px; }
.param-item .label { font-size: 11px; color: var(--text-muted); }
.param-item .value { font-size: 16px; font-weight: 600; }
.param-item input {
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--page);
  color: var(--text-primary);
  font-size: 14px;
  width: 100%;
}
.param-edit { margin-top: 12px; }
.param-actions { grid-column: 1 / -1; display: flex; gap: 8px; margin-top: 4px; }
.btn-primary, .btn-secondary {
  padding: 7px 14px;
  border-radius: 8px;
  font-size: 13px;
  cursor: pointer;
  border: 1px solid transparent;
}
.btn-primary { background: var(--series-1); color: white; }
.btn-secondary { background: transparent; color: var(--text-secondary); border-color: var(--border); }

/* ---- Custos tab: editable table cells ---- */
.cell-input {
  width: 64px;
  padding: 4px 6px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--page);
  color: var(--text-primary);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.row-historico .cell-input { opacity: 0.5; }
.row-dirty { background: color-mix(in srgb, var(--status-warning) 8%, transparent); }

.btn-save-row {
  padding: 4px 10px;
  border-radius: 6px;
  border: 1px solid var(--series-1);
  background: transparent;
  color: var(--series-1);
  font-size: 11px;
  cursor: pointer;
}
.btn-save-row:disabled { opacity: 0.3; cursor: default; border-color: var(--border); color: var(--text-muted); }

.flag-badge {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 999px;
  font-size: 11px;
  margin: 1px;
  background: color-mix(in srgb, var(--status-warning) 20%, transparent);
  color: #8a5a00;
}
.flag-badge.info {
  background: var(--page);
  color: var(--text-muted);
  border: 1px solid var(--border);
}
.origem-badge {
  font-size: 10px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.table-scroll { overflow-x: auto; max-height: 480px; overflow-y: auto; }

/* Sombra na borda que diz "tem mais coisa para o lado".
   No celular a tabela de Custos mostrava Ordem, Data, Fornecedor e Motorista —
   peso, km e custo ficavam fora da tela. Rolavam, mas nada na tela dizia isso,
   e quem não arrastasse por acaso concluía que o app não mostra custo.

   As quatro camadas são o truque clássico de sombra de rolagem: as duas
   primeiras são tampas da cor do card, presas ao conteúdo (`local`), e as duas
   últimas são as sombras, presas ao quadro (`scroll`). Quando a rolagem está
   na ponta, a tampa cobre a sombra daquele lado; quando não há transbordo
   nenhum, as duas tampas cobrem tudo. Some sozinho na hora certa, sem uma
   linha de JavaScript medindo largura. */
.table-scroll {
  background-image:
    linear-gradient(to right, var(--surface-1) 30%, transparent),
    linear-gradient(to left,  var(--surface-1) 30%, transparent),
    linear-gradient(to right, rgba(11, 11, 11, .16), transparent),
    linear-gradient(to left,  rgba(11, 11, 11, .16), transparent);
  background-position: 0 0, 100% 0, 0 0, 100% 0;
  background-repeat: no-repeat;
  background-size: 32px 100%, 32px 100%, 14px 100%, 14px 100%;
  background-attachment: local, local, scroll, scroll;
}

table { width: 100%; border-collapse: collapse; font-size: 13px; }

/* Par de rótulos de cabeçalho: o longo na tela grande, o curto no celular.
   Trocar o texto por CSS puro não dá, então os dois ficam no HTML e um deles
   some — o mesmo caminho já usado nos rótulos de unidade. */
.rotulo-curto { display: none; }
thead th {
  position: sticky;
  top: 0;
  background: var(--surface-1);
  text-align: left;
  padding: 8px 10px;
  color: var(--text-muted);
  font-weight: 500;
  border-bottom: 1px solid var(--gridline);
}
tbody td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--gridline);
  color: var(--text-secondary);
  white-space: nowrap;
}
tbody tr:hover { background: var(--page); }

/* Supplier names run to 40+ chars ("LABORPRINT GRAFICA E EDITORA EIRELI") and
   the Viagens table already has 16 columns, so a full-width column would push
   Custo/kg off screen. Truncated with the full name on the cell's title. */
/* A empresa não é mais um filtro entre outros: ela decide de qual base tudo na
   aba veio. Destacada para que ninguém leia um número sem saber de quem é. */
.select-empresa {
  font-weight: 600;
  border-color: var(--series-1);
}

/* Só aparece com "Todas as empresas" selecionado. Fora do modo combinado
   seria uma coluna inteira repetindo a mesma palavra em todas as linhas. */
.col-empresa { display: none; }
.modo-todas .col-empresa {
  display: table-cell;
  color: var(--text-muted);
  font-size: 12px;
  max-width: 130px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.col-fornecedor {
  max-width: 190px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.status-pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 500;
}
.status-pill.FINALIZADO { background: color-mix(in srgb, var(--status-good) 15%, transparent); color: var(--status-good); }
.status-pill.EM_ANDAMENTO { background: color-mix(in srgb, var(--series-1) 15%, transparent); color: var(--series-1); }
.status-pill.AGUARDANDO { background: color-mix(in srgb, var(--status-warning) 20%, transparent); color: #8a5a00; }
.status-pill.ATRASADO { background: color-mix(in srgb, var(--status-critical) 15%, transparent); color: var(--status-critical); }

@media (max-width: 900px) {
  .kpi-row { grid-template-columns: 1fr 1fr; }
  /* Cinco cartões numa grade de dois deixavam o último — "Atrasado", na
     Logística — sozinho, ocupando meia linha à toa. Numa contagem ímpar o
     último atravessa as duas colunas. Fica aqui, e não no bloco do celular,
     porque a grade vira de duas colunas já nos 900px. */
  .kpi-row > .stat-tile:last-child:nth-child(odd) { grid-column: 1 / -1; }
}

/* Aba Fiscal. "a pagar" é estado, não valor — fica em itálico recessivo para não
   ser lido como número. A diferença fora de 3% ganha cor porque é o único sinal
   da tabela que pede ação: ou a nota está errada, ou a guia está. */
.fi-pendente { font-style: italic; color: var(--text-muted); }
.fi-fora { color: var(--status-warning); font-weight: 500; }

.valor-negativo { color: var(--status-critical); }

/* ---- Visão Geral: o resumo diário ---- */
.vg-cabecalho {
  display: flex;
  align-items: baseline;
  gap: 14px;
  margin-bottom: 18px;
}
.vg-data { font-size: 26px; font-weight: 600; }
/* O botão é ação sobre o relatório, não filtro dele — na barra de filtros ele
   quebrava para uma segunda linha e ainda sugeria que mudava o que se vê. */
.vg-cabecalho #vg-copiar { margin-left: auto; align-self: center; }
.vg-util {
  font-size: 14px;
  color: white;
  background: var(--series-1);
  padding: 3px 12px;
  border-radius: 999px;
}
/* O spread é a linha de chegada da página inteira — destacado, e com sinal:
   negativo significa ter vendido mais barato do que comprou naquele dia. */
/* Variação contra o ano anterior, sob o número do ano corrente. */
.vg-delta { font-size: 11px; font-weight: 500; margin-top: 1px; }
.vg-delta.bom  { color: var(--status-good); }
.vg-delta.ruim { color: var(--status-critical); }
/* Δ kg é quase sempre negativo (o que entrou e não saiu virou estoque), então
   não recebe cor: vermelho ali leria como problema, e não é. */

/* Aviso de boleto em aberto: fica acima de tudo porque muda como a página
   inteira deve ser lida, não é um detalhe de uma tabela. */
.vg-alerta {
  display: inline-block;
  background: color-mix(in srgb, var(--status-warning) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--status-warning) 40%, transparent);
  border-radius: 999px;
  padding: 4px 12px;
  margin-bottom: 14px;
  font-size: 12px;
  color: var(--text-secondary);
}
.vg-alerta-nota { color: var(--text-secondary); }

/* ---- Controles: uma verificação por card, cada uma rodando sob demanda ---- */
.controle-card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 18px 20px;
  margin-bottom: 20px;
}
.controle-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 24px;
}
.controle-header h3 { margin: 0; font-size: 15px; }
.controle-header .btn-primary { flex-shrink: 0; }
.controle-card.vazio { border-style: dashed; background: transparent; }
.btn-tirar {
  border: none; background: transparent; cursor: pointer;
  color: var(--text-muted); font-size: 16px; line-height: 1;
  padding: 2px 6px; border-radius: 6px;
}
.btn-tirar:hover { background: var(--page); color: var(--status-critical); }

/* ---- Visão Geral: três blocos empilhados ---- */
/* A página tem quatro colunas e nada mais. Esticada na largura da janela, cada
   número ficava a 300px do seu próprio cabeçalho e a comparação entre empresas
   — que é o ponto da tela — exigia varrer o olho pela linha inteira. Limitar a
   largura aproxima rótulo, empresas e total num bloco que se lê de uma vez. */
/* A barra de filtros acompanha, senão ela sozinha define a largura da página e
   os cards estreitos parecem recortados dentro dela. */
#panel-visao-geral .filters,
#vg-body { max-width: 720px; }
/* Grade fixa: o rótulo da métrica é curto ("kg", "R$/kg") e não deve puxar a
   coluna. Sem isso o navegador dava um quarto da largura ao rótulo e jogava as
   empresas para a direita, longe do próprio cabeçalho. */
/* Régua entre os blocos: separa sem precisar de espaço em branco largo, e
   mantém o card compacto o bastante para dia e mês caberem juntos na tela. */
.vg-bloco + .vg-bloco {
  border-top: 1px solid var(--border);
  margin-top: 9px;
  padding-top: 9px;
}
.vg-bloco table {
  width: 100%;
  font-variant-numeric: tabular-nums;
  table-layout: fixed;
  border-collapse: collapse;
}
.vg-bloco col.rotulo { width: 132px; }

/* A régua colorida atravessa o cabeçalho inteiro, não só a célula do título. */
.vg-bloco thead th {
  padding: 0 12px 7px;
  border-bottom: 2px solid var(--gridline);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--text-muted);
  text-align: right;
}
.vg-bloco thead th:first-child {
  text-align: left;
  color: var(--text-primary);
}
.vg-bloco.compra    thead th { border-bottom-color: var(--series-1); }
.vg-bloco.venda     thead th { border-bottom-color: var(--series-2); }
/* Resultado fecha a página, então a régua dele é a mais escura das três. */
.vg-bloco.resultado thead th { border-bottom-color: var(--text-primary); }

.vg-bloco tbody th {
  text-align: left;
  font-weight: 400;
  color: var(--text-muted);
  font-size: 13px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--gridline);
  white-space: nowrap;
}
.vg-bloco tbody td {
  text-align: right;
  padding: 8px 12px;
  border-bottom: 1px solid var(--gridline);
  font-variant-numeric: tabular-nums;
}
.vg-bloco tbody tr:last-child th,
.vg-bloco tbody tr:last-child td { border-bottom: none; }

/* O total é a leitura do grupo — mais forte que as empresas, e encostado na
   borda direita, que é para onde o olho vai depois de comparar as duas. */
.vg-col-total { font-weight: 600; color: var(--text-primary); }
thead .vg-col-total { color: var(--text-primary); }

/* Spread é a conclusão da página. */
.vg-linha-spread th { color: var(--text-primary); font-weight: 500; }
.vg-linha-spread td { font-size: 16px; font-weight: 600; color: var(--text-primary); }

/* ---- celular ----
   O dashboard nasceu para tela de mesa e a Visão Geral é a única aba que faz
   sentido no bolso: é o fechamento que o pai do Gustavo confere de manhã.
   Aqui só se recupera espaço horizontal — nada de esconder número, porque na
   tela pequena é justamente o número que a pessoa veio ver. */
@media (max-width: 560px) {
  .content { padding: 14px; }

  /* As sete abas não cabem. Rolagem lateral em vez de quebra de linha: uma
     barra de duas alturas empurraria o conteúdo para fora da primeira tela. */
  .topbar {
    gap: 14px;
    padding: 10px 14px;
    align-items: center;
  }
  .brand { font-size: 14px; white-space: nowrap; }
  .brand-sub { display: none; }
  .tab { padding: 7px 11px; font-size: 13px; white-space: nowrap; }

  /* Cabeçalho de tabela com busca + contadores + exportar: os três lado a lado
     não cabem, e o `space-between` os empurrava até "144 já resolvida(s)"
     quebrar em duas linhas encostado no campo. Em duas fileiras cada um tem a
     largura de que precisa. */
  .table-header { flex-wrap: wrap; gap: 8px; }
  .table-header-right { gap: 10px; flex-wrap: wrap; }

  /* No celular o selo sai da barra inteiro — nem a bolinha fica. Antes ele já
     era só o ponto, e ainda assim custava caro: ele e o "sair" formavam 102px de
     zona morta na direita, um quarto da tela, onde o swipe não pega nas abas. Num
     iPhone pequeno, com 220px de faixa visível para 598px de abas, rolar virava
     questão de acertar a região certa.
     Ele reaparece — com texto — quando o dado está atrasado ou o sincronizador
     parou. É o único momento em que o selo tem algo a dizer, e aí ele vale o
     espaço: um número velho tem a mesma cara de confiança que um novo. */
  .espelho-selo { display: none; }
  .espelho-selo.atrasado,
  .espelho-selo.parado { display: flex; }
  /* Em degraus, porque o espaço aqui é disputado: em dia o selo não existe;
     atrasado é a bolinha âmbar sozinha (7px, avisa sem cobrar); parado ganha o
     texto. Deixar o texto já no atraso comprimia as abas de 249px para 75px —
     trocava a navegação por um aviso que a cor já dava.
     `com-falha` é a exceção, e por um motivo: a bolinha diz que algo está
     diferente, e no atraso comum isso basta porque a única leitura possível é
     "o dado está velho". Com tabela fora do ar a bolinha fica ambígua — atraso
     de rotina e ORDEM que parou de sincronizar acendem a mesma luz âmbar, e só
     o texto separa as duas. Aqui o nome da tabela é a informação. */
  .espelho-selo .selo-texto { display: none; }
  .espelho-selo.parado .selo-texto,
  .espelho-selo.com-falha .selo-texto { display: inline; }
  /* E aí o texto cede largura em vez de esmagar as abas: parada é para ser lida,
     mas não ao ponto de impedir de sair da aba. */
  .espelho-selo.parado,
  .espelho-selo.com-falha { flex-shrink: 1; min-width: 0; }

  /* Sem o selo, a faixa de abas encosta no "sair". Menos respiro entre os itens
     devolve o resto do vão para a rolagem. */
  .topbar { gap: 10px; }

  .filters { padding: 12px; gap: 10px; }
  .chart-card, .table-card { padding: 14px 12px; }

  /* Numa tabela de cinco colunas, os 20px de respiro lateral de cada célula
     somam 100px — quase um terço da tela do celular gasto em espaço em branco.
     E quem estava definindo a largura já não era o dado: "Faturamento" pedia
     98px de cabeçalho para uma célula de 60. O cabeçalho pode quebrar em duas
     linhas; o número, não. */
  table { font-size: 12px; }
  thead th { padding: 6px 3px; white-space: normal; }
  tbody td { padding: 8px 3px; }

  /* Mesmo encurtado, "Suleste Ambiental" pedia 106px — um terço da tela para
     a coluna que o olho menos precisa medir. Corta com reticências; o nome
     inteiro continua no title da célula. */
  /* 70px é o que sobra depois das quatro colunas de número. Encolheu de 74
     quando o ranking passou a somar os cadastros: juntar "APARAS DE ONDULADO
     I" com os dois "Papelão I" leva o peso de 2,4 para 5,3 milhões, e um
     dígito a mais na coluna tem que sair de algum lugar. */
  #v-ranking-clientes td:first-child,
  #v-ranking-produtos td:first-child,
  #p-ranking-fornecedores td:first-child,
  #p-ranking-produtos td:first-child {
    max-width: 70px;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* "Faturamento" é uma palavra só: não quebra em duas linhas e sozinha pedia
     83px para uma célula de 60. Aqui ela cede lugar a "Valor". */
  .rotulo-largo { display: none; }
  .rotulo-curto { display: inline; }

  /* Em meia largura o número não cabia inteiro: "R$ 0,0461" quebrava com o
     "R$" numa linha e o valor na outra. */
  .stat-value { font-size: 22px; }
  .stat-tile.hero .stat-value { font-size: 26px; }
  .stat-tile { padding: 13px; gap: 10px; }


  /* Data e dia útil na primeira linha, botão sozinho na segunda: espremido ao
     lado do título ele virava três linhas de texto dentro da borda. */
  .vg-cabecalho { flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
  .vg-data { font-size: 20px; }
  .vg-util { font-size: 12px; padding: 2px 10px; white-space: nowrap; }
  .vg-cabecalho #vg-copiar { margin-left: 0; width: 100%; }

  /* O rótulo da métrica é curto ("kg", "Valor") e no celular cada pixel dele
     sai de cima do número. 52px cabem "Spread ¢/kg" em duas linhas. */
  /* 66px é o que "RESULTADO" pede; o que sobra dividido por três dá 85px por
     coluna, folgado para o maior número que aparece aqui sem o "R$". */
  .vg-bloco col.rotulo { width: 66px; }
  .vg-cifrao { display: none; }
  .vg-bloco thead th { padding: 0 4px 6px; font-size: 9px; letter-spacing: .04em; }
  /* "RESULTADO" não cabe em 52px e a coluna é fixa, então ele era cortado no
     "RESULTAD". Deixar transbordar é seguro aqui: à direita dele está o
     cabeçalho da ADRIANA, que é alinhado à direita e tem folga sobrando. */
  .vg-bloco thead th:first-child { overflow: visible; white-space: nowrap; }
  .vg-bloco tbody th {
    padding: 7px 4px;
    font-size: 11px;
    white-space: normal;
    line-height: 1.2;
  }
  .vg-bloco tbody td { padding: 7px 4px; font-size: 12px; }
  .vg-linha-spread td { font-size: 13px; }
  .vg-delta { font-size: 10px; }

  /* As regras de celular das linhas de detalhe NÃO ficam aqui — ficam no bloco
     @media do fim do arquivo, depois das regras de desktop delas. Mesma
     especificidade decide por ordem de origem, e daqui elas perdiam: o telefone
     aplicava o recuo de 26px e a fonte de 12px numa coluna de 66px. */
}

/* ---- tela de login ---- */
.tela-login {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  min-height: 100dvh;
  padding: 20px;
}
/* No celular o cartão é ancorado no alto em vez de centralizado. O iOS não
   encolhe o layout quando o teclado sobe — ele tenta rolar o campo em foco para
   a vista, e aqui não há para onde rolar, porque a tela tem exatamente a altura
   da janela. Resultado: o campo tem autofoco, o teclado sobe sozinho ao abrir, e
   o botão "Entrar" nascia atrás dele. Centralizado só faz sentido em tela onde
   não há teclado ocupando metade dela. */
@media (max-width: 560px) {
  .tela-login { align-items: flex-start; padding-top: 7vh; }
}
.cartao-login {
  display: flex;
  flex-direction: column;
  gap: 6px;
  width: 100%;
  max-width: 320px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 28px 24px;
}
.cartao-login .brand { font-size: 18px; margin-bottom: 18px; }
.cartao-login label {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 10px;
}
.cartao-login input {
  font-size: 16px; /* 16px impede o iPhone de dar zoom ao focar o campo */
  padding: 9px 11px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--page);
  color: var(--text-primary);
}
.cartao-login .btn-primary { margin-top: 22px; padding: 10px; font-size: 15px; }
.erro-login {
  color: var(--status-critical);
  font-size: 13px;
  margin: 12px 0 0;
}

/* Identidade de quem está logado, no canto da barra. Ao lado do selo do
   espelho: os dois dizem "de onde vem o que você está vendo". */
.sessao {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--text-muted);
  white-space: nowrap;
}
.sessao .btn-link { font-size: 12px; padding: 2px 4px; }
/* O nome sai antes do selo. Ele é 89px de identificação de quem já sabe quem
   é; o selo é a idade do dado que a pessoa está lendo. Em 820px não cabem os
   dois, e era o selo que estava sendo cortado. */
@media (max-width: 900px) {
  .sessao span { display: none; }
}

/* A régua do bloco de Posição. Verde porque os três saldos são valor a favor
   do caixa futuro — distingue de Compra (azul) e Venda (laranja), que são
   fluxo, e do Resultado (preto), que fecha o período. */
.vg-bloco.posicao thead th { border-bottom-color: var(--status-good); }

/* Só aqui os rótulos são frases ("Adiantado a fornecedor") e não unidades
   ("kg", "R$/kg"): com o nowrap dos outros blocos eles vazavam 22px para dentro
   da coluna da ADRIANA. Alargar a coluna resolveria, mas desalinharia da grade
   do "No dia" — e o alinhamento entre os blocos é o ponto. Então quebra em duas
   linhas: a linha fica mais alta, a coluna fica no lugar. */
.vg-bloco.posicao tbody th { white-space: normal; line-height: 1.25; }

/* Botão de expandir das linhas somadas. É um botão de verdade, e não um span
   com onclick, porque a linha inteira que ele abre é informação: teclado e
   leitor de tela precisam alcançá-lo. Herda a tipografia da célula para não
   virar um elemento estranho no meio de uma coluna de rótulos. */
.vg-expandir {
  border: none;
  background: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
}
/* O triângulo lê o aria-expanded, que é onde o estado realmente mora. */
.vg-expandir::before {
  content: "▸";
  font-size: 9px;
  line-height: 1;
  color: var(--text-muted);
  transition: transform .12s ease;
}
.vg-expandir[aria-expanded="true"]::before { transform: rotate(90deg); }
.vg-expandir:hover { color: var(--text-primary); }
.vg-expandir:focus-visible {
  outline: 2px solid var(--series-1);
  outline-offset: 2px;
  border-radius: 3px;
}

/* Linhas de conta: recuadas e mais leves que a linha que as soma. O recuo
   entra depois do triângulo do pai, alinhando o nome da conta com o rótulo. */
.vg-bloco tr.vg-detalhe th {
  padding-left: 26px;
  font-size: 12px;
  color: var(--text-muted);
}
.vg-bloco tr.vg-detalhe td {
  font-size: 12px;
  font-weight: 400;
  color: var(--text-secondary);
}
/* Sem régua entre contas do mesmo grupo: o bloco tem cinco linhas somadas, e
   quinze filhas com linha cheia viravam uma grade dentro da grade. */
.vg-bloco tr.vg-detalhe th,
.vg-bloco tr.vg-detalhe td { border-bottom-color: transparent; }

/* Celular, e por isso depois das regras acima: mesma especificidade decide por
   ordem de origem, e este bloco tem de ganhar.

   Numa coluna de 66px o recuo de 26px é 40% dela, e sobravam 36px para o nome:
   "Cx. Sarah" quebrava em duas linhas e "Cx. Osasco" partia no meio da palavra.
   Recuo mínimo e corpo menor — quem distingue pai de filho aqui é o tamanho e a
   cor, não o espaço em branco.

   O `overflow-wrap` é rede de segurança, não solução: os nomes já vêm
   abreviados do JS. Existe para o dia em que uma conta nova tiver uma palavra
   que ninguém previu — aí ela quebra no meio, que é feio, em vez de vazar por
   cima da coluna do vizinho, que é errado. */
@media (max-width: 560px) {
  .vg-bloco tr.vg-detalhe th {
    padding-left: 8px;
    font-size: 10px;
    line-height: 1.15;
    overflow-wrap: anywhere;
  }
  .vg-bloco tr.vg-detalhe td { font-size: 11px; }
  /* O triângulo também encolhe, senão ele fica maior que o texto que abre. */
  .vg-expandir { gap: 3px; }
  .vg-expandir::before { font-size: 8px; }
}

/* ---- Spread por material: cinco cartões grandes na Visão Geral ---- */
/* auto-fit e não cinco colunas fixas: no celular vira duas, no desktop cinco,
   sem media query e sem cartão espremido no meio do caminho. */
.mat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
  gap: 12px;
}
.mat-card {
  background: var(--page);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 16px;
}
.mat-nome {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
/* O spread é o número que a pessoa veio ver: grande, e em centavos, que é como
   a conta é falada na operação. */
.mat-spread { font-size: 30px; font-weight: 600; margin: 6px 0 2px; }
.mat-spread.negativo { color: var(--status-critical); }
.mat-detalhe { font-size: 12px; color: var(--text-secondary); }
.mat-peso { font-size: 11px; color: var(--text-muted); margin-top: 4px; }
/* Volume ínfimo: o cartão continua aparecendo, mas recuado — o spread de uma
   categoria com 10 t não pode ser lido com o mesmo peso do de 4.000 t. */
.mat-card.fraco { opacity: .5; }
@media (max-width: 560px) {
  .mat-grid { grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); gap: 8px; }
  .mat-spread { font-size: 24px; }
  .mat-card { padding: 11px 12px; }
}
