/* ══════════════════════════════════════════════════════════════════════════════
   IDENTIDADE — Grupo GPS aplicada ao AlmoxSystem   (2026-08-25)

   Estratégia (a mesma desde o começo): em vez de reescrever as 830 linhas de
   componentes do styles.css, REMAPEAMOS os tokens que o app já usa (--surface,
   --label, --hairline, --acento…). Trocar token repinta o sistema inteiro sem tocar
   em layout — que é o que não pode quebrar num app em produção.

   ⚠️ O QUE MUDOU E POR QUÊ: a camada anterior era a identidade "painel HUD" — neon
   ciano, fundo de grade animada, varredura, brilho. Bonita e errada para este uso: o
   sistema é o instrumento de trabalho de quem passa a manhã dentro dele fechando
   requisição, e o cliente é o Grupo GPS. A identidade agora é a institucional do GPS,
   copiada do design system de `~/gestao-contratos` (DESIGN.md):

     azul-marinho #002D4E  a marca — barra lateral, títulos, valor de KPI
     azul de ação #004C97  TUDO que é interativo; se está nesse azul, responde ao clique
     azul vivo    #0A6ED1  topo do gradiente do botão primário e realce de hover
     névoa        #EEF1F6  o fundo da aplicação: frio o bastante para o branco do card
                           parecer superfície levantada, e não recorte

   Três regras herdadas junto com a paleta:
   • A REGRA DOS 10%: o azul de ação ocupa no máximo um décimo da tela. Duas ações
     primárias na mesma tela significam que uma delas está errada.
   • COR SEMÂNTICA É INFORMAÇÃO: verde, vermelho e laranja só aparecem quando falam de
     resultado ou estado. Nenhum deles é enfeite nem variação de marca.
   • VIDRO SÓ NA NAVEGAÇÃO: card de conteúdo é superfície OPACA, sempre.

   Do lado da forma nada foi jogado fora: raio concêntrico, sombra em camadas com fio
   de luz na aresta de cima e mola de verdade continuam — é o acabamento, não a
   identidade. O que saiu foi a ENERGIA cyber: sem grade animada, sem varredura, sem
   brilho de neon. "Nada quica, nada estica, nada pisca."

   Carrega POR ÚLTIMO, depois de styles.css, senão o app vence.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ── Tipografia: Ruda, local ─────────────────────────────────────────────── */
:root, :root[data-theme="dark"], :root[data-theme="light"] {
  --sans: 'Ruda', -apple-system, system-ui, sans-serif;
  --font-system: var(--sans);
}
body, input, textarea, select, button, table { font-family: var(--sans); }
/* Ruda é mais aberta que a Nunito: o mesmo texto ocupa mais. Compensa no rastreio. */
body { letter-spacing: -0.005em; }

/* ══ MARCA GPS — os tokens de cor, nos dois temas ════════════════════════════ */
:root {
  /* A marca, chapada. Estes três não mudam com o tema: são a identidade. */
  --gps-navy:       #002D4E;
  --gps-navy-deep:  #002443;
  --gps-navy-ink:   #001A31;
  --gps-blue:       #004C97;
  --gps-blue-bright:#0A6ED1;
  --gps-blue-soft:  #E8F0F9;
  --gps-gray:       #5F6263;
  --gps-gray-mid:   #8A8E90;
  --gps-gray-line:  #D8DDE4;
  /* Azul claro para superfície ESCURA (barra lateral e tema escuro): o azul de ação
     sobre navy mede 2,3:1 e some. Este é o mesmo azul, clareado até passar. */
  --gps-blue-dark-surface: #6BB0EE;
}

/* ══ TEMA CLARO — o padrão. É nele que a identidade do GPS vive ══════════════
   Ambiente claro e frio: névoa azulada sob superfícies brancas com sombra real. */
:root[data-theme="light"] {
  --canvas:  #EEF1F6;
  --mesh:    #EEF1F6;
  --surface: #FFFFFF;
  --surface-2: #F7F9FC;
  --surface-sunken: #F2F3F8;

  --label:  #0E1B29;
  --label2: rgba(14, 27, 41, 0.78);
  --label3: rgba(14, 27, 41, 0.65);
  --heading: var(--gps-navy);

  --navy: var(--gps-navy); --navy-deep: var(--gps-navy-deep); --navy-ink: var(--gps-navy-ink);
  --acento: var(--gps-blue); --acento-forte: var(--gps-blue-bright); --acento-sobre: #fff;
  --acento-suave: var(--gps-blue-soft); --acento-linha: rgba(0, 76, 151, 0.28);
  --acento-brilho: rgba(0, 76, 151, 0.22);
  --brand: var(--gps-blue); --brand-bright: var(--gps-blue-bright);
  --accent-solid: var(--gps-blue); --accent-solid-ink: #fff;
  /* O app antigo usa --neon* em alguns lugares; aqui eles são o azul de ação. */
  --neon: var(--gps-blue); --neon-forte: var(--gps-blue-bright);
  --neon-fundo: var(--gps-blue-soft); --neon-linha: rgba(0, 76, 151, 0.26);

  --hairline: var(--gps-gray-line); --hairline-firm: #C3CBD6;
  --edge: rgba(20, 34, 48, 0.08); --spec-top: rgba(255, 255, 255, 0.9);
  --fill: rgba(14, 27, 41, 0.05); --fill2: rgba(14, 27, 41, 0.09);

  /* Semânticas: só falam de resultado e estado (regra da cor com significado). */
  --green:#107A52; --green-fill:#17A36E; --green-ink:#0B5E3F; --green-bg:rgba(23,163,110,.12);
  --red:#C4362F;   --red-fill:#E04B42;   --red-ink:#A82B25;   --red-bg:rgba(224,75,66,.12);
  --orange:#9A5B00; --orange-fill:#E08A16; --orange-ink:#8A5100; --orange-bg:rgba(224,138,22,.14);
  --blue:#004C97;  --blue-ink:#00427F;  --blue-bg:rgba(0,76,151,.10); --blue-chip:rgba(0,76,151,.12);
  --teal:#0E7C8A;  --teal-ink:#0B6673;  --teal-bg:rgba(14,124,138,.12);
  --purple:#5B4BC4; --purple-ink:#4A3CA8; --purple-bg:rgba(91,75,196,.12);
  --indigo:#34479B; --indigo-ink:#2A3A80; --indigo-bg:rgba(52,71,155,.12);
  --pink:#B03A66;  --pink-ink:#933055;  --pink-bg:rgba(176,58,102,.12);
  --yellow:#A8820A;
  --red-chip:rgba(224,75,66,.14);

  /* Profundidade real em quatro níveis — sombra fria, nunca preta pura. */
  --shadow-s: 0 1px 2px rgba(16, 30, 54, .07);
  --shadow-m: 0 1px 2px rgba(16, 30, 54, .06), 0 4px 12px -4px rgba(16, 30, 54, .12);
  --shadow-r: 0 2px 4px rgba(16, 30, 54, .07), 0 12px 28px -10px rgba(16, 30, 54, .18);
  --shadow-l: 0 24px 56px -18px rgba(16, 30, 54, .28);
  --inner-shadow: rgba(16, 30, 54, .08);

  --glass:        rgba(255, 255, 255, 0.72);
  --glass-strong: rgba(255, 255, 255, 0.86);
  --glass-thin:   rgba(255, 255, 255, 0.55);
  --glass-chrome: rgba(255, 255, 255, 0.80);
  --glass-blur:        blur(18px) saturate(140%);
  --glass-blur-strong: blur(28px) saturate(150%);

  color-scheme: light;
}

