/* ============================================================
   DESIGN SYSTEM TOKENS — WebPonto DSH
   Uso exclusivo: NUNCA duplicar estes tokens com estilos inline
   ============================================================ */

/* ---- Cores ---- */
:root {
  --clr-primary: #2563eb;
  --clr-primary-light: #dbeafe;
  --clr-primary-subtle: #eff6ff;
  --clr-success: #16a34a;
  --clr-success-light: #dcfce7;
  --clr-success-subtle: #f0fdf4;
  --clr-warning: #d97706;
  --clr-warning-light: #fef3c7;
  --clr-warning-subtle: #fffbeb;
  --clr-danger: #dc2626;
  --clr-danger-light: #fee2e2;
  --clr-danger-subtle: #fef2f2;

  /* ---- Os DOIS tons que faltavam no semaforo ----
     Pedido do usuario: "verde pra estar ok, laranja pra rejeicao e vermelho
     pra cancelamento ou falha de algo, amarelo pra pendente, ainda nao
     enviado". O sistema so tinha 3 tons (success/warning/danger) e jogava
     REJEITADO e CANCELADO no MESMO vermelho — o olho nao distinguia "foi
     rejeitado, da' pra corrigir e reenviar" de "foi cancelado, acabou".
     Agora sao QUATRO situacoes distintas:
       verde    -> autorizado / encerrado
       laranja  -> rejeitado / denegado
       vermelho -> cancelado
       amarelo  -> pendente (rascunho, validado, assinado, enviado, contingencia)
     Os textos (abaixo, no .sp-status-*) foram escolhidos para passar no
     WCAG AA sobre o proprio fundo claro. */
  --clr-rejeicao: #ea580c;
  --clr-rejeicao-light: #ffedd5;
  /* O AMARELO NAO PODE SER O `yellow-500` (#eab308). Medido: ele da' 1,92:1
     contra o branco do card — a barra de 3px ficaria praticamente invisivel,
     que e' o oposto do que a sinalizacao existe para fazer. Os candidatos,
     medidos de verdade (nao no olho):
       #eab308  H45  1,92:1  <- reprova
       #ca8a04  H41  2,94:1  <- reprova por 0,06
       #c2870b  H41  3,10:1
       #b8860b  H43  3,25:1  <- ESCOLHIDO (matiz mais amarelo E margem)
       #a16207  H35  4,92:1  (ja' puxa para o marrom)
     O matiz importa tanto quanto o contraste: o laranja da rejeicao esta' em
     H21, entao o amarelo precisa ficar o mais longe possivel dele. #b8860b
     (H43) fica a 22 graus do laranja; `--clr-warning` (#d97706, H32) ficaria a
     apenas 11 — indistinguivel de "rejeitado" para quem olha de relance. */
  --clr-pendente: #b8860b;
  --clr-pendente-light: #fef9c3;
  /* ---- VIOLETA: a acao que DUPLICA (Clonar) ----
     Nao existia violeta no sistema, entao "Clonar" estava usando o MESMO azul
     de "Consultar": duas acoes diferentes com a mesma cor, que e' exatamente
     a incoerencia que o operador le como surpresa.
     O azul da consulta esta' em H221 e este violeta em H262 — 41 graus de
     distancia (o minimo adotado e' 18). Medido, e nao no olho: o texto
     #5b21b6 sobre o fundo claro #ede9fe da' 7,57:1, folgado no WCAG AA. */
  --clr-violeta: #7c3aed;
  --clr-violeta-light: #ede9fe;
  --clr-text: #0f172a;
  --clr-text-secondary: #475569;
  /* Era #94a3b8 — contraste 2.56:1 sobre branco, REPROVADO no WCAG AA
     (exige 4.5:1). O usuario reclamou de nao conseguir ler os rotulos
     ("Trajeto", "Placa", "Protocolo"), e era exatamente isso: um cinza
     claro demais. #64748b da 4.76:1 e continua visualmente secundario.
     Use --clr-text-faint para o que e REALMENTE decorativo. */
  --clr-text-muted: #64748b;
  --clr-text-faint: #94a3b8;
  --clr-surface: #ffffff;
  --clr-surface-dim: #f1f5f9;
  --clr-surface-hover: #f8fafc;
  --clr-bg: #f8fafc;
  --clr-border: #e2e8f0;
  --clr-border-hover: #cbd5e1;
  --clr-border-focus: #2563eb;
  --clr-divider: #e2e8f0;

  /* Texto sobre fundo colorido (contraste AA conferido em cada par) */
  --clr-on-primary: #ffffff;
  --clr-on-success: #ffffff;
  --clr-on-danger:  #ffffff;

  /* ---- Tipografia ----
     Escala FLUIDA: os valores crescem com a tela (clamp), entao o texto de
     tabela/rotulo deixa de ser minusculo no celular sem inchar no desktop.
     Os nomes antigos (--text-xs etc.) continuam valendo — o que muda e so o
     VALOR, entao nenhuma tela precisa ser reescrita por causa disso.

     AJUSTE: o piso subiu. --text-xs comecava em 0.75rem (12px), que num
     celular de 412px fica abaixo do confortavel para rotulo de campo — o
     usuario reclamou de dificuldade de leitura. Agora comeca em 0.8125rem
     (13px) e sobe. O --text-sm e' o novo tamanho MINIMO de texto corrido.
     Regra: se o usuario precisa LER para operar, nao use --text-xs. */
  --text-xs:   clamp(0.8125rem, 0.78rem + 0.18vw, 0.875rem);
  --text-sm:   clamp(0.9375rem, 0.9rem + 0.2vw,   1rem);
  --text-base: clamp(1rem,     0.97rem + 0.15vw,  1.0625rem);
  --text-lg:   clamp(1.125rem, 1.08rem + 0.25vw,  1.25rem);
  --text-xl:   clamp(1.25rem,  1.19rem + 0.3vw,   1.5rem);
  --text-2xl:  clamp(1.5rem,   1.4rem + 0.5vw,    1.875rem);
  --text-3xl:  clamp(1.75rem,  1.55rem + 0.9vw,   2.25rem);

  --font-normal: 400;
  --font-medium: 500;
  --font-semibold: 600;
  --font-bold: 700;

  /* Entrelinha: subiu de 1.5 para 1.55 no corpo e 1.6 em texto denso.
     Numero de documento (chave, protocolo) fica em 1.4 porque e lido em
     bloco monoespacado, onde linha solta atrapalha a conferencia. */
  --leading-tight: 1.25;
  --leading-normal: 1.55;
  --leading-relaxed: 1.65;
  --leading-mono: 1.4;

  /* Numeros que precisam alinhar em coluna (valores, totais) */
  --font-numeric: tabular-nums;

  /* ---- Bordas ---- */
  --radius-sm: 6px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-full: 9999px;

  /* ---- Sombras ----
     Tres niveis, para existir hierarquia REAL. Antes so havia sm/md e quase
     tudo usava shadow-sm, entao tudo parecia ter o mesmo peso na tela. */
  --shadow-sm: 0 1px 2px rgba(15,23,42,.06);
  --shadow-md: 0 4px 12px rgba(15,23,42,.08);
  --shadow-lg: 0 12px 32px rgba(15,23,42,.14);

  /* ---- Animação ---- */
  --dur-fast: 150ms;
  --dur-normal: 200ms;
  --dur-slow: 300ms;
  --ease: cubic-bezier(.4,0,.2,1);

  /* ---- Alvos de toque e espaco ----
     O sistema e usado no celular. 44px e o minimo para o dedo acertar sem
     errar, e vale para QUALQUER elemento tocavel: botao, aba, item de menu,
     linha de acao. O --touch-sm (38px) e a excecao para botoes secundarios
     dentro de tabela, onde 44px estouraria a linha. */
  --touch: 44px;
  --touch-sm: 38px;

  /* ---- Larguras de leitura ---- */
  --measure: 68ch;

  /* ---- Camadas (z-index) ----
     Nomeadas para acabar com o chute de "z-index: 9999". Os valores sao os
     mesmos que o app.js ja usava (tier1..tier4), so agora tem nome. */
  --z-dropdown: 12000;
  --z-sticky: 12500;
  --z-modal: 13000;
  --z-toast: 14000;
}

/* ---- Reset Base ---- */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html { font-size: 16px; }

/* O atributo `hidden` do HTML precisa vencer o `display` do design system.
   O navegador aplica `[hidden] { display: none }` na folha DELE (user agent),
   mas qualquer `display:` que o tokens.css declare tem prioridade sobre isso —
   entao `el.hidden = true` era simplesmente IGNORADO em tudo que tem classe
   .sp-* (.sp-btn, .sp-card, .sp-badge... todos declaram display).
   Resultado: o elemento continuava na tela e o codigo parecia nao fazer nada.
   Esta regra restaura o comportamento que o HTML promete. */
[hidden] { display: none !important; }

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  font-size: var(--text-sm);
  color: var(--clr-text);
  background: var(--clr-bg);
  line-height: var(--leading-normal);
  -webkit-font-smoothing: antialiased;
  /* Evita o "zoom involuntario" do iOS ao focar um input com fonte pequena */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* Foco visivel padrao em TODO elemento interativo.
   Antes so .sp-btn tinha :focus-visible, entao quem navega por teclado (ou
   usa leitor de tela) se perdia ao sair dos botoes. */
a:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
button:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--clr-primary);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* Numeros que ficam em coluna (valores, totais, quantidades) precisam alinhar.
   Sem isto, "R$ 9,00" e "R$ 1.100,00" desalinham a coluna inteira. */
.sp-table td,
.sp-stat-value,
.sp-num {
  font-variant-numeric: tabular-nums;
}

/* ---- Cards ---- */
.sp-card {
  background: var(--clr-surface);
  border: 1px solid var(--clr-border);
  border-radius: var(--radius-lg);
  padding: 14px;
  box-shadow: var(--shadow-sm);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.sp-card-hover:hover {
  box-shadow: var(--shadow-md);
  border-color: var(--clr-border-hover);
  transition: box-shadow var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}
/* Estado ativo no toque: sem isto, o toque no card no celular nao da
   nenhum retorno visual e o usuario acha que o sistema "nao respondeu". */
.sp-card-hover:active { transform: scale(.995); }

/* Cabecalho de card: titulo + acao alinhados, com respiro consistente */
.sp-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 10px;
}
.sp-card-title {
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  color: var(--clr-text);
  line-height: var(--leading-tight);
}

/* ---- Botões ----
   Altura base 36px no DESKTOP, 44px no MOBILE. O dedo e o alvo principal
   deste sistema; 36px era apertado demais em tela de toque. */