/* ══ TEMA ESCURO — a mesma marca, para quem trabalha à noite ══════════════════
   Não é um segundo visual: é o navy do GPS assumindo o fundo. O azul de ação sobe
   para o azul claro de superfície escura, senão ele desaparece no marinho. */
:root[data-theme="dark"] {
  --canvas:  #0A1522;
  --mesh:    #0A1522;
  --surface: #0F2036;
  --surface-2: #0C1A2C;
  --surface-sunken: #081324;

  --label:  #E9EFF6;
  --label2: rgba(233, 239, 246, 0.76);
  --label3: rgba(233, 239, 246, 0.60);
  --heading: #F3F7FC;

  --navy: var(--gps-navy); --navy-deep: var(--gps-navy-deep); --navy-ink: var(--gps-navy-ink);
  --acento: var(--gps-blue-dark-surface); --acento-forte: #93C8F5; --acento-sobre: #04182B;
  --acento-suave: rgba(107, 176, 238, 0.14); --acento-linha: rgba(107, 176, 238, 0.32);
  --acento-brilho: rgba(107, 176, 238, 0.30);
  --brand: var(--gps-blue-dark-surface); --brand-bright: #93C8F5;
  --accent-solid: var(--gps-blue-dark-surface); --accent-solid-ink: #04182B;
  --neon: var(--gps-blue-dark-surface); --neon-forte: #93C8F5;
  --neon-fundo: rgba(107, 176, 238, 0.14); --neon-linha: rgba(107, 176, 238, 0.30);

  --hairline: rgba(150, 180, 214, 0.16); --hairline-firm: rgba(150, 180, 214, 0.30);
  --edge: rgba(150, 180, 214, 0.12); --spec-top: rgba(255, 255, 255, 0.06);
  --fill: rgba(255, 255, 255, 0.06); --fill2: rgba(255, 255, 255, 0.11);

  --green:#17A36E; --green-fill:#17A36E; --green-ink:#6FE0AE; --green-bg:rgba(23,163,110,.16);
  --red:#E04B42;   --red-fill:#E04B42;   --red-ink:#FF9C95;   --red-bg:rgba(224,75,66,.16);
  --orange:#E08A16; --orange-fill:#E08A16; --orange-ink:#F5BE6B; --orange-bg:rgba(224,138,22,.16);
  --blue:#0A6ED1;  --blue-ink:#8FC4F5;  --blue-bg:rgba(10,110,209,.18); --blue-chip:rgba(10,110,209,.20);
  --teal:#0E7C8A;  --teal-ink:#69D2DE;  --teal-bg:rgba(14,124,138,.18);
  --purple:#5B4BC4; --purple-ink:#B3A8F5; --purple-bg:rgba(91,75,196,.20);
  --indigo:#34479B; --indigo-ink:#A2B0F0; --indigo-bg:rgba(52,71,155,.22);
  --pink:#B03A66;  --pink-ink:#F09BBB;  --pink-bg:rgba(176,58,102,.20);
  --yellow:#D8AA1E;
  --red-chip:rgba(224,75,66,.20);

  --shadow-s: 0 1px 2px rgba(0,0,0,.34);
  --shadow-m: 0 2px 6px -2px rgba(0,0,0,.40), 0 10px 24px -12px rgba(0,0,0,.60);
  --shadow-r: 0 6px 16px -6px rgba(0,0,0,.45), 0 22px 46px -18px rgba(0,0,0,.70);
  --shadow-l: 0 24px 60px -18px rgba(0,0,0,.78);
  --inner-shadow: rgba(0, 0, 0, 0.40);

  --glass:        rgba(15, 32, 54, 0.62);
  --glass-strong: rgba(12, 26, 44, 0.84);
  --glass-thin:   rgba(15, 32, 54, 0.45);
  --glass-chrome: rgba(11, 24, 40, 0.72);
  --glass-blur:        blur(20px) saturate(140%);
  --glass-blur-strong: blur(30px) saturate(150%);

  color-scheme: dark;
}

/* ══ FUNDO — névoa, não grade ════════════════════════════════════════════════
   A camada `.mesh-bg` continua no HTML (é o fundo do app), mas deixa de ser o "fundo
   vivo" do HUD: sem grade em deriva, sem varredura, sem scanlines. Fundo de
   instrumento de trabalho não pode competir com a tabela que está em cima dele. */
.mesh-bg { background: var(--canvas) !important; }
:root[data-theme="light"] .mesh-bg {
  background: radial-gradient(1200px 700px at 15% -10%, rgba(0, 76, 151, 0.05), transparent 60%), #EEF1F6 !important;
}
:root[data-theme="dark"] .mesh-bg {
  background: radial-gradient(1200px 700px at 15% -10%, rgba(0, 76, 151, 0.22), transparent 60%), #0A1522 !important;
}
.mesh-bg__grade, .mesh-bg__varredura, .mesh-bg__linhas { display: none !important; }

/* ══ FORMA ═══════════════════════════════════════════════════════════════════
   Raio concêntrico: o interno é o externo MENOS o padding. Errar isso é o sinal
   mais visível de interface amadora — e o app tinha raios soltos. */
:root {
  --r-xs:7px; --r-s:10px; --r-m:15px; --r-l:18px; --r-xl:24px;
}

/* Profundidade real: sombra em camadas + fio de luz na aresta de cima. */
.card, .stat-card, .table-wrap, .modal, .tl-box, .aprov-card, .filter-bar {
  background: var(--surface);
  border: 1px solid var(--hairline);
  box-shadow: var(--shadow-m), inset 0 1px 0 var(--spec-top);
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
}
.card:hover, .stat-card:hover {
  box-shadow: var(--shadow-r), inset 0 1px 0 var(--spec-top);
}

/* A barra de filtros entrou na lista das superfícies acima, mas ela nasceu no
   styles.css sem padding e sem raio: virou uma faixa branca de canto vivo, 32px de
   altura para pílulas de 30px — as pílulas encostavam na borda de cima e na de baixo.
   Superfície pede respiro e raio; sem os dois ela lê como um erro de layout. */
.filter-bar {
  padding: 9px 11px;
  border-radius: var(--r-m);
  gap: 7px;
}
/* E a pílula usava --surface, exatamente a MESMA cor da barra que a contém: um
   controle branco sobre uma superfície branca, separado só por um fio. Dentro da
   barra ela passa a ser um degrau recuado — o contraste vem do preenchimento, não
   de mais uma linha. O contador, por sua vez, sobe para a cor da superfície. */
.filter-bar .fpill { background: var(--fill); border-color: transparent; box-shadow: none; }
.filter-bar .fpill:hover { background: var(--fill2); color: var(--label); }
.filter-bar .fpill-n { background: var(--surface); }
/* Fila de trabalho vazia não disputa atenção com fila que tem serviço. */
.fpill-n.zero, .stage-tab-n.zero { opacity: .5; font-weight: 700; }
.fpill.active .fpill-n.zero, .stage-tab.active .stage-tab-n.zero { opacity: .75; }

/* Contador de 10–11px sobre cor chapada é onde o contraste some sem ninguém notar —
   e o auditor só passou a enxergar isto quando deixou de ignorar texto de UM
   caractere. O selo do filtro ativo INVERTE (fundo na tinta do botão, texto na cor
   do botão) em vez de ser um véu branco sobre o acento, que media 3,24:1; a aba
   ativa usa a tinta do acento no lugar de um branco fixo, que no tema escuro dava
   2,02:1 (branco sobre ciano aceso); e o selo vermelho desce o tom o bastante para
   o branco passar dos 4,0:1 que media, sem deixar de ser alarme. */
.fpill.active .fpill-n { background: var(--acento-sobre); color: var(--acento); }
.stage-tab.active .stage-tab-n { background: var(--brand); color: var(--accent-solid-ink); }
/* Selo de alarme: fundo no NEGATIVO do GPS (#C4362F). O preenchimento mais claro
   (#E04B42) mede 4,0:1 com texto branco — some justamente no contador de 10px, que é
   onde ninguém repara na falta de contraste. Vale para o sino também. */