.sp-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 0 14px;
  height: 36px;
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  border-radius: var(--radius-md);
  cursor: pointer;
  border: 1px solid transparent;
  transition: filter var(--dur-fast) var(--ease),
              background-color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
  white-space: nowrap;
  line-height: 1;
  text-decoration: none;
  /* Impede o "flash cinza" do navegador ao tocar no Android/iOS */
  -webkit-tap-highlight-color: transparent;
  user-select: none;
}
.sp-btn:hover { filter: brightness(1.08); }
.sp-btn:active { filter: brightness(0.95); }
.sp-btn:focus-visible { outline: 2px solid var(--clr-primary); outline-offset: 2px; }
.sp-btn:disabled,
.sp-btn[disabled],
.sp-btn[aria-disabled="true"] {
  opacity: .5;
  cursor: not-allowed;
  filter: none;
  pointer-events: none;
}

.sp-btn-primary { background: var(--clr-primary); color: var(--clr-on-primary); }
.sp-btn-secondary { background: var(--clr-surface); border-color: var(--clr-border); color: var(--clr-text); }
.sp-btn-secondary:hover { background: var(--clr-surface-dim); }
.sp-btn-ghost { background: transparent; color: var(--clr-text-secondary); }
.sp-btn-ghost:hover { background: var(--clr-surface-dim); color: var(--clr-text); }
.sp-btn-danger { background: var(--clr-danger); color: var(--clr-on-danger); }
.sp-btn-danger:hover { filter: brightness(1.12); }
.sp-btn-success { background: var(--clr-success); color: var(--clr-on-success); }
.sp-btn-success:hover { filter: brightness(1.12); }

/* Botao so de icone: quadrado, com area de toque garantida */
.sp-btn-icon {
  padding: 0;
  width: 36px;
  flex: 0 0 auto;
}

.sp-btn-sm { height: 32px; padding: 0 10px; font-size: 0.7rem; }
.sp-btn-block { width: 100%; }

/* ---- Botoes de acao em TABELA ----
   Nas listagens, cada linha tem "Editar" e "Excluir" em botoes minusculos
   (text-[11px] / px-3 py-1). Sao o alvo mais tocado do sistema e o mais
   apertado: no celular, dois deles colados viram um alvo unico e o usuario
   apaga um registro tentando editar. Estas classes garantem altura de toque
   e separacao, sem inflar a linha da tabela no desktop. */