.nav-badge, .bn-badge, .notif-dot, .stage-tab.urgente .stage-tab-n { background: #C4362F; color: #fff; }

/* ══ Alerta de pendências ════════════════════════════════════════════════════
   Linha grande e clicável: quem abre o sistema às 7h precisa ver o que fazer sem ler. */
.pend-sub { font: 800 11px/1 var(--sans); letter-spacing: .09em; text-transform: uppercase; color: var(--label3); margin: -6px 0 14px; }
.pend-lista { display: flex; flex-direction: column; gap: 8px; }
.pend-item {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  padding: 12px 14px; border-radius: var(--r-m); cursor: pointer;
  border: 1px solid var(--hairline); background: var(--surface-2);
  transition: transform var(--duration-fast) var(--spring-subtle), border-color var(--duration-fast) linear;
}
.pend-item:hover { border-color: var(--acento); transform: translateX(2px); }
.pend-ic { flex: none; width: 36px; height: 36px; border-radius: var(--r-s); display: grid; place-items: center; }
.pend-ic svg { width: 19px; height: 19px; }
.pend-tx { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.pend-tt { font: 800 14px/1.25 var(--sans); color: var(--label); }
.pend-bd { font: 600 12.5px/1.35 var(--sans); color: var(--label2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pend-n {
  flex: none; min-width: 30px; height: 26px; padding: 0 9px; border-radius: var(--r-cap);
  display: grid; place-items: center; font: 800 13px/1 var(--sans); font-variant-numeric: tabular-nums;
  background: var(--acento); color: var(--acento-sobre);
}
.pend-nao { display: flex; align-items: center; gap: 7px; margin-right: auto; font: 700 12px/1 var(--sans); color: var(--label3); cursor: pointer; }
.pend-nao input { width: 15px; height: 15px; accent-color: var(--acento); }
@media (max-width: 560px) { .pend-bd { white-space: normal; } }

/* ══ Corretor: a sugestão precisa estar À VISTA ══════════════════════════════
   Sublinhar a palavra e contar os erros deixa o trabalho todo com quem escreve. O selo
   traz a palavra certa já escrita — clicar aplica. Herda a cor do tipo do achado, então
   o vermelho continua sendo "erro de acento" e o âmbar, "confira". */
.corretor__erro {
  border: 1px solid var(--hairline); cursor: pointer;
  padding: 3px 9px; border-radius: var(--r-cap);
  font: 800 11px/1.5 var(--sans); font-variant-numeric: tabular-nums;
  background: var(--fill); color: var(--label2);
  transition: background var(--duration-fast) var(--ease-out), color var(--duration-fast) linear;
}
.corretor__erro:hover { background: var(--acento); color: var(--acento-sobre); border-color: transparent; }
.corretor__erro.marca--corrigivel { color: var(--red-ink); }
.corretor__erro.marca--provavel   { color: var(--orange-ink); }
.corretor__erro:hover.marca--corrigivel, .corretor__erro:hover.marca--provavel { color: var(--acento-sobre); }
.corretor__mais { font: 800 11px/1.5 var(--sans); color: var(--label3); align-self: center; }
.cor-pop { min-width: 172px; }
.cor-pop__hd {
  display: flex; flex-direction: column; gap: 2px;
  padding: 6px 12px 8px; margin-bottom: 4px;
  border-bottom: 1px solid var(--hairline);
  font: 800 13px/1.3 var(--sans); color: var(--label);
}
.cor-pop__hd span { font: 700 10.5px/1.3 var(--sans); letter-spacing: .06em; text-transform: uppercase; color: var(--label3); }
.cor-pop__ig { color: var(--label3) !important; }

/* Nota do que os botões de exportação levam — o número deles é o das requisições a
   cotar, não o do filtro aberto, e lado a lado os dois números se contradiziam.
   O grupo quebra INTEIRO para a linha de baixo: solto, o rótulo ficava numa linha
   e os botões na outra. */
.fb-export { display: flex; align-items: center; gap: 7px; flex: none; }
.fb-nota {
  font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  color: var(--label3); white-space: nowrap;
}

/* ══ VIDRO — só na camada de navegação ═══════════════════════════════════════
   ⚠️ A barra lateral é ESCURA NOS DOIS TEMAS (texto branco por cima) — foi assim que
   o app nasceu. Trocar o fundo dela por `--glass-chrome`, que segue o tema, deixou-a
   branca no tema claro e o texto branco sumiu: 302 achados de contraste numa varredura.
   Ela mantém vidro, mas vidro ESCURO, sempre. */
.sidebar {
  background: linear-gradient(180deg, rgba(11,21,32,.86) 0%, rgba(5,11,18,.92) 100%);
  backdrop-filter: var(--glass-blur-strong);
  -webkit-backdrop-filter: var(--glass-blur-strong);
}
.topbar, .bottom-nav, .mobile-topbar, .mm-panel {
  background: var(--glass-chrome);
  backdrop-filter: var(--glass-blur-strong);
  -webkit-backdrop-filter: var(--glass-blur-strong);
  border-color: var(--hairline);
}
/* Rótulos da navegação: mediam 4,09:1 e 3,56:1 sobre o navy — abaixo do mínimo de texto. */
.nav-section-label { color: rgba(255,255,255,.72); }
.sidebar-foot-text { color: rgba(255,255,255,.62); }
.nav-item { color: rgba(255,255,255,.86); }
/* A linha do logo ficou de fora daquela varredura e media 4,4:1 — passa raspando
   por baixo dos 4,5. Achada agora que a auditoria enxerga fundo em gradiente. */
.brand-ver { color: rgba(255,255,255,.62); }

/* ══ AÇÃO — o azul institucional, em no máximo 10% da tela ═══════════════════
   Regra dos 10% do design system do GPS: se está no azul de ação, responde ao clique.
   Duas ações primárias na mesma tela significam que uma delas está errada. */

/* Item de navegação ativo: barra sólida na borda + fundo tingido. Sem halo. */
.nav-item.active, .bn-item.active {
  color: var(--acento-forte);
  background: var(--acento-suave);
  box-shadow: inset 2px 0 0 var(--acento);
}
.nav-item.active svg, .bn-item.active svg { color: var(--acento-forte); }

/* ⚠️ A barra lateral é uma superfície ESCURA nos dois temas (navy do GPS, texto branco).
   Então o acento dela também tem de ser o de superfície escura: o azul de ação #004C97
   sobre o navy mede 2,3:1 e some — no tema claro isso já tinha travado o item ATIVO em
   1,97:1, MENOS legível que os inativos a 9,66:1. Reescopar o token AQUI repinta a coluna
   inteira sem tocar em nenhum componente, porque as regras resolvem `var(--…)` no elemento.
   (Por que passou da primeira vez: `fundoReal()` do auditar.js devolvia null diante de
   gradiente — e a barra pinta com linear-gradient, então a coluna ficava fora da medição.) */
.sidebar {
  --acento:       var(--gps-blue-dark-surface);
  --acento-forte: #93C8F5;
  --acento-suave: rgba(107, 176, 238, 0.14);
  --acento-brilho: rgba(107, 176, 238, 0.26);
  --neon:         var(--gps-blue-dark-surface);
  --neon-forte:   #93C8F5;
  --neon-fundo:   rgba(107, 176, 238, 0.14);
  --neon-linha:   rgba(107, 176, 238, 0.30);
}
/* A barra de luz do styles.css usa --brand-bright, substituído lá no :root e por isso fora
   do escopo acima — no claro ela ficaria azul-escura sobre o navy, invisível. */
.sidebar .nav-item.active::before { background: var(--gps-blue-dark-surface); box-shadow: none; }

/* Botão primário: cor CHAPADA (degradê de três paradas lava a cor) + fio interno. */
.btn-primary {
  background: var(--acento);
  color: var(--acento-sobre);
  border-color: transparent;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.22), 0 2px 6px -2px var(--acento-brilho);
}
.btn-primary:hover { background: var(--acento-forte); box-shadow: inset 0 1px 0 rgba(255,255,255,.26), 0 6px 16px -6px var(--acento-brilho); }

/* Pílula de filtro ativa e KPI selecionado */
.fpill.active { background: var(--acento); color: var(--acento-sobre); border-color: transparent; box-shadow: var(--shadow-s); }
.kpi-click.kpi-on { border-color: var(--acento); box-shadow: 0 0 0 1px var(--acento) inset, var(--shadow-m); }
.tl-mes.on { background: var(--acento); box-shadow: var(--shadow-s); }

/* Números e rótulos de sistema em caixa alta, com o rastreio da skill */
.stat-label, .kpi-head, th, .tl-lbl, .card-sub {
  text-transform: uppercase; letter-spacing: .09em; font-weight: 800;
}
.stat-value, .num, .money, td.num, td.money { font-variant-numeric: tabular-nums; }

/* Foco: um anel só, na cor do acento, sempre visível */
.btn:focus-visible, .fpill:focus-visible, .nav-item:focus-visible, .kpi-click:focus-visible,
.modal-close:focus-visible, .tl-mes:focus-visible, .tl-nav:focus-visible, .req-item-rm:focus-visible {
  outline: 2px solid var(--acento); outline-offset: 2px;
}
input:focus-visible, textarea:focus-visible, select:focus-visible, .ap-field:focus-visible {
  /* Anel azul de 3px no foco — o campo diz que está ativo sem brilhar. */
  outline: none; border-color: var(--acento);
  box-shadow: 0 0 0 3px var(--acento-suave);
}

/* ══ MOVIMENTO — mola de verdade, e só transform/opacity ═════════════════════
   `linear()` passa de 1 e por isso dá o repique; `cubic-bezier` não passa e por
   isso nunca parece mola. */
:root { --ease-spring: var(--spring-fast); --ease-out: var(--ease-effects); }
.btn, .fpill, .nav-item, .stat-card, .card, .kpi-click {
  transition: transform var(--duration-fast) var(--spring-subtle),
              box-shadow var(--duration-normal) var(--ease-effects),
              background var(--duration-fast) linear,
              color var(--duration-fast) linear;
}
.btn:active, .fpill:active, .kpi-click:active { transform: scale(.97); }
.stat-card:hover, .card:hover { transform: translateY(-2px); }

/* Entrada da tela: sobe e revela, escalonado. Só transform/opacity. */
.page-anim > * { animation: hud-entra var(--duration-slow) var(--spring-subtle) both; }
.page-anim > *:nth-child(1){animation-delay:0ms}   .page-anim > *:nth-child(2){animation-delay:45ms}
.page-anim > *:nth-child(3){animation-delay:90ms}  .page-anim > *:nth-child(4){animation-delay:135ms}
.page-anim > *:nth-child(n+5){animation-delay:180ms}
@keyframes hud-entra { from { opacity:0; transform: translate3d(0,10px,0); } to { opacity:1; transform:none; } }

/* ⚠️ A varredura de luz no cartão de indicador e o PULSO do selo vencido saíram com a
   identidade cyber: "nada quica, nada estica, nada pisca". Num instrumento de trabalho, o
   que pisca não vira urgência — vira ruído que o operador aprende a ignorar. Vencido já se
   distingue pela COR semântica, que é informação e basta. A entrada da tela (`page-anim`)
   fica: ela orienta a leitura de cima para baixo e acontece uma vez só. */
.stat-card { position: relative; }

/* Menos movimento é uma chave do sistema, não um detalhe de acessibilidade. */
@media (prefers-reduced-motion: reduce) {
  .page-anim > * { animation: none !important; }
  .btn:active, .fpill:active, .stat-card:hover, .card:hover { transform: none; }
}

/* ══ Tabela: linha que acende ao passar ══════════════════════════════════════ */
tbody tr { transition: background var(--duration-fast) linear, box-shadow var(--duration-fast) linear; }
tbody tr:hover { background: var(--acento-suave); box-shadow: inset 2px 0 0 var(--acento-linha); }

/* ══ Modal: entra com mola, e o fundo escurece de verdade ════════════════════ */
.modal-overlay { background: rgba(4, 9, 15, .62); backdrop-filter: blur(3px); }
.modal { box-shadow: var(--shadow-l), inset 0 1px 0 var(--spec-top); }

/* ══════════════════════════════════════════════════════════════════════════════
   CAMADA FLUTUANTE — opaca, sempre

   ⚠️ Erro que eu cometi: deixei `--surface` translúcido para o cartão ganhar o
   fundo vivo por baixo. Só que popup, calendário, menu e modal FLUTUAM SOBRE
   CONTEÚDO — e translucidez ali deixa o formulário de trás aparecendo através da
   lista de opções. Vira ruído, não profundidade.

   A regra: translucidez é da NAVEGAÇÃO (barra lateral, topo) e do cartão, que
   flutuam sobre o FUNDO. Tudo que flutua sobre CONTEÚDO é opaco.

   O acabamento segue o `.cal` da skill: fundo sólido + fio de luz na aresta de
   cima + sombra profunda. Sem halo de neon: a profundidade vem da sombra em camadas,
   que é o que descola o painel do conteúdo num tema institucional.
   ══════════════════════════════════════════════════════════════════════════════ */
:root[data-theme="dark"]  { --flutuante: #10233A; --flutuante-linha: rgba(150,190,230,.20); }
:root[data-theme="light"] { --flutuante: #FFFFFF; --flutuante-linha: rgba(20,34,48,.16); }

.ap-pop, .row-menu, .notif-pop, .combo-results, .modal, .mm-panel, .price-pop, .ax-box {
  background: var(--flutuante) !important;
  /* Sem fio: fio de 1px sob sombra grande é o "cartão fantasma". Quem descola
     esta superfície é a sombra, e elevação se declara uma vez só. */
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow:
    inset 0 1px 0 var(--spec-top),
    var(--shadow-l);
}

/* O menu abre com a mesma mola do resto — some o "aparecer seco". */
.ap-pop, .row-menu, .notif-pop {
  transition: opacity var(--duration-fast) var(--ease-effects),
              transform var(--spring-fast-duration) var(--spring-fast);
}

/* Opção do menu: alvo confortável, acento no que está escolhido. */
.ap-opt, .combo-opt, .price-opt, .rm-item {
  border-radius: var(--r-xs);
  transition: background var(--duration-fast) linear, color var(--duration-fast) linear;
}
.ap-opt:hover, .combo-opt:hover, .price-opt:hover, .rm-item:hover { background: var(--acento-suave); }
.ap-opt.sel { color: var(--acento); background: var(--acento-suave); }

/* Calendário: o dia de hoje ganha anel, o escolhido ganha o acento cheio. */
.ap-cal-day.sel { background: var(--acento); color: var(--acento-sobre); box-shadow: var(--shadow-s); }
.ap-cal-day.today:not(.sel) { box-shadow: inset 0 0 0 1.5px var(--acento-linha); color: var(--acento); }
.ap-cal-day:hover:not(.sel) { background: var(--acento-suave); }
.ap-cal-act { color: var(--acento); }
.ap-cal-act:hover { background: var(--acento-suave); }

/* O véu do modal escurece de verdade: o conteúdo de trás não pode competir. */
.modal-overlay { background: rgba(3, 7, 12, .68); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
/* O véu do seletor é invisível, mas precisa existir para capturar o clique fora. */
.ap-pop-scrim { background: transparent; }

/* ══ Prazo da OM ═════════════════════════════════════════════════════════════
   A segunda barra de filtro é a do RELÓGIO da obra, não a do status. Ela precisa ler
   como um bloco à parte da primeira, senão viram duas fileiras de pílulas iguais. */
.prazo-bar { margin-top: -6px; }
.prazo-resumo {
  display: block; margin: -8px 0 14px;
  padding: 9px 13px; border-radius: var(--r-m);
  font: 700 12.5px/1.4 var(--sans);
  border: 1px solid var(--hairline); background: var(--surface-2); color: var(--label2);
}
.prazo-resumo.grave   { border-color: var(--red);    background: var(--red-bg);    color: var(--red-ink); }
.prazo-resumo.atencao { border-color: var(--orange); background: var(--orange-bg); color: var(--orange-ink); }

/* ══ Painel por setor ════════════════════════════════════════════════════════
   Responde "onde a obra está parada" antes de qualquer tabela. Cada selo é filtro. */
.setor-bar { margin-bottom: 14px; }
.setor-tt { font: 800 10.5px/1 var(--sans); letter-spacing: .1em; text-transform: uppercase; color: var(--label3); margin-bottom: 8px; }
.setor-chips { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.setor-chip {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
  padding: 5px 6px 5px 12px; border-radius: var(--r-cap);
  border: 1px solid var(--hairline); background: var(--surface-2);
  font: 800 12px/1 var(--sans); color: var(--label2);
  transition: border-color var(--duration-fast) linear, color var(--duration-fast) linear;
}
.setor-chip:hover { border-color: var(--acento); color: var(--label); }
.setor-chip.on { background: var(--acento); border-color: transparent; color: var(--acento-sobre); }
.setor-nome { max-width: 190px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.setor-n {
  min-width: 22px; height: 20px; padding: 0 6px; border-radius: var(--r-cap);
  display: grid; place-items: center; font-variant-numeric: tabular-nums;
  background: var(--fill2); color: inherit;
}
.setor-chip.on .setor-n { background: rgba(255,255,255,.26); }
.setor-mais { font: 700 11.5px/1 var(--sans); color: var(--label3); }
/* Price list opcional: o campo continua ali, mas recuado — consumo não precisa dele. */
.price-opcional { opacity: .72; }

/* ══ Análise de compras ══════════════════════════════════════════════════════
   O veredito vem antes do gráfico: quem abre a tela precisa saber o diagnóstico numa
   frase, e só depois olhar de onde ele veio. */
.ver-box { padding: 14px 16px; border-radius: var(--r-m); border: 1px solid var(--hairline); background: var(--surface-2); margin-bottom: 16px; }
.ver-box.grave { border-color: var(--red); background: var(--red-bg); }
.ver-box.atencao { border-color: var(--orange); background: var(--orange-bg); }
.ver-tt { font: 800 15px/1.35 var(--sans); color: var(--label); }
.ver-box.grave .ver-tt { color: var(--red-ink); }
.ver-box.atencao .ver-tt { color: var(--orange-ink); }
.ver-sub { font: 700 12.5px/1.5 var(--sans); color: var(--label2); margin-top: 5px; }

.fase-linha { padding: 9px 12px; border-radius: var(--r-s); }
.fase-linha.gargalo { background: var(--red-bg); }
.fase-cab { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.fase-nome { font: 800 13px/1.2 var(--sans); color: var(--label); }
.fase-dono { font-size: 10px !important; }
.fase-num { margin-left: auto; font: 800 15px/1 var(--sans); font-variant-numeric: tabular-nums; color: var(--label); }
.fase-linha.gargalo .fase-num, .fase-linha.gargalo .fase-nome { color: var(--red-ink); }
.fase-tri { height: 7px; border-radius: 4px; background: var(--fill2); margin: 7px 0 5px; overflow: hidden; }
.fase-tri > i { display: block; height: 100%; border-radius: 4px; background: var(--acento); }
.fase-linha.gargalo .fase-tri > i { background: var(--red-fill); }
.fase-pe { font: 600 11.5px/1.4 var(--sans); color: var(--label3); }

.espera-linha { display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-bottom: 1px solid var(--hairline); font: 700 12.5px/1 var(--sans); }
.espera-linha:last-child { border-bottom: none; }
.espera-pt { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.espera-nome { color: var(--label); min-width: 88px; }
.espera-n { min-width: 30px; padding: 3px 8px; border-radius: var(--r-cap); background: var(--fill2); color: var(--label); text-align: center; font-variant-numeric: tabular-nums; }
.espera-d { color: var(--label3); }
.espera-v { margin-left: auto; font-variant-numeric: tabular-nums; color: var(--label2); }

/* ══ COR DE GRÁFICO — a paleta de data-viz do GPS ════════════════════════════
   O motor de gráficos pinta por `--viz-N`/`--grad-N`, que vinham genéricos da skill
   (ciano, roxo, rosa). O design system do GPS tem o próprio conjunto e ele é fixo:
   a mesma série é sempre a mesma cor, em todo lugar — cor é identidade, não rodízio.

   Duas posições são reservadas por SEMÂNTICA e não pela ordem da paleta: a 3 é o verde
   positivo e a 8 é o vermelho negativo, porque são as que o app usa em Entradas × Saídas
   (`VIZ` no app.js). Trocar isso por cor de rodízio faria "saída" aparecer em laranja num
   gráfico e em roxo no outro.

   ⚠️ O seletor abaixo lista os três de propósito: `hud-tokens.css` declara as séries em
   `:root, :root[data-theme="light"]`, que tem DOIS pontos de especificidade — um `:root`
   sozinho carregado depois NÃO vence. É a mesma armadilha que já custou meia paleta na
   adoção anterior e está registrada no CLAUDE.md. */
:root, :root[data-theme="light"], :root[data-theme="dark"] {
  --viz-1: #004C97; --viz-2: #0E7C8A; --viz-3: #17A36E; --viz-4: #5B4BC4;
  --viz-5: #34479B; --viz-6: #E08A16; --viz-7: #0A6ED1; --viz-8: #C4362F;
  --viz-1-soft: rgba(0,76,151,.10);  --viz-2-soft: rgba(14,124,138,.10);
  --viz-3-soft: rgba(23,163,110,.10); --viz-4-soft: rgba(91,75,196,.10);
  --viz-5-soft: rgba(52,71,155,.10); --viz-6-soft: rgba(224,138,22,.10);
  --viz-7-soft: rgba(10,110,209,.10); --viz-8-soft: rgba(196,54,47,.10);
  --viz-neutro: #8A8E90;
  --grad-1: linear-gradient(180deg,#2f78bd 0%,#004C97 100%);
  --grad-2: linear-gradient(180deg,#3aa3b0 0%,#0E7C8A 100%);
  --grad-3: linear-gradient(180deg,#4cc492 0%,#17A36E 100%);
  --grad-4: linear-gradient(180deg,#8477dc 0%,#5B4BC4 100%);
  --grad-5: linear-gradient(180deg,#5f70bd 0%,#34479B 100%);
  --grad-6: linear-gradient(180deg,#eeab52 0%,#E08A16 100%);
  --grad-7: linear-gradient(180deg,#4c95e0 0%,#0A6ED1 100%);
  --grad-8: linear-gradient(180deg,#d9695f 0%,#C4362F 100%);
  --grad-pos:    linear-gradient(180deg,#4cc492 0%,#107A52 100%);
  --grad-neg:    linear-gradient(180deg,#e0736a 0%,#C4362F 100%);
  --grad-neutro: linear-gradient(180deg,#a9adaf 0%,#5F6263 100%);
  --ord-1:#004C97; --ord-2:#0A6ED1; --ord-3:#34479B;
}

/* ═══ Orçamento da OM ═══════════════════════════════════════════════════════
   O editor é largo de propósito: um orçamento tem dezenas de linhas de price
   list com quantidade editável, e a coluna de resumo precisa ficar visível
   enquanto se digita. Tudo em cima dos tokens que já existem — nenhuma cor
   nova. */

.orc-bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 14px; margin-bottom: 14px;
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius-md); position: sticky; top: 0; z-index: 20;
}

.orc-grid { display: grid; gap: 14px; align-items: start; }
@media (min-width: 1100px) { .orc-grid { grid-template-columns: minmax(0, 1fr) 300px; } }
.orc-col { display: grid; gap: 14px; min-width: 0; }

.orc-resumo { position: sticky; top: 74px; }
.orc-resumo-l {
  display: flex; justify-content: space-between; gap: 12px; padding: 7px 0;
  font-size: 13px; color: var(--label2);
}
.orc-resumo-l b { color: var(--label1); font-variant-numeric: tabular-nums; }
.orc-resumo-l.total {
  margin-top: 6px; padding-top: 10px; border-top: 1px solid var(--line);
  font-weight: 700; color: var(--label1);
}
.orc-resumo-l.total b { font-size: 19px; color: var(--blue-ink); }

/* Campo numérico da linha: estreito e alinhado à direita, para a coluna de
   valores ler como coluna e não como texto solto. */
.orc-n {
  width: 84px; text-align: right; font-variant-numeric: tabular-nums;
}
.orc-busca { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 10px; }
.orc-busca input, .orc-busca select { flex: 1; min-width: 220px; }

/* Memória de cálculo: os operadores ficam ENTRE os campos, na ordem da fórmula,
   para a conta impressa poder ser lida como conta. */
.orc-mem { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 10px; margin-bottom: 10px; }
.orc-mem-top { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 8px; }
.orc-mem-th { text-align: center; font-size: 11px; }
.orc-mem-td { white-space: nowrap; }
.orc-mem-td .orc-n { width: 68px; }
.orc-op { color: var(--label3); margin-right: 2px; font-size: 12px; }
.orc-mem-foot { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
.orc-mem-foot b { font-variant-numeric: tabular-nums; }

/* Linha clicável da lista — mesma affordance das outras tabelas do sistema. */
tr.row-click { cursor: pointer; }
tr.row-click:hover { background: var(--fill); }

/* Documento do orçamento dentro do modal. A folha traz o próprio CSS (prefixado
   com #doc-sheet) e a própria paleta — ela NÃO recebe o tema do app, porque é o
   arquivo que sai para o cliente e precisa sair sempre igual. */
.orc-doc-acoes { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
.orc-doc-host {
  background: #fff; color: #1f2328; border-radius: var(--radius-sm);
  padding: 14px; overflow-x: auto; max-height: 68vh; overflow-y: auto;
}

/* Impressão: só a folha vai para o papel. As margens são as MESMAS que o
   gerador de PDF usa (12mm/11mm/10mm) — é o que faz impresso e PDF baterem
   folha a folha. Mexer numa sem mexer na outra separa os dois documentos. */
@media print {
  body > *:not(.modal-overlay), .orc-doc-acoes, .modal-header, .modal-footer,
  .sidebar, .topbar, .bottom-nav, .toast-box { display: none !important; }
  .modal-overlay, .modal { position: static !important; inset: auto !important;
    background: #fff !important; box-shadow: none !important; max-height: none !important;
    width: auto !important; max-width: none !important; padding: 0 !important; overflow: visible !important; }
  .orc-doc-host { max-height: none !important; overflow: visible !important; padding: 0 !important; border-radius: 0 !important; }
  @page { size: A4 portrait; margin: 12mm 11mm 10mm; }
  html, body { background: #fff !important; height: auto !important; overflow: visible !important; }
  * { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; }
}

/* ═══ Piso de legibilidade e acabamento (04/09/2026) ══════════════════════════
   Achados medidos no navegador, não suposição. O contraste do sistema passou
   limpo (nenhum texto abaixo de 4,5:1 com as camadas de gradiente compostas);
   o que estava fora do piso era TAMANHO de texto funcional.

   Os micro-rótulos em caixa alta com rastreio de .09em são um recurso da
   identidade e ficam — o que muda é só o corpo, de 10px para 11px. A 10px, com
   caixa alta e rastreio, o rótulo de coluna some no balcão e no celular, e o
   sistema é usado nos dois. */

/* Cabeçalho de tabela: `thead th` (0,0,2) precisa de especificidade igual para
   vencer a regra base do styles.css. */
thead th { font-size: 11px; }
.stat-label, .kpi-head, .tl-lbl { font-size: 11px; }
.nav-section-label { font-size: 11px; }
.sidebar-foot-text { font-size: 11px; }
.nav-badge, .notif-dot, .bn-badge { font-size: 11px; }

/* Rótulo da barra inferior. Medido a 375px — a largura da maioria dos celulares:
   os cinco rótulos cabem em 11px sem cortar, então o piso vale ali também. A
   exceção fica só para os aparelhos realmente estreitos, onde "Relatórios" não
   passa. Antes eram 9px abaixo de 420px, o que pegava quase todo telefone. */
.bn-item { font-size: 11px; }
@media (max-width: 360px) { .bn-item { font-size: 10px; } }

/* ── Superfícies que o navegador desenha ─────────────────────────────────────
   Seleção, foco, scrollbar e numerais já eram tematizados aqui. Faltavam duas:
   o cursor de texto, que vinha preto do navegador dentro de campo escuro, e a
   scrollbar do Firefox, que ignora o seletor -webkit. */
:root { scrollbar-color: var(--label3) transparent; }
input, textarea, select, [contenteditable] { caret-color: var(--acento); }

/* ── Dúvidas do comprador ────────────────────────────────────────────────────
   A faixa colorida de 3px à esquerda era decoração carregando informação que o
   componente já dá melhor: uma dúvida respondida mostra o bloco de resposta
   inteiro, com ícone de check. A faixa some, o estado passa para o ícone do
   cabeçalho — que é onde o olho já está. */
.duv.aberta, .duv.ok { border-left-width: 1px; border-left-color: var(--hairline); }
.duv.aberta > .duv-q > .duv-cab > svg { color: var(--orange-ink); }
.duv.ok > .duv-q > .duv-cab > svg { color: var(--green-ink); }

/* ── Valor de indicador não quebra ───────────────────────────────────────────
   No celular, "R$ 392.609,26" quebrava entre o "R$" e o número: duas linhas
   para um valor só, e o cartão do Dashboard crescia junto. Um valor monetário
   é uma unidade — ou cabe inteiro, ou encolhe. Medido a 375px: cabe em uma
   linha com folga; abaixo de 360px o corpo cede antes de transbordar. */
.stat-value { white-space: nowrap; }
@media (max-width: 360px) { .stat-value { font-size: 19px; letter-spacing: -.6px; } }

/* Colunas iguais de verdade. `1fr` é `minmax(auto, 1fr)`: a largura mínima do
   conteúdo manda, e o cartão do valor monetário — que agora não quebra — passou
   a roubar espaço do vizinho, deixando a fileira torta no celular. `minmax(0,1fr)`
   devolve a simetria e faz o valor caber dentro da coluna, não o contrário. */
@media (max-width: 420px) {
  .stat-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}

/* Valor monetário do Dashboard. Antes carregava `font-size:23px` inline no
   app.js — um encolhimento manual porque "R$ 392.609,26" é bem mais longo que
   "19.305". Estilo inline vence qualquer media query, então no celular o valor
   ficava grande demais e era CORTADO pela borda do cartão: perder dígito de
   dinheiro é pior que qualquer defeito visual.

   Aqui ele acompanha a largura em vez de saltar entre pontos fixos, com teto no
   tamanho que a tela larga já usava e piso onde ainda sobra folga na coluna. */
.stat-money { font-size: clamp(15px, 4.6vw, 23px); }

/* ── Editor de orçamento: coluna que não estica ──────────────────────────────
   `.orc-col` é uma grade de uma coluna só. Sem `grid-template-columns`, a
   trilha é `auto` — dimensionada pelo CONTEÚDO, não pelo container. O campo de
   texto tem largura intrínseca (o `size` padrão do input), então o cartão
   inteiro esticava 127px além da coluna e passava POR BAIXO do painel de
   resumo, escondendo o campo "Local". `minmax(0,1fr)` faz o conteúdo caber na
   coluna, que é a ordem certa.

   `.form-row` tinha o mesmo `1fr 1fr` do resto do app: nunca apareceu porque
   ele só era usado em modal largo. Aqui ele mora numa coluna estreita. */
.orc-col { grid-template-columns: minmax(0, 1fr); }
.form-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.form-field input, .form-field select, .form-field textarea { min-width: 0; }