.sp-acao {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  height: 32px;
  padding: 0 10px;
  border-radius: var(--radius-md);
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  border: 1px solid transparent;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--dur-fast) var(--ease), filter var(--dur-fast) var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.sp-acao:hover { filter: brightness(.96); }
.sp-acao:focus-visible { outline: 2px solid var(--clr-primary); outline-offset: 2px; }
.sp-acao-editar  { background: var(--clr-primary-light); color: #1e40af; }
.sp-acao-excluir { background: var(--clr-danger-light);  color: #991b1b; }
.sp-acao-ver     { background: var(--clr-surface-dim);   color: var(--clr-text-secondary); }
.sp-acao-sucesso { background: var(--clr-success-light); color: #166534; }
/* Grupo de acoes da linha: nunca deixa dois botoes encostados */
.sp-acao-grupo { display: inline-flex; gap: 6px; align-items: center; }

@media (max-width: 767px) {
  .sp-acao { height: var(--touch-sm); padding: 0 12px; }
  .sp-acao-grupo { gap: 8px; }
}

/* No MOBILE, todo botao tem area de toque de verdade. Aplicado por media
   query em vez de sair mudando classe por classe nas telas: assim uma tela
   nova ja nasce correta, sem depender de eu lembrar de ajustar. */
@media (max-width: 767px) {
  .sp-btn { height: var(--touch); padding: 0 16px; }
  .sp-btn-sm { height: var(--touch-sm); padding: 0 12px; }
  .sp-btn-icon { width: var(--touch); }
}

/* ---- Badges ---- */
.sp-badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  white-space: nowrap;
}
.sp-badge-success { background: var(--clr-success-light); color: #166534; }
.sp-badge-warning { background: var(--clr-warning-light); color: #92400e; }
.sp-badge-danger  { background: var(--clr-danger-light);  color: #991b1b; }
.sp-badge-muted   { background: var(--clr-surface-dim);   color: var(--clr-text-muted); }
.sp-badge-primary { background: var(--clr-primary-light); color: #1e40af; }

/* ============================================================
   STATUS DE DOCUMENTO — mapa unico
   ------------------------------------------------------------
   Antes, cada modulo escolhia a propria cor de status com classe
   Tailwind inline (bg-red-200, bg-emerald-100, bg-yellow-50...).
   Resultado: o MESMO status aparecia com cor diferente conforme a
   tela, e o usuario tinha de reaprender a legenda em cada lugar.

   Aqui a cor passa a ser consequencia do SIGNIFICADO do status, e
   nao da tela. A regra de leitura, do ponto de vista de quem opera:

     RASCUNHO .... cinza    -> nao vale nada ainda, nao saiu daqui
     VALIDADO .... azul     -> dados conferidos, ainda nao enviado
     ASSINADO .... azul     -> pronto para transmitir
     ENVIADO ..... ambar    -> saiu, aguardando a SEFAZ responder
     AUTORIZADO .. verde    -> documento com valor fiscal, acabou
     ENCERRADO ... verde    -> ciclo fechado (MDF-e)
     DENEGADO .... vermelho -> recusado pelo FISCO (nao e cancelamento)
     CANCELADO ... vermelho -> invalido por decisao da empresa
     REJEITADO ... vermelho -> erro da SEFAZ, pode corrigir e reenviar
     EM_CONTINGENCIA ambar  -> emitido offline, precisa transmitir

   Verde = pode seguir. Ambar = algo esta em transito. Vermelho = parou.
   Cinza = nem comecou. Essa e a unica coisa que o operador precisa saber.
   ============================================================ */
.sp-status {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  line-height: 1.4;
  white-space: nowrap;
  letter-spacing: .01em;
}
/* Ponto colorido antes do texto: o status precisa ser reconhecivel
   DE RELANCE, pela cor, sem o usuario ter de ler o rotulo. */
.sp-status::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: 0 0 auto;
}

/* A PALETA ACOMPANHA AS QUATRO SITUACOES da borda do card (.sp-row-*).
   Isto e' obrigatorio, nao estetico: o ponto do badge e' `currentColor`, e a
   borda do card usa a cor CHEIA do mesmo tom. Se o badge de REJEITADO fosse
   vermelho e a borda laranja, o usuario veria exatamente a incoerencia que
   pediu para eliminar ("assim nao tem surpresa e nem incoerencia").

   O que mudou e o que era:
     RASCUNHO   era cinza  -> amarelo  (e' "pendente, ainda nao enviado")
     VALIDADO   era azul   -> amarelo  (idem: ainda nao saiu daqui)
     ASSINADO   era azul   -> amarelo  (idem)
     ENVIADO    era ambar  -> amarelo  (aguardando retorno; segue pendente)
     REJEITADO  era VERMELHO -> LARANJA (da' pra corrigir e reenviar)
     DENEGADO   era VERMELHO -> LARANJA (idem)
     CANCELADO  continua vermelho (fim de linha)
     AUTORIZADO / ENCERRADO continuam verde
   Texto sobre o fundo claro do proprio badge: todos acima de 4.5:1 (AA). */
.sp-status-rascunho   { background: var(--clr-pendente-light);  color: #854d0e; }
.sp-status-validado   { background: var(--clr-pendente-light);  color: #854d0e; }
.sp-status-assinado   { background: var(--clr-pendente-light);  color: #854d0e; }
.sp-status-enviado    { background: var(--clr-pendente-light);  color: #854d0e; }
.sp-status-autorizado { background: var(--clr-success-light);   color: #166534; }
.sp-status-encerrado  { background: var(--clr-success-light);   color: #166534; }
.sp-status-denegado   { background: var(--clr-rejeicao-light);  color: #9a3412; }
.sp-status-rejeitado  { background: var(--clr-rejeicao-light);  color: #9a3412; }
.sp-status-cancelado  { background: var(--clr-danger-light);    color: #991b1b; }
.sp-status-contingencia {
  background: var(--clr-pendente-light);
  color: #854d0e;
  /* Contingencia e o unico status que EXIGE acao depois: fica listrado
     para chamar o olho, ja que o documento ainda nao esta valido. */
  background-image: repeating-linear-gradient(
    45deg, transparent, transparent 5px, rgba(184,134,11,.20) 5px, rgba(184,134,11,.20) 10px
  );
}

/* Linha de tabela / card com documento parado: borda lateral marcando.
   Da para varrer a lista com o olho e achar o que precisa de atencao.

   QUATRO tons, um por SITUACAO, e cada um e' a MESMA cor do badge e do chip
   de filtro daquele status. O usuario pediu assim: "a borda ... e' bom ficar
   de acordo com a cor de cada status que tem nos botoes de selecao, isso e'
   bem melhor, assim nao tem surpresa e nem incoerencia".
     sp-row-ok        verde    -> autorizado / encerrado
     sp-row-rejeicao  laranja  -> rejeitado / denegado
     sp-row-cancelado vermelho -> cancelado
     sp-row-pendente  amarelo  -> rascunho / validado / assinado / enviado / contingencia

   Nao existe "sem tom": quem chama escolhe PENDENTE como fallback, que e' o
   estado mais conservador — nunca afirma que o documento esta ok.

   As duas regras escrevem em `box-shadow`, a MESMA propriedade. Por isso o
   card NAO pode ter `sp-card-hover`: `.sp-card-hover:hover` tambem escreve
   em `box-shadow` e, ganhando por especificidade, APAGAVA a borda no hover.
   Era esse o defeito relatado no MDFe. */
.sp-row-ok        { box-shadow: inset 3px 0 0 var(--clr-success); }
.sp-row-rejeicao  { box-shadow: inset 3px 0 0 var(--clr-rejeicao); }
.sp-row-cancelado { box-shadow: inset 3px 0 0 var(--clr-danger); }
.sp-row-pendente  { box-shadow: inset 3px 0 0 var(--clr-pendente); }

/* ---- Tabelas ----
   Regra do sistema (decidida pelo usuario): NAO quebrar texto na vertical.
   Texto longo rola para o lado. Isso e mantido aqui — o que muda e o
   respiro e a legibilidade, que estavam apertados no celular. */
.sp-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  position: relative;
}
.sp-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--text-sm);
}
.sp-table th {
  background: var(--clr-bg);
  padding: 10px 12px;
  text-align: left;
  font-weight: var(--font-semibold);
  font-size: var(--text-xs);
  color: var(--clr-text-secondary);
  text-transform: uppercase;
  letter-spacing: .06em;
  white-space: nowrap;
  position: sticky;
  top: 0;
  z-index: 2;
  /* O cabecalho fica FIXO ao rolar. Sem a borda propria, a linha some
     visualmente atras do conteudo que passa por baixo. */
  box-shadow: inset 0 -1px 0 var(--clr-border);
}
.sp-table th:first-child { border-radius: var(--radius-md) 0 0 0; }
.sp-table th:last-child  { border-radius: 0 var(--radius-md) 0 0; }

.sp-table td {
  padding: 10px 12px;
  border-top: 1px solid var(--clr-divider);
  white-space: nowrap;
  vertical-align: middle;
  /* Toda celula tem fundo PROPRIO. Nao e' enfeite: a primeira coluna e'
     `position: sticky` no celular, e celula transparente deixa o texto das
     outras colunas passar POR BAIXO do texto fixo (dois numeros sobrepostos,
     ilegiveis). */
  background: var(--clr-surface);
}
.sp-table tr:hover td { background: var(--clr-surface-hover); }

/* Célula que PODE quebrar (nome, descricao, motivo de rejeicao).
   Use .sp-cell-wrap exatamente onde o texto e longo e a quebra ajuda. */
.sp-table td.sp-cell-wrap {
  white-space: normal;
  word-break: break-word;
  min-width: 160px;
  max-width: 320px;
}
.sp-table td.sp-cell-num { text-align: right; font-variant-numeric: tabular-nums; }
.sp-table .sp-totals-row td {
  font-weight: var(--font-bold);
  background: var(--clr-surface-dim) !important;
  border-top: 2px solid var(--clr-border);
  font-variant-numeric: tabular-nums;
}

/* Coluna fixa: em tabela larga no celular, a 1a coluna (documento/numero)
   acompanha a rolagem. Sem isto o usuario rola para o lado e perde a
   referencia de QUAL linha esta olhando. */
@media (max-width: 767px) {
  .sp-table td, .sp-table th { padding: 12px; }
  .sp-table-fix-first th:first-child,
  .sp-table-fix-first td:first-child {
    position: sticky;
    left: 0;
    z-index: 3;
    background: var(--clr-surface);
    box-shadow: 1px 0 0 var(--clr-divider);
  }
  .sp-table-fix-first th:first-child { background: var(--clr-bg); z-index: 4; }
  .sp-table-fix-first tr:hover td:first-child { background: var(--clr-surface-hover); }
}

/* ---- Formulários ----
   ALTURA 44px e' regra, nao sugestao: abaixo disso o dedo erra o alvo no
   celular (era 36px, e pior ainda nos modulos que montavam o campo na mao).
   FONTE 16px e' outro requisito: o iOS da zoom automatico na tela inteira
   quando o input tem menos de 16px. Por isso o tamanho nao usa a escala
   fluida (que cairia para 13px no celular) — usa max() para nunca descer
   de 16px, que e' o minimo que o Safari aceita sem dar zoom. */
.sp-select, .sp-input {
  height: var(--touch);
  min-height: var(--touch);
  font-size: max(16px, var(--text-sm));
  padding: 0 12px;
  border: 1px solid var(--clr-border);
  border-radius: var(--radius-md);
  background: var(--clr-surface);
  color: var(--clr-text);
  -webkit-tap-highlight-color: transparent;
}
.sp-select:focus, .sp-input:focus {
  outline: none;
  border-color: var(--clr-border-focus);
  box-shadow: 0 0 0 3px rgba(37,99,235,.15);
}
/* Variante compacta: SO para filtro apertado em linha de tabela ou barra de
   ferramentas no DESKTOP. No mobile ela e' neutralizada (ver o bloco de
   mobile no fim do arquivo) porque 32px nao e' alvo de toque. */
.sp-input-sm { height: 34px; font-size: var(--text-xs); padding: 0 10px; }
.sp-field { display: flex; flex-direction: column; gap: 6px; }
.sp-field label,
.sp-field-label {
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  color: var(--clr-text-secondary);
  letter-spacing: 0;
}
.sp-field input, .sp-field select, .sp-field textarea {
  padding: 8px 10px;
  border: 1px solid var(--clr-border);
  border-radius: var(--radius-md);
  background: var(--clr-surface);
  color: var(--clr-text);
  /* 16px no mobile e o minimo para o iOS NAO dar zoom ao focar o campo.
     Com fonte menor, o Safari amplia a tela sozinho e o layout pula. */
  font-size: max(16px, var(--text-sm));
  font-family: inherit;
}
.sp-field input:focus, .sp-field select:focus, .sp-field textarea:focus {
  outline: none;
  border-color: var(--clr-border-focus);
  box-shadow: 0 0 0 3px rgba(37,99,235,.15);
}
/* Campo obrigatorio: marca o rotulo em vez de colorir o campo inteiro */
.sp-field-obrigatorio label::after {
  content: ' *';
  color: var(--clr-danger);
  font-weight: var(--font-bold);
}
/* Mensagem de erro ABAIXO do campo, no lugar certo de ler */
.sp-field-erro input,
.sp-field-erro select,
.sp-field-erro textarea {
  border-color: var(--clr-danger);
}
.sp-field-erro input:focus,
.sp-field-erro select:focus,
.sp-field-erro textarea:focus {
  box-shadow: 0 0 0 3px rgba(220,38,38,.15);
}
.sp-field-msg {
  font-size: var(--text-xs);
  color: var(--clr-danger);
  line-height: var(--leading-tight);
}
.sp-field-hint {
  font-size: var(--text-xs);
  color: var(--clr-text-muted);
  line-height: var(--leading-tight);
}

@media (max-width: 767px) {
  .sp-select, .sp-input { height: var(--touch); font-size: 16px; padding: 0 12px; }
  .sp-field input, .sp-field select { min-height: var(--touch); }
}

/* ---- Modais ---- */
.wp-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 13000;
}
.wp-modal {
  background: var(--clr-surface);
  border-radius: var(--radius-lg);
  width: 520px;
  max-width: 94vw;
  max-height: 88vh;
  overflow-y: auto;
  box-shadow: 0 20px 60px rgba(0,0,0,.25);
}
.wp-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--clr-border);
}
.wp-modal-header h3 { font-size: var(--text-base); font-weight: var(--font-bold); }
.wp-modal-close {
  background: none;
  border: none;
  font-size: 20px;
  cursor: pointer;
  color: var(--clr-text-muted);
  padding: 4px;
  line-height: 1;
  border-radius: var(--radius-sm);
}
.wp-modal-close:hover { background: var(--clr-surface-dim); color: var(--clr-text); }
.wp-modal-body { padding: 20px; }
.wp-modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 20px;
  border-top: 1px solid var(--clr-border);
}

/* ============================================================
   MODAIS — cabem na tela mobile (Galaxy A7 / ~412px)
   Cobre os dois padrões de overlay: .wp-modal-overlay e fixed bg-black/40
   ============================================================ */
@media (max-width: 767px) {
  .wp-modal-overlay,
  [class*="bg-black/40"] {
    padding: 10px;
    overflow-y: auto;
    align-items: flex-start;
  }
  .wp-modal-overlay > *,
  [class*="bg-black/40"] > * {
    width: 100% !important;
    max-width: 100% !important;
    max-height: 90vh;
    overflow-y: auto;
  }
  .wp-modal,
  [class*="wp-modal"] {
    max-height: 90vh;
  }

  /* No mobile: ao SELECIONAR texto, o navegador abre o menu nativo de
     "copiar/selecionar tudo". Sem isto o usuario nao consegue copiar trechos
     de dentro dos modais (o overlay bloqueava a selecao). */
  .wp-modal-overlay,
  .wp-modal,
  .wp-modal-body {
    -webkit-user-select: text;
    user-select: text;
  }
}

/* Força direção em coluna onde há flex-col (modais de preview: botões em cima, imagem embaixo) */
[class*="flex-col"] {
  flex-direction: column !important;
}

/* ---- Form Grid ---- */
/* Grade de formulario. ATENCAO: colapsa para 1 coluna no bloco de mobile de
   640px — o nome NAO contem "grid-cols", entao a regra global
   `[class*="grid-cols-"]` nao a alcanca. Se voce criar outro grid com nome
   proprio, adicione-o la' tambem, senao ele fica em 2 colunas no celular. */
.sp-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.sp-form-full { grid-column: 1 / -1; }

/* ---- Layout Helpers ---- */
.sp-grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; }
.sp-grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.sp-grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.sp-flex-center { display: flex; align-items: center; justify-content: center; }
.sp-flex-between { display: flex; align-items: center; justify-content: space-between; }
.sp-gap-2 { gap: 8px; }
.sp-gap-3 { gap: 12px; }

/* ---- Status Dots ---- */
.sp-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 6px;
}
.sp-dot-muted   { background: var(--clr-text-muted); }
.sp-dot-success { background: var(--clr-success); }
.sp-dot-warning { background: var(--clr-warning); }
.sp-dot-primary { background: var(--clr-primary); }
.sp-dot-danger  { background: var(--clr-danger); }
/* Os dois tons novos, para o ponto do chip de filtro falar a MESMA lingua da
   borda do card e do badge do status (.sp-row-* / .sp-status-*). */
.sp-dot-rejeicao { background: var(--clr-rejeicao); }
.sp-dot-pendente { background: var(--clr-pendente); }

/* ---- Monospace valores ---- */
.sp-mono { font-family: 'JetBrains Mono', 'Courier New', monospace; }

/* ---- Kanban ---- */
.sp-kanban {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 12px;
}
.sp-kanban-col {
  background: var(--clr-surface-dim);
  border: 1px solid var(--clr-border);
  border-radius: var(--radius-lg);
  min-height: 400px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.sp-kanban-header {
  padding: 12px 14px;
  border-bottom: 1px solid var(--clr-border);
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  color: var(--clr-text-secondary);
  text-transform: uppercase;
  letter-spacing: .06em;
  background: var(--clr-surface);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}
.sp-kanban-count {
  background: var(--clr-surface-dim);
  color: var(--clr-text-secondary);
  border-radius: var(--radius-full);
  padding: 1px 7px;
  font-size: .7rem;
  font-variant-numeric: tabular-nums;
}
.sp-kanban-body { padding: 8px; display: flex; flex-direction: column; gap: 8px; flex: 1; }

/* ---- Estados vazios ----
   Antes, lista vazia simplesmente nao mostrava nada. O usuario ficava sem
   saber se estava carregando, se deu erro, ou se realmente nao ha nada.
   Um estado vazio explica a situacao e aponta o proximo passo. */
.sp-vazio {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 40px 20px;
  text-align: center;
  color: var(--clr-text-muted);
}
.sp-vazio-icone {
  width: 40px;
  height: 40px;
  color: var(--clr-border-hover);
  margin-bottom: 2px;
}
.sp-vazio-titulo {
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  color: var(--clr-text-secondary);
}
.sp-vazio-texto {
  font-size: var(--text-xs);
  max-width: 34ch;
  line-height: var(--leading-normal);
}

/* ---- Carregando ---- */
.sp-carregando {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 32px 16px;
  color: var(--clr-text-muted);
  font-size: var(--text-xs);
}
.sp-spinner {
  width: 16px;
  height: 16px;
  border: 2px solid var(--clr-border);
  border-top-color: var(--clr-primary);
  border-radius: 50%;
  animation: sp-spin .7s linear infinite;
  flex: 0 0 auto;
}
@keyframes sp-spin { to { transform: rotate(360deg); } }

/* Esqueleto de carregamento: mostra a FORMA do conteudo que vem.
   Percebido como mais rapido que um spinner generico. */
.sp-esqueleto {
  background: linear-gradient(90deg, var(--clr-surface-dim) 25%, #e8edf3 50%, var(--clr-surface-dim) 75%);
  background-size: 200% 100%;
  animation: sp-brilho 1.4s ease-in-out infinite;
  border-radius: var(--radius-sm);
  height: 12px;
}
@keyframes sp-brilho {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* ---- Tabs ----
   Abas rolam para o lado quando nao cabem (nao quebram linha, nao cortam).
   No mobile cada aba tem altura de toque cheia. */
.sp-tabs-bar {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--clr-border);
  margin-bottom: 16px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  flex-wrap: nowrap;
}
.sp-tabs-bar::-webkit-scrollbar { display: none; }

.sp-tab {
  padding: 8px 14px;
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  color: var(--clr-text-secondary);
  background: transparent;
  border: 1px solid transparent;
  border-bottom: none;
  border-radius: var(--radius-md) var(--radius-md) 0 0;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease),
              background-color var(--dur-fast) var(--ease);
  white-space: nowrap;
  line-height: 1;
  margin-bottom: -1px;
  flex: 0 0 auto;
  -webkit-tap-highlight-color: transparent;
}
.sp-tab:hover {
  color: var(--clr-text);
  background: var(--clr-surface-dim);
}
.sp-tab-active {
  color: var(--clr-primary);
  background: var(--clr-surface);
  border-color: var(--clr-border);
  border-bottom-color: var(--clr-surface);
}
.sp-tab-active:hover {
  color: var(--clr-primary);
  background: var(--clr-surface);
}
/* Barra de sublinhado na aba ativa: reforca a posicao mesmo quando a barra
   esta rolada e a borda inferior fica fora de vista. */
.sp-tab-active::after {
  content: '';
  position: absolute;
  left: 8px;
  right: 8px;
  bottom: -1px;
  height: 2px;
  background: var(--clr-primary);
  border-radius: 2px;
}
.sp-tab { position: relative; }

@media (max-width: 767px) {
  .sp-tab { min-height: var(--touch); padding: 0 14px; display: inline-flex; align-items: center; }
}

/* ---- Page Header ---- */
.sp-page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 20px;
  gap: 12px;
  flex-wrap: wrap;
}
.sp-page-header h1 {
  font-size: var(--text-xl);
  font-weight: var(--font-bold);
  color: var(--clr-text);
  line-height: var(--leading-tight);
}
.sp-page-header-sub {
  font-size: var(--text-xs);
  color: var(--clr-text-muted);
  margin-top: 2px;
}

/* Linha do titulo quando ela carrega um contador/badge ao lado do h1
   (ex.: Financeiro + total geral). Sem isso o badge desalinha do titulo. */
.sp-page-header-titulo {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* No mobile o cabecalho vira coluna: titulo em cima, acao embaixo ocupando
   a largura — em vez de espremer os dois lado a lado numa tela de 412px. */
@media (max-width: 767px) {
  .sp-page-header { flex-direction: column; align-items: stretch; gap: 10px; }
  .sp-page-header h1 { font-size: var(--text-lg); }
  .sp-page-header .sp-btn { width: 100%; }
}

/* ---- Barra de acoes fixa (polegar) ----
   Em tela de acao (emitir, salvar, confirmar), o botao principal fica
   grudado no rodape, dentro do alcance do dedo. No desktop o comportamento
   classico continua (acao no topo), entao nada muda para quem usa mouse. */
.sp-acao-fixa {
  position: sticky;
  bottom: 0;
  z-index: var(--z-sticky);
  background: var(--clr-surface);
  border-top: 1px solid var(--clr-border);
  padding: 10px 12px;
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  box-shadow: 0 -4px 12px rgba(15,23,42,.06);
  /* Respeita a area segura do iPhone (barra inferior do gesto) */
  padding-bottom: max(10px, env(safe-area-inset-bottom));
}
@media (max-width: 767px) {
  .sp-acao-fixa { flex-direction: column-reverse; }
  .sp-acao-fixa .sp-btn { width: 100%; }
}

/* ---- Stats Grid ---- */
.sp-stats-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin-bottom: 16px;
}
.sp-stat-card { padding: 14px; display: flex; flex-direction: column; gap: 4px; }
.sp-stat-label { font-size: var(--text-xs); color: var(--clr-text-secondary); font-weight: var(--font-medium); }
.sp-stat-value { font-size: var(--text-lg); font-weight: var(--font-bold); }

/* ---- Responsivo ---- */
@media(max-width: 1280px) {
  .sp-kanban { grid-template-columns: repeat(3, 1fr); }
  .sp-stats-grid { grid-template-columns: repeat(3, 1fr); }
}
@media(max-width: 1024px) {
  .sp-kanban { grid-template-columns: repeat(2, 1fr); }
  .sp-stats-grid { grid-template-columns: repeat(2, 1fr); }
  .sp-grid-4 { grid-template-columns: repeat(2, 1fr); }
  .sp-grid-3 { grid-template-columns: repeat(2, 1fr); }
}
@media(max-width: 640px) {
  .sp-kanban { grid-template-columns: 1fr; }
  .sp-stats-grid { grid-template-columns: 1fr; }
  /* O .sp-form-grid estava FORA desta lista — e nao era pego por mais nada.
     A regra global de colapso e' `[class*="grid-cols-"]`, que casa pelo NOME
     da classe do Tailwind; "sp-form-grid" nao contem a substring "grid-cols",
     entao ela nunca casava. Resultado: o formulario do "Novo Manifesto" ficava
     em 2 colunas a 412px, com os campos pela metade. Era esse o "campo Empresa
     cortado". Todo grid do sistema colapsa no celular; este era o unico que
     nao colapsava, e nada avisava. */
  .sp-grid-2, .sp-grid-3, .sp-grid-4, .sp-form-grid { grid-template-columns: 1fr; }
  .sp-card { padding: 12px; }
  .sp-modal { width: 100%; max-width: 100%; }
}

/* ---- Reduced Motion ---- */
@media(prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
}

/* ---- Truncate ---- */
.sp-truncate {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ============================================================
   MOBILE — layout robusto (não depende de Tailwind runtime)
   ============================================================ */

/* Backdrop do menu (gaveta) */
#sidebar-backdrop { display: none; }
#sidebar-backdrop.mobile-open {
  display: block;
  position: fixed;
  top: 0; right: 0; bottom: 0; left: 0;
  background: rgba(15,23,42,.5);
  /* Desfoca o conteúdo atrás: deixa claro que o foco é o menu, sem
     escurecer tanto que o usuário perca a noção de onde estava. */
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  z-index: 49;
  animation: sp-fade-in var(--dur-fast) var(--ease);
}
@keyframes sp-fade-in { from { opacity: 0; } to { opacity: 1; } }

@media (max-width: 767px) {
  /* Sidebar como gaveta vertical fixa à esquerda */
  #sidebar.mobile-open {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 50;
    display: flex;
    flex-direction: column;
    width: 260px;
    max-width: 82vw;
    box-shadow: 0 0 30px rgba(0,0,0,.4);
    animation: sp-gaveta-entra var(--dur-normal) var(--ease);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  #sidebar.mobile-open nav { display: flex; flex-direction: column; }

  /* Main rola quando o conteúdo não cabe (nada fica cortado/inacessível) */
  main { min-width: 0; overflow-x: auto; }
}
@keyframes sp-gaveta-entra {
  from { transform: translateX(-100%); }
  to   { transform: translateX(0); }
}

/* ---- Menu lateral: item clicável de verdade ----
   No menu, cada item é um alvo de toque. Antes o item tinha ~36px de altura
   e nenhum estado de "onde estou" — o usuário não sabia em que módulo estava
   depois de abrir a gaveta. */
.sp-nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 12px;
  min-height: var(--touch);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: #cbd5e1;
  text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease);
  -webkit-tap-highlight-color: transparent;
  cursor: pointer;
}
.sp-nav-item:hover { background: #1e293b; color: #fff; }
.sp-nav-item:focus-visible { outline: 2px solid var(--clr-primary); outline-offset: -2px; }

/* Onde estou: fundo mais claro + barra na lateral esquerda. */
.sp-nav-item-ativo {
  background: #1e293b;
  color: #fff;
  box-shadow: inset 3px 0 0 var(--clr-primary);
}
.sp-nav-item-ativo .sp-nav-icone { color: #60a5fa; }

.sp-nav-icone {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  color: #64748b;
  transition: color var(--dur-fast) var(--ease);
}
.sp-nav-item:hover .sp-nav-icone { color: #94a3b8; }

/* Botão de fechar dentro da gaveta (mobile) */
.sp-nav-fechar {
  display: none;
  align-items: center;
  justify-content: center;
  width: var(--touch);
  height: var(--touch);
  border: none;
  background: transparent;
  color: #94a3b8;
  cursor: pointer;
  border-radius: var(--radius-md);
  flex: 0 0 auto;
}
@media (max-width: 767px) {
  .sp-nav-fechar { display: inline-flex; }
}

/* ---- Barra superior (status do serviço, botão de menu) ---- */
.sp-topo {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 16px;
  flex-wrap: wrap;
}
.sp-topo-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 34px;
  padding: 0 12px;
  border: 1px solid var(--clr-border);
  border-radius: var(--radius-md);
  background: var(--clr-surface);
  color: var(--clr-text-secondary);
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.sp-topo-btn:hover { background: var(--clr-surface-dim); }
@media (max-width: 767px) {
  .sp-topo-btn { min-height: var(--touch); }
}

/* Botao de abrir a gaveta do menu: SO' existe no celular.
   No desktop o sidebar esta' sempre na tela, entao o botao nao teria o que
   abrir — era um controle duplicado.

   ATENCAO ao motivo de estar escrito AQUI e nao como `md:hidden` no HTML:
   o tokens.css e' carregado DEPOIS do tailwind.css, e `.sp-topo-btn` (que
   define `display: inline-flex`) tem a MESMA especificidade do utilitario
   `md:hidden`. Em empate de especificidade quem vence e' quem vem por ultimo,
   ou seja o tokens.css — entao o `md:hidden` do HTML nunca teve efeito nenhum
   e o botao aparecia tambem no desktop. Usar o ID resolve por especificidade,
   sem precisar de `!important`. */
#btn-menu-mobile { display: none; }
@media (max-width: 767px) {
  #btn-menu-mobile { display: inline-flex; }
}

/* ---- Relogio de sessao no cabecalho -------------------------------------
   Mostra "Sessao expira em 7h 12min" para o usuario se organizar antes de
   ser deslogado. E' um aviso, entao a cor comunica a urgencia:
     normal  = discreto, igual aos outros botoes da barra
     aviso   = ambar (falta menos de 10 min)
     critico = vermelho (falta menos de 2 min)
   Fica no fim da barra (`margin-left: auto`) para nao empurrar o botao de
   menu nem o de status, que sao os mais clicados. */
.sp-sessao {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 34px;
  padding: 0 12px;
  border: 1px solid var(--clr-border);
  border-radius: var(--radius-md);
  background: var(--clr-surface);
  color: var(--clr-text-secondary);
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  white-space: nowrap;
  margin-left: auto;
  font-variant-numeric: tabular-nums; /* largura fixa dos digitos: sem tremer */
}
.sp-sessao[hidden] { display: none; }
.sp-sessao svg { width: 14px; height: 14px; flex: 0 0 auto; }

.sp-sessao-normal { color: var(--clr-text-secondary); }

.sp-sessao-aviso {
  border-color: var(--clr-warning);
  background: var(--clr-warning-subtle);
  color: #92400e; /* mesmo tom do .sp-badge-warning: 7.4:1 sobre #fffbeb */
}

.sp-sessao-critico {
  border-color: var(--clr-danger);
  background: var(--clr-danger-subtle);
  color: #991b1b; /* mesmo tom do .sp-status-denegado: 8.1:1 sobre #fef2f2 */
  /* Pulso lento e sutil. Animacao de atencao, nao de desespero — e respeita
     quem pediu menos movimento no sistema operacional. */
  animation: sp-sessao-pulso 2s var(--ease) infinite;
}
@keyframes sp-sessao-pulso {
  0%, 100% { opacity: 1; }
  50% { opacity: .72; }
}
@media (prefers-reduced-motion: reduce) {
  .sp-sessao-critico { animation: none; }
}

/* No celular a barra nao tem largura para tres controles lado a lado: o
   relogio desce para a propria linha e ocupa a largura toda. Ele e' o aviso
   mais importante da barra, entao ganha destaque em vez de sumir. */
@media (max-width: 767px) {
  .sp-sessao {
    min-height: var(--touch);
    margin-left: 0;
    order: 3;
    flex: 1 0 100%;
    justify-content: center;
  }
}

/* Tabelas: rolagem horizontal garantida (sem quebrar textos na vertical) */
.sp-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.sp-table td { white-space: nowrap; }
.sp-table td.sp-cell-wrap { white-space: normal; word-break: break-word; }

/* Células com valor longo (chave, NSU, protocolo): mantém em linha, scrolla */
.sp-mono {
  font-family: 'JetBrains Mono', 'Courier New', monospace;
  white-space: nowrap;
  letter-spacing: -.01em;
}

/* Impede conteúdo de estourar horizontalmente em qualquer container */
.sp-card, .wp-modal, .sp-table-wrap, .sp-page-header, .sp-stats-grid { max-width: 100%; }

/* ============================================================
   RESPONSIVIDADE GLOBAL (guias, tabelas, touch) — não depende de Tailwind runtime
   ============================================================ */

/* Guias/tabs: rolam horizontalmente quando não cabem (nada de guia cortada) */
.sp-tabs-bar, .sp-tab-bar, [class*="tab-bar"] {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  flex-wrap: nowrap;
}
.sp-tab {
  white-space: nowrap;
  flex-shrink: 0;
}

/* Tabelas: NUNCA quebrar textos na vertical — rolar para os lados (como o usuário pediu) */
table { max-width: 100%; border-collapse: collapse; }
table th, table td { white-space: nowrap; }

/* O container de rolagem da tabela.
   ATENCAO ao `position: relative`: o cabecalho (.sp-table th) e a primeira
   coluna (.sp-table-fix-first) sao `position: sticky`. Se o container de
   rolagem nao for o ancestral posicionado mais proximo, o sticky gruda na
   PAGINA em vez de grudar no container — e ai o cabecalho "foge" ao rolar.
   Antes disto o card inteiro tinha `overflow-x: auto`, o que o tornava
   tambem o container de rolagem e o contexto de recorte: o cabecalho
   travava no card, a coluna fixa travava errado e o border-radius do card
   era cortado. Agora a rolagem e' SO deste wrapper. */
.sp-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  max-width: 100%;
  position: relative;
  border-radius: inherit;
}

/* Rede de seguranca: tabela que ficou sem wrapper explicito recebe a
   rolagem E a dica de "arraste para o lado".
   `.sp-table-wrap` tambem casa aqui (o wrapper de verdade costuma envolver
   uma `table`), mas o JS deduplica por elemento — a dica e' criada uma vez. */
.sp-table-wrap,
table:not(.sp-tabela-crua) {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  max-width: 100%;
}

/* Inputs e elementos não estouram o container */
input, select, textarea { max-width: 100%; }
.sp-grid-2, .sp-grid-3, .sp-grid-4, .sp-stats-grid { max-width: 100%; }

/* Children de flex não empurram o container pra fora */
.flex > * { min-width: 0; }

/* Flex rows: quebram linha em vez de estourar botões/labels (mobile) */
.flex { flex-wrap: wrap; }

/* Card NUNCA rola lateral. Isto era `overflow-x: auto !important` em
   .sp-card e em QUALQUER [class*="rounded-xl"], que e' praticamente todo
   container do sistema — inclusive os modais e os grids de card do MDFe.
   O resultado eram tres bugs de uma vez:
     1) o card virava contexto de recorte, matando o `position: sticky`
        do cabecalho da tabela e da primeira coluna;
     2) o `overflow-x: auto` forca `overflow-y: auto` implicito, e o card
        ganhava uma barra de rolagem propria (mais uma);
     3) `border-radius` + `overflow: hidden` do card deixava a barra
        desenhada por cima da borda arredondada.
   Quem rola e' o `.sp-table-wrap` / `.damdfe-modal-body`, nunca o card.
   `min-width: 0` e' o que IMPEDE o estouro: sem ele um filho em flex/grid
   com conteudo largo empurra o container para fora da tela. */
.sp-card {
  overflow: visible;
  min-width: 0;
}

/* Grids no mobile: viram 1 coluna (nada espremido, nada cortado) */
@media (max-width: 767px) {
  [class*="grid-cols-"] { grid-template-columns: 1fr !important; }
}

/* ============================================================
   CARD MDFE — botões XML/PDF
   Desktop: topo direito (como sempre foi). Mobile: rodapé lado a lado.
   ============================================================ */
.mdfe-card-download { position: absolute; top: 12px; right: 12px; }
@media (max-width: 767px) {
  .mdfe-card { display: flex; flex-direction: column; }
  .mdfe-card-download {
    position: static;
    order: 99;
    margin-top: 10px;
    align-self: flex-end;
  }
}

/* ============================================================
   ALERTAS — caixas de aviso embutidas na tela
   Antes existiam como utilitarios Tailwind repetidos a mao em varias
   telas (bg-red-50 border border-red-200 ...), cada uma com um tamanho
   diferente. Agora tem uma fonte unica.
   ============================================================ */
.sp-alerta {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 14px;
  border: 1px solid var(--clr-border);
  border-left-width: 4px;
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  line-height: 1.5;
}

.sp-alerta-erro {
  background: var(--clr-danger-subtle);
  border-color: var(--clr-danger-light);
  border-left-color: var(--clr-danger);
  color: var(--clr-danger);
}

.sp-alerta-aviso {
  background: var(--clr-warning-subtle);
  border-color: var(--clr-warning-light);
  border-left-color: var(--clr-warning);
  color: var(--clr-warning);
}

.sp-alerta-sucesso {
  background: var(--clr-success-subtle);
  border-color: var(--clr-success-light);
  border-left-color: var(--clr-success);
  color: var(--clr-success);
}

.sp-alerta-info {
  background: var(--clr-primary-subtle);
  border-color: var(--clr-primary-light);
  border-left-color: var(--clr-primary);
  color: var(--clr-primary);
}

/* Variante grande, para alerta de bloco inteiro (ex.: erro que ocupa
   o lugar da tela toda). */
.sp-alerta-lg {
  padding: 20px 22px;
  border-radius: var(--radius-lg);
  font-size: var(--text-base);
}

/* Titulo opcional dentro do alerta */
.sp-alerta-titulo {
  display: block;
  font-weight: var(--font-semibold);
  margin-bottom: 2px;
}

/* No mobile o alerta nunca fica apertado */
@media (max-width: 640px) {
  .sp-alerta { padding: 11px 12px; font-size: var(--text-xs); }
  .sp-alerta-lg { padding: 16px; font-size: var(--text-sm); }
}

/* ============================================================
   COMPLEMENTOS — classes que faltavam para tirar os ultimos
   utilitarios crus das telas.
   ============================================================ */

/* Cabecalho de tabela quando a <table> nao usa .sp-table (tabelas
   montadas dinamicamente so com <thead>). Visual identico ao
   .sp-table th, para nao existirem dois padroes de cabecalho. */
.sp-table-head {
  background: var(--clr-bg);
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  color: var(--clr-text-secondary);
  text-transform: uppercase;
  letter-spacing: .06em;
}

/* ---------------------------------------------------------------
   SOMBRA LATERAL: "esta tabela tem mais conteudo para o lado"

   As classes de ESTADO sao mantidas pelo app.js
   (marcarRolagemHorizontal / atualizarSeta), recalculadas a cada rolagem:
     .tem-mais-dir  -> ha conteudo escondido a DIREITA
     .tem-mais-esq  -> ha conteudo escondido a ESQUERDA (ja' rolou)

   POR QUE A SOMBRA DEPENDE DO ESTADO, e nao de estar marcado no markup:
   antes a sombra vinha de `.sp-table-wrap.sp-table-scrollable::after`, e
   `sp-table-scrollable` era escrita A MAO em 8 tabelas apenas. Toda tabela
   que o JS descobria sozinho ganhava a dica mas NENHUMA sombra — e eram
   justamente as telas onde o usuario reclamava de "nao tem sinalizacao
   nenhuma". Amarrada ao estado, a sombra:
     1) vale para todo container que o JS marcar, com ou sem wrapper;
     2) ACENDE E APAGA conforme a ponta — ao chegar no fim, a sombra da
        direita apaga; ao voltar para o inicio, apaga a da esquerda. Nao
        fica sinalizando uma acao que ja' nao existe;
     3) e' dos DOIS lados, entao mostra que ha conteudo para tras.

   `position: relative` e' obrigatorio: sem ancestral posicionado o
   pseudo-elemento escapa para a pagina e a sombra aparece no lugar
   errado. O `.sp-table-wrap` ja' nasce com ele; a regra abaixo cobre as
   tabelas que o JS marca direto, sem wrapper.

   z-index 4: fica ACIMA do cabecalho sticky (z-index 2), senao a sombra
   sumiria justamente na faixa do cabecalho. Fica ABAIXO da dica de
   rolagem (z-index 5), que e' a sinalizacao principal e nunca pode ser
   coberta. Nas tabelas com primeira coluna congelada
   (.sp-table-fix-first, z-index 4) a sombra da esquerda fica atras da
   coluna — sem prejuizo: a coluna congelada ja' e' a propria sinalizacao.

   NOTA: o modal do DAMDFe (.damdfe-modal-body) resolve o mesmo problema
   com `box-shadow: inset`. La' funciona porque a folha A4 e' o unico
   filho e nao ha nada opaco cobrindo a borda. Em tabela NAO serve: o
   `inset` pinta ATRAS do conteudo, e o cabecalho (.sp-table th, com
   fundo proprio) engoliria a sombra. Por isso aqui e' pseudo-elemento.
   --------------------------------------------------------------- */
.sp-table-scrollable { position: relative; }

.sp-table-scrollable.tem-mais-dir::after,
.sp-table-scrollable.tem-mais-esq::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  width: 24px;
  pointer-events: none;
  z-index: 4;
}
.sp-table-scrollable.tem-mais-dir::after {
  right: 0;
  background: linear-gradient(to right, transparent, rgba(15, 23, 42, .10));
}
.sp-table-scrollable.tem-mais-esq::before {
  left: 0;
  background: linear-gradient(to left, transparent, rgba(15, 23, 42, .10));
}

/* Alerta centralizado (erro que ocupa a tela no lugar do conteudo) */
.sp-alerta-centro {
  display: block;
  text-align: center;
}

/* Bloco <pre> de detalhes tecnicos (retorno cru da SEFAZ, stack de erro).
   Rola na horizontal em vez de quebrar a linha — o texto e' tecnico e
   quebrar atrapalha a leitura. */
.sp-log-detalhe {
  margin-top: 4px;
  padding: 8px;
  border-radius: var(--radius-sm);
  background: var(--clr-bg);
  color: var(--clr-text-secondary);
  font-family: 'JetBrains Mono', 'Courier New', monospace;
  font-size: var(--text-xs);
  line-height: 1.5;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 200px;
  overflow-y: auto;
}

@media (max-width: 640px) {
  .sp-log-detalhe { font-size: 11px; padding: 7px; }
}

/* Variantes de badge que faltavam */
.sp-badge-solid { background: var(--clr-success); color: #fff; }
.sp-badge-xs {
  font-size: 10px;
  padding: 2px 7px;
  font-weight: var(--font-bold);
  letter-spacing: .03em;
}

/* ============================================================
   BOTOES DE OPCAO DE MODAL (.mdl-btn)
   Usados no modal "qual modelo?" do MDFE. Antes nao tinham CSS
   proprio — o visual vinha de utilitarios Tailwind repetidos a mao
   em cada uso, entao qualquer ajuste tinha de ser feito em N lugares.
   ============================================================ */
.mdl-btn {
  display: block;
  width: 100%;
  padding: 14px 16px;
  border: 2px solid var(--clr-border);
  border-radius: var(--radius-lg);
  background: var(--clr-surface);
  color: var(--clr-text);
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  line-height: 1.45;
  text-align: left;
  cursor: pointer;
  transition: border-color var(--dur-fast, .15s) var(--ease),
              background var(--dur-fast, .15s) var(--ease);
}

/* Espaco entre botoes QUANDO empilhados. Dentro de .mdl-grade quem
   cuida do espaco e' o `gap` do grid — sem este reset, o segundo cartao
   descia 10px a mais que o primeiro e a grade ficava torta. */
.mdl-btn + .mdl-btn { margin-top: 10px; }
.mdl-grade .mdl-btn + .mdl-btn { margin-top: 0; }

.mdl-btn:hover,
.mdl-btn:focus-visible {
  border-color: var(--clr-primary);
  background: var(--clr-primary-subtle);
  outline: none;
}

/* Opcao secundaria (borda neutra ate passar o mouse) */
.mdl-btn-opcao { border-color: var(--clr-border); }

/* Opcao ja escolhida / recomendada (fica destacada de saida) */
.mdl-btn-ativo {
  border-color: var(--clr-primary);
  background: var(--clr-primary-subtle);
}

/* No mobile o alvo de toque precisa ser >= 44px de altura */
@media (max-width: 640px) {
  .mdl-btn { padding: 15px 14px; min-height: var(--touch); }
}

/* ============================================================
   SUPERFICIES NEUTRAS — caixas internas, blocos de detalhe, linhas
   clicaveis. Antes eram bg-slate-50 / bg-slate-100 espalhados nas
   telas, cada um com um raio e um padding diferente.
   ============================================================ */

/* Caixa neutra: agrupa um bloco de conteudo dentro de um card */
.sp-caixa {
  background: var(--clr-bg);
  border: 1px solid var(--clr-border);
  border-radius: var(--radius-lg);
  padding: 12px;
}

/* Mesma caixa, sem borda (so o fundo) */
.sp-caixa-simples {
  background: var(--clr-bg);
  border-radius: var(--radius-lg);
  padding: 12px;
}

/* Linha clicavel dentro de uma lista (hover discreto) */
.sp-linha-hover {
  cursor: pointer;
  border-radius: var(--radius-md);
  transition: background var(--dur-fast, .15s) var(--ease);
}
.sp-linha-hover:hover { background: var(--clr-surface-hover); }

/* Cabecalho / rodape de tabela com fundo neutro */
.sp-table-neutro {
  background: var(--clr-bg);
  border-bottom: 1px solid var(--clr-border);
}

/* Bloco de detalhe monoespacado (retorno tecnico em caixa clara) */
.sp-detalhe-mono {
  background: var(--clr-bg);
  border: 1px solid var(--clr-border);
  border-radius: var(--radius-md);
  padding: 10px;
  font-family: 'JetBrains Mono', 'Courier New', monospace;
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--clr-text-secondary);
  white-space: pre-wrap;
  word-break: break-word;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* Faixa de log com barra lateral colorida (sucesso/erro) */
.sp-log-item {
  background: var(--clr-bg);
  border-left: 4px solid var(--clr-border);
  border-radius: var(--radius-lg);
  padding: 12px;
  font-size: var(--text-sm);
}
.sp-log-item-ok  { border-left-color: var(--clr-success); }
.sp-log-item-err { border-left-color: var(--clr-danger); }

/* ---- Aviso de certificado (CONFIG) ---- */
.sp-cert-ok {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 12px;
  margin-bottom: 12px;
  border: 1px solid var(--clr-success-light);
  border-radius: var(--radius-lg);
  background: var(--clr-success-subtle);
  font-size: var(--text-sm);
}
.sp-cert-bloco {
  padding: 16px;
  margin-bottom: 16px;
  border: 1px solid var(--clr-success-light);
  border-radius: var(--radius-lg);
  background: var(--clr-success-subtle);
}
.sp-badge-pleno {
  font-size: 10px;
  font-weight: var(--font-bold);
  text-transform: uppercase;
  letter-spacing: .04em;
  padding: 2px 8px;
  border-radius: var(--radius-sm);
  background: var(--clr-success-light);
  color: #166534;
}
.sp-badge-neutro {
  font-size: var(--text-xs);
  padding: 2px 8px;
  border-radius: var(--radius-full);
  background: var(--clr-surface-dim);
  color: var(--clr-text-muted);
}

/* No mobile as caixas internas reduzem o respiro, senao o conteudo
   fica com margem dupla dentro do card. */
@media (max-width: 640px) {
  .sp-caixa, .sp-caixa-simples { padding: 10px; }
  .sp-log-item { padding: 10px; }
  .sp-cert-bloco { padding: 12px; }
}

/* ============================================================
   CORES DE TEXTO SEMANTICAS
   Substituem text-red-600 / text-amber-600 / text-emerald-600, que
   apareciam soltos em mensagens de erro, aviso e sucesso.
   ============================================================ */
.sp-text-erro    { color: var(--clr-danger); font-weight: var(--font-semibold); }
.sp-text-aviso   { color: var(--clr-warning); font-weight: var(--font-semibold); }
.sp-text-ok      { color: var(--clr-success); font-weight: var(--font-semibold); }
.sp-text-neutro  { color: var(--clr-text-muted); }

/* Versao sem negrito, para mensagens longas (o negrito em paragrafo
   inteiro atrapalha a leitura no mobile). */
.sp-text-erro-leve  { color: var(--clr-danger); }
.sp-text-aviso-leve { color: var(--clr-warning); }
.sp-text-ok-leve    { color: var(--clr-success); }

/* Link de acao destrutiva em tabela (ex.: "Excluir" em texto puro) */
.sp-link-perigo {
  color: var(--clr-danger);
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  cursor: pointer;
  background: none;
  border: 0;
  padding: 2px 4px;
  border-radius: var(--radius-sm);
  transition: color var(--dur-fast, .15s) var(--ease);
}
.sp-link-perigo:hover { color: var(--clr-danger-strong, #991b1b); text-decoration: underline; }

/* Ponto de status colorido (icones do dashboard) */
.sp-ponto-ok    { color: var(--clr-success); }
.sp-ponto-aviso { color: var(--clr-warning); }
.sp-ponto-erro  { color: var(--clr-danger); }

/* Campo realcado (valor preenchido automaticamente, ex.: importacao de CNPJ).
   Deixa claro que aquele dado veio do sistema, nao foi digitado. */
.sp-input-destaque {
  border-color: var(--clr-success);
  background: var(--clr-success-subtle);
  font-weight: var(--font-semibold);
}

/* Texto auxiliar muito pequeno (rodape de bloco, nota de rodape) */
.sp-texto-min {
  font-size: 11px;
  color: var(--clr-text-muted);
  line-height: 1.45;
}

/* Divisor neutro que separa blocos */
.sp-divisor-ok { border-top: 1px solid var(--clr-success-light); }

/* ============================================================
   MODAL PADRAO DO SISTEMA
   Existia so uma regra solta de mobile para .sp-modal, sem o
   conjunto. Cada tela montava o proprio modal com utilitario cru
   (fixed inset-0 bg-black/40 flex items-center justify-center p-4),
   o que dava tres problemas recorrentes:
     - o p-4 comia a largura e cortava campo no celular;
     - o cabecalho ocupava espaco demais;
     - campos estouravam para fora do modal.
   ============================================================ */
.sp-modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 20000;
  background: rgba(15, 23, 42, .5);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}

.sp-modal {
  background: var(--clr-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  width: 100%;
  max-width: 640px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.sp-modal-lg { max-width: 900px; }
.sp-modal-sm { max-width: 420px; }

.sp-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--clr-border);
  flex-shrink: 0;
}

.sp-modal-titulo {
  margin: 0;
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  color: var(--clr-text);
}

.sp-modal-fechar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--touch-sm);
  height: var(--touch-sm);
  flex-shrink: 0;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--clr-text-secondary);
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease);
}
.sp-modal-fechar:hover { background: var(--clr-surface-dim); color: var(--clr-text); }

.sp-modal-corpo {
  padding: 18px;
  overflow-y: auto;
  flex: 1;
  min-height: 0;
  -webkit-overflow-scrolling: touch;
}

.sp-modal-rodape {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  padding: 14px 18px;
  border-top: 1px solid var(--clr-border);
  background: var(--clr-surface);
  flex-shrink: 0;
}

/* ---- Auxiliares de formulario ---- */
.sp-check {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  font-size: var(--text-sm);
  color: var(--clr-text-secondary);
  min-height: 32px;
}
.sp-check input[type="checkbox"] {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  accent-color: var(--clr-primary);
  cursor: pointer;
}

/* Titulo de secao dentro de um formulario longo */
.sp-secao-titulo {
  border-top: 1px solid var(--clr-border);
  padding-top: 14px;
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  color: var(--clr-text);
}

/* <summary> clicavel (bloco que abre/fecha) */
.sp-detalhe-toggle {
  cursor: pointer;
  color: var(--clr-primary);
  font-weight: var(--font-semibold);
  font-size: var(--text-sm);
  padding: 4px 0;
  min-height: 32px;
}

/* ============================================================
   DICA DE ROLAGEM HORIZONTAL
   O usuario reclamou: "nem sinalizacao que precisa rolar para as
   laterais tem no sistema, como q o usuario vai saber? ele vai
   adivinhar?" — com razao. Isto e' o aviso explicito.
   Aparece SÓ quando existe conteudo escondido (nao numa tabela que cabe na
   tela), mas NAO some ao chegar na ponta — ver a regra de visibilidade
   logo abaixo do bloco.
   ============================================================ */
.sp-scroll-dica {
  display: none;
  /* FLUTUANTE E CENTRALIZADA — nao pode ser arrastada junto com o conteudo.
     O usuario reclamou: "o botao 'arraste para os lados' deve sempre ficar
     flutuante centralizado e nao ser arrastado junto".

     COMO FUNCIONA: num elemento `sticky`, `left` e' um afastamento medido a
     partir da BORDA DO SCROLLPORT (a area visivel), e o percentual resolve
     contra a caixa do container — ou seja, 50% da LARGURA VISIVEL, nao da
     largura do conteudo. Com `translateX(-50%)` o CENTRO da dica cai
     exatamente na metade da area visivel.

     O `sticky` so' empurra o elemento quando a posicao NATURAL dele ficaria
     aquem do limite. Por isso a posicao natural precisa estar sempre a' ESQUERDA
     do limite: como a dica e' o ultimo filho de um bloco e nao tem margem
     lateral automatica, sua posicao natural e' a borda esquerda do conteudo
     (coordenada 0), que na tela vale `-scrollLeft` — sempre <= 0. Logo ela e'
     SEMPRE presa na marca de 50%, em qualquer posicao de rolagem.

     O BUG ERA O `margin: 10px auto 0` da versao anterior. O `auto` lateral
     jogava a posicao natural para o CENTRO DO CONTEUDO: o `left: 0` de entao
     nada tinha para prender, e a dica viajava junto com a tabela ate' bater na
     borda esquerda — exatamente o que o usuario viu. */
  position: sticky;
  left: 50%;
  transform: translateX(-50%);
  bottom: 0;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 12px;
  background: var(--clr-text);
  color: #fff;
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  border-radius: var(--radius-full);
  width: fit-content;
  /* Sem `auto` nas laterais — e' o `auto` que quebra a centralizacao. */
  margin: 10px 0 0;
  box-shadow: var(--shadow-md);
  pointer-events: none;
  z-index: 5;
}
.sp-scroll-dica-icone { font-size: 15px; line-height: 1; }

/* QUEM MANDA NA VISIBILIDADE DA DICA e' a MARCA `sp-table-scrollable`, nao o
   estado da ponta. `sp-table-scrollable` = "este container rola na
   horizontal" (escrita pelo app.js e pelo modal da folha A4), e e' a unica
   coisa que a dica precisa saber para existir.

   ANTES a regra era `.tem-mais-dir > .sp-scroll-dica`. Como `tem-mais-dir`
   SAI quando o usuario chega no fim da barra, a dica SUMIA justamente ali —
   e so' voltava se ele retornasse um pouco. Foi esse o defeito relatado:
   "na hora de chegar ao final da barra de rolagem o nome flutuante
   desaparece e so' volta quando a pessoa retorna a barra um pouco, isso nao
   pode acontecer".

   O motivo de estar errado: a dica e' um AVISO ("da' pra arrastar"), nao um
   contador do que ainda falta. Aviso nao depende de quanto sobra. Quem conta
   o que falta sao as SOMBRAS (`.tem-mais-dir` / `.tem-mais-esq`), e essas
   continuam apagando na ponta — ali sim faz sentido, porque a sombra
   sinaliza "tem coisa escondida deste lado" e na ponta nao tem mais. */
.sp-table-scrollable > .sp-scroll-dica { display: flex; }

/* ============================================================
   MODAL DO DAMDFe / DANFE
   A folha e' A4 (794px). Nao pode ser espremida — o container
   rola. E a rolagem horizontal e' AVISADA, nao escondida.
   ============================================================ */
.damdfe-modal {
  position: fixed;
  inset: 0;
  z-index: 20000;
  background: var(--clr-bg);
  display: flex;
  flex-direction: column;
}

.damdfe-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 14px;
  background: var(--clr-surface);
  border-bottom: 1px solid var(--clr-border);
  flex-shrink: 0;
}

.damdfe-modal-titulo {
  margin: 0;
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  color: var(--clr-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.damdfe-modal-acoes {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-shrink: 0;
}

.damdfe-modal-body {
  flex: 1;
  min-height: 0;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  padding: 12px;
  background: var(--clr-surface-dim);
  position: relative;
}

/* A FOLHA: largura FIXA de A4. Nunca encolhe — se nao couber, o
   container rola. E' isso que impede o layout de quebrar em colunas
   tortas (o problema relatado). */
.damdfe-folha {
  width: 794px;
  min-width: 794px;
  margin: 0 auto;
  background: #fff;
  box-shadow: var(--shadow-md);
}

/* Sombra lateral = "tem mais coisa para este lado".

   AQUI e' `inset` de proposito, e nao o pseudo-elemento usado nas tabelas:
   um `::before`/`::after` com posicionamento absoluto ROLA JUNTO com o
   conteudo (o absoluto acompanha o scroll do ancestral), entao numa folha A4
   ele sairia da tela. O `inset` fica preso a caixa VISIVEL do container, que
   e' exatamente onde a sinalizacao precisa ficar.

   A OPACIDADE CAIU DE .45 PARA .10 — e o `blur` subiu, para nao sobrar
   aresta. Com .45 o usuario via uma "parede cinzenta" que brotava do nada no
   instante em que ele comecava a arrastar: "tem uma especie de parede/borda
   cinzenta depois do nome DANFE quando se comeca a arrastar a rolagem".
   Nao era para parecer um defeito de renderizacao: a intencao sempre foi a
   mesma sombra suave das tabelas. .10 e' o MESMO peso usado la', entao a
   sinalizacao passa a ser coerente no sistema inteiro — e o aviso principal
   do modal continua sendo a dica flutuante, que agora nunca desaparece. */
.damdfe-modal-body.tem-mais-dir {
  box-shadow: inset -18px 0 16px -16px rgba(15, 23, 42, .10);
}
.damdfe-modal-body.tem-mais-esq {
  box-shadow: inset 18px 0 16px -16px rgba(15, 23, 42, .10);
}
.damdfe-modal-body.tem-mais-dir.tem-mais-esq {
  box-shadow: inset -18px 0 16px -16px rgba(15,23,42,.10),
              inset 18px 0 16px -16px rgba(15,23,42,.10);
}

/* O modal da folha A4 carrega a marca `sp-table-scrollable` (ele ROLA na
   horizontal, e e' essa a marca que faz a dica aparecer — a mesma das
   tabelas). So' que a marca tambem liga as sombras por PSEUDO-ELEMENTO, e
   aqui elas nao podem existir:
     1) o modal ja' tem sombra propria, por `inset` (logo acima);
     2) o `::after` e' `position: absolute`, e dentro de um container que rola
        o absoluto ACOMPANHA o scroll — a faixa iria parar no fim da folha em
        vez de ficar na borda visivel.
   Esta regra e' uma EXCECAO EXPLICITA, e nao um `:not()` no seletor original:
   assim as regras de sombra das tabelas continuam legiveis como estao. Como
   a especificidade e' igual (0,2,0), quem decide e' a ORDEM — por isso esta
   regra vem DEPOIS das sombras. */
.damdfe-modal-body.tem-mais-dir::after,
.damdfe-modal-body.tem-mais-esq::before {
  content: none;
  display: none;
}

/* ============================================================
   VARIANTES DE ACAO COLORIDAS
   O usuario reclamou (com razao): "pq vc tirou as cores dos botoes
   q facilitam a identificacao?" — ao padronizar, tudo virou cinza
   (sp-btn-secondary) e o usuario perdeu a pista visual de qual botao
   faz o que. Num card com 9 acoes, cor e' NAVEGACAO, nao enfeite.

   Estas variantes tem fundo suave + texto forte: identificam a acao
   de longe sem competir com o botao primario da tela (que continua
   sendo o solido).
   ============================================================ */
.sp-btn-suave-ok {
  background: var(--clr-success-light);
  color: #14532d;
  border-color: transparent;
}
.sp-btn-suave-ok:hover { background: #bbf7d0; filter: none; }

.sp-btn-suave-erro {
  background: var(--clr-danger-light);
  color: #991b1b;
  border-color: transparent;
}
.sp-btn-suave-erro:hover { background: #fecaca; filter: none; }

.sp-btn-suave-info {
  background: var(--clr-primary-light);
  color: #1e40af;
  border-color: transparent;
}
.sp-btn-suave-info:hover { background: #bfdbfe; filter: none; }

.sp-btn-suave-aviso {
  background: var(--clr-warning-light);
  color: #92400e;
  border-color: transparent;
}
.sp-btn-suave-aviso:hover { background: #fde68a; filter: none; }

/* Neutro: abre, visualiza ou BAIXA. Cinza claro, sem carga semantica.
   (O comentario anterior dizia "neutro escuro: para Encerrar" — mas o valor
   era o cinza CLARO, entao "Encerrar" e "Detalhes" ficavam identicos. A cor
   prometida no comentario nao existia.) */
.sp-btn-suave-neutro {
  background: var(--clr-surface-dim);
  color: var(--clr-text);
  border-color: transparent;
}
.sp-btn-suave-neutro:hover { background: var(--clr-border); filter: none; }

/* Violeta: acao que DUPLICA (Clonar). Distinto do azul da consulta de
   proposito — eram os dois a mesma cor. */
.sp-btn-suave-violeta {
  background: var(--clr-violeta-light);
  color: #5b21b6;
  border-color: transparent;
}
.sp-btn-suave-violeta:hover { background: #ddd6fe; filter: none; }

/* ESCURO: acao que ENCERRA o ciclo (Encerrar). Nao e' destrutiva (nao vai de
   vermelho) nem positiva (nao vai de verde) — ela FECHA o documento. Fundo
   escuro resolve porque e' o unico botao escuro do card: distingue-se de
   qualquer outro de relance. Medido: branco sobre #0f172a = 17,85:1. */
.sp-btn-suave-escuro {
  background: var(--clr-text);
  color: #ffffff;
  border-color: transparent;
}
.sp-btn-suave-escuro:hover { background: #1e293b; filter: none; }

/* ============================================================
   BARRA DE FILTROS — Empresa + Status na MESMA linha
   O usuario reclamou: "ta muito espacado causando desperdicio de
   espaco, isso no mobile fica horrivel". O padrao era:
     linha 1 -> label + select de largura fixa
     linha 2 -> label + chips
   Dois campos, duas faixas de titulo, ~120px de altura. Agora e' um
   bloco so', que quebra em linhas no celular e alinha na base no
   desktop (o label do select alinha com o label dos chips).
   ============================================================ */
.sp-filtros {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px 16px;
  margin-bottom: 16px;
}
.sp-filtro-campo {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
  flex: 1 1 200px;
  max-width: 320px;
}
.sp-filtro-grupo {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
  flex: 1 1 260px;
}

/* Chips de status: linha unica que ROLA quando nao cabe.
   De proposito nao usa flex-wrap: os chips tem de manter a leitura
   horizontal (Todos | Rascunho | Autorizado...). Se quebrassem em duas
   linhas viraria o mesmo desperdicio vertical que estava sendo corrigido.
   Como rola, o aviso de "arraste para o lado" e' ligado pelo app.js. */
.sp-chips {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 6px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding-bottom: 2px;
}
.sp-chips::-webkit-scrollbar { display: none; }

.sp-chip {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: var(--touch-sm);
  padding: 0 14px;
  border: 1px solid var(--clr-border);
  border-radius: var(--radius-full);
  background: var(--clr-surface);
  color: var(--clr-text-secondary);
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.sp-chip:hover { background: var(--clr-surface-dim); color: var(--clr-text); }
.sp-chip-ativo,
.sp-chip-ativo:hover {
  background: var(--clr-primary);
  border-color: var(--clr-primary);
  color: #fff;
}

/* ============================================================
   DADO ROTULADO — "Trajeto: Sao Paulo -> Curitiba"
   Antes cada modulo montava isso com utilitarios crus e um
   `style="min-width:64px"` no rotulo. O rotulo era o texto mais
   claro da tela (#94a3b8, 2.56:1) — era o que o usuario nao
   conseguia ler. Aqui o rotulo ganha o token secundario e o VALOR
   ganha o token principal: o dado e' o que se le de verdade.
   ============================================================ */
.sp-dado {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
}
.sp-dado-rotulo {
  flex-shrink: 0;
  min-width: 68px;
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  color: var(--clr-text-muted);
}
.sp-dado-valor {
  min-width: 0;
  font-size: var(--text-sm);
  color: var(--clr-text);
}
.sp-dado-truncar {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Valor que merece destaque (numero do documento, placa) */
.sp-dado-forte { font-weight: var(--font-bold); }

/* ============================================================
   CARD MDFE — cabecalho, corpo, rodape
   O card era montado com `px-4 pt-3 pb-2 grid gap-y-2`: as faixas
   ficavam com alturas diferentes e o conjunto parecia "solto".
   Aqui o espacamento e' declarado em um lugar so', para todos os
   cards ficarem iguais — e mais enxuto no celular, que era a queixa
   de desperdicio de espaco.
   ============================================================ */
.mdfe-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 14px 10px;
  border-bottom: 1px solid var(--clr-divider);
}
.mdfe-card-titulo { min-width: 0; }
.mdfe-card-linha-id {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.mdfe-card-numero {
  font-size: var(--text-lg);
  font-weight: var(--font-bold);
  color: var(--clr-text);
  font-variant-numeric: tabular-nums;
}
.mdfe-card-rota {
  margin-top: 2px;
  font-size: var(--text-sm);
  color: var(--clr-text-secondary);
}
.mdfe-card-rota span { font-weight: var(--font-semibold); color: var(--clr-text); }

.mdfe-card-corpo {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 16px;
  row-gap: 8px;
  padding: 12px 14px;
}
.mdfe-card-erro { margin: 0 14px 12px; }

.mdfe-card-botoes {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 0 14px 12px;
}

.mdfe-card-rodape {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 14px 12px;
  border-top: 1px solid var(--clr-divider);
}

@media (max-width: 640px) {
  /* Uma coluna no celular: dois dados por linha em 412px de tela
     espremiam o valor ate' cortar. */
  .mdfe-card-corpo { grid-template-columns: 1fr; }
  .mdfe-card-head { padding: 10px 12px 8px; }
  .mdfe-card-corpo, .mdfe-card-botoes { padding-left: 12px; padding-right: 12px; }
  .mdfe-card-rodape { padding: 8px 12px 10px; }
  /* No celular o rotulo vira uma legenda ACIMA do valor. Lado a lado,
     "Protocolo: 1234..." ficava com ~200px para os dois. */
  .sp-dado { flex-direction: column; align-items: flex-start; gap: 2px; }
  .sp-dado-rotulo { min-width: 0; }
}

/* Cabecalho do modulo MDFe: titulo + acoes numa linha so' */
.mdfe-header { margin-bottom: 14px; }
.mdfe-header-acoes {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  flex-shrink: 0;
}
@media (max-width: 767px) {
  /* O subtitulo ("Emissao de Manifestos...") e' decorativo e ocupava
     uma linha inteira no celular. O titulo ja diz o que e' a tela. */
  .mdfe-header .sp-page-header-sub { display: none; }
  .mdfe-header-acoes { width: 100%; }
  .mdfe-header-acoes .sp-btn { flex: 1 1 140px; }
}

/* ============================================================
   USO GERAL — complementos das tabelas e utilitarios
   ============================================================ */
.sp-cell-centro { text-align: center; }
.sp-cell-destaque { font-weight: var(--font-semibold); color: var(--clr-text); }
.sp-cell-nota {
  font-size: var(--text-xs);
  color: var(--clr-text-secondary);
  letter-spacing: .01em;
}

/* Barra Empresa + acoes da tela de XMLs */
.mdfe-xmls-barra {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px 16px;
  margin-bottom: 16px;
}
.mdfe-xmls-acoes {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  flex: 1 1 auto;
  justify-content: flex-end;
}

/* Paginacao: botoes quadrados, alinhados, com estado atual marcado */
.sp-paginacao {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 16px;
}

/* Esconde o input de arquivo mantendo-o acessivel para o label
   (o `hidden` do Tailwind depende do rebuild — isto nao depende). */
.sp-visualmente-oculto {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ============================================================
   MODAL DE ESCOLHA (cartoes de opcao) — DAMDFe modelo 1 x 2
   Existia em duas versoes na mesma funcao (uma "mobile" com style
   inline, outra "desktop" com Tailwind cru) e as duas divergiam:
   no desktop os cartoes ficavam lado a lado, no mobile empilhados,
   e as cores de borda eram literais (#e2e8f0, #2563eb) em vez dos
   tokens. Uma implementacao so', com o design system.
   ============================================================ */
.mdl-grade {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
@media (max-width: 640px) {
  /* Em 412px de tela, dois cartoes de opcao lado a lado nao cabem
     com legibilidade. Empilha. */
  .mdl-grade { grid-template-columns: 1fr; }
}

.mdl-btn-nome {
  font-size: var(--text-base);
  font-weight: var(--font-bold);
  color: var(--clr-text);
}
.mdl-btn-desc {
  margin-top: 2px;
  font-size: var(--text-xs);
  color: var(--clr-text-muted);
}
.mdl-btn-ativo .mdl-btn-nome { color: var(--clr-primary-strong, #1e40af); }
