/* ==========================================================================
   DESIGN SYSTEM "ALCANCE SOLAR" NO PORTAL (instrução `docs/revisao/017`,
   decisão do PO de 09/10/2026: o portal inteiro, RFP e BM, no tema CLARO FIXO,
   como o Portal de Propostas).

   Fonte: `docs/design-system/` (README da marca e `tokens.json`, cópia de
   leitura). Os valores abaixo são os do `tokens.json`; o que o sistema não
   dizia está marcado "ESCOLHA" ao lado, com o motivo, e listado em
   `docs/relatorios/design-system-desenho.md`.

   Precedência (a mesma do Propostas): a palavra do PO → o Design System → as
   decisões do Portal de Propostas (D-VIS-02 e adendos) → os elementos do CRM
   ASEC listados na instrução → o que o portal tinha, só no que nenhum dos
   anteriores disser.

   AS DUAS CAMADAS DE NOMES:
   1. os nomes do SISTEMA (`--navy`, `--blu`, `--org`, `--ink`, `--linha`…, e os
      por tema `--fundo`, `--fundo-suave`, `--texto`, `--texto-apoio`,
      `--titulo`, `--subtitulo`, `--fio`, `--acento`, `--foco`), no tema Claro;
   2. A PONTE: os nomes que o portal já usava (`--azul`, `--superficie`,
      `--texto-2`, `--line`, `--r-card`, `--sh`…) passam a VALER os do sistema,
      como o Propostas fez. Nenhum componente precisou mudar de token para mudar
      de cor; o que mudou de FORMA (raio, sombra, degradê, botão, tabela, selo,
      aviso, menu) foi reescrito na regra dele, mais abaixo.

   O tema ESCURO saiu (o bloco `html[data-tema="escuro"]`, o
   `@media (prefers-color-scheme: dark)` e o alternador): o tema é claro fixo, e
   a impressão sai com os mesmos tokens. Os únicos escopos que redefinem tokens
   são ESTRUTURA em navy, como no Propostas: o menu lateral (`.side`) e a capa
   das telas de entrada (`body.auth-dark`).
   ========================================================================== */

/* AS FONTES, servidas pelo próprio portal (`rfp/static/fonts/`, os mesmos
   arquivos do Design System e do Propostas, sha256 idênticos): a CSP só aceita
   `font-src 'self'`. `swap`: o texto aparece na reserva (Liberation Sans,
   Arial) e troca quando a Barlow chega. */
@font-face { font-family: "Barlow"; font-weight: 400; font-style: normal; font-display: swap;
  src: url("../fonts/barlow-400.81419bf5abb5.woff2") format("woff2"); }
@font-face { font-family: "Barlow"; font-weight: 500; font-style: normal; font-display: swap;
  src: url("../fonts/barlow-500.8e986e86d57e.woff2") format("woff2"); }
@font-face { font-family: "Barlow"; font-weight: 600; font-style: normal; font-display: swap;
  src: url("../fonts/barlow-600.a1e2a2d7d4c0.woff2") format("woff2"); }
@font-face { font-family: "Barlow"; font-weight: 700; font-style: normal; font-display: swap;
  src: url("../fonts/barlow-700.15481e4eab6d.woff2") format("woff2"); }
@font-face { font-family: "Barlow Condensed"; font-weight: 600; font-style: normal; font-display: swap;
  src: url("../fonts/barlow-condensed-600.ba4513495282.woff2") format("woff2"); }
@font-face { font-family: "Barlow Condensed"; font-weight: 700; font-style: normal; font-display: swap;
  src: url("../fonts/barlow-condensed-700.e1180918b873.woff2") format("woff2"); }
@font-face { font-family: "JetBrains Mono"; font-weight: 400; font-style: normal; font-display: swap;
  src: url("../fonts/jetbrains-mono-400.caf0dfde4e44.woff2") format("woff2"); }
@font-face { font-family: "JetBrains Mono"; font-weight: 600; font-style: normal; font-display: swap;
  src: url("../fonts/jetbrains-mono-600.075ec35bc15b.woff2") format("woff2"); }

:root {
  /* ===================================== 1 · O SISTEMA: as cores FIXAS
     (`tokens.json`, `color.tokens`). Contraste medido sobre branco. */
  --navy: #062033;          /* estrutura: menu, cabeçalho de tabela, títulos (16,6:1) */
  --deep: #04141f;          /* fim do degradê da capa: só fundo */
  --capa-topo: #0a3252;     /* início do degradê da capa; `fundo-suave` do escuro */
  --contraluz: #2b5f86;     /* radial da capa, até `--contraluz-max` */
  --blu: #00528b;           /* azul Alcance (logotipo): botão, link, subtítulo (8,1:1) */
  --blu2: #1c6ea3;          /* traços técnicos; hover do botão (branco: 5,5:1) */
  --laranja-marca: #E88025; /* o laranja do LOGOTIPO: brilho da capa e o logotipo */
  --org: #f26b21;           /* laranja de ACENTO do DT-01: filete, marcador, barra.
                               3,0:1 sobre branco: NUNCA texto abaixo de 24 px */
  --ink: #1a2530;           /* texto corrido (15,5:1) */
  --linha: #dfe7ee;         /* fios de tabela e divisórias (decoração, 1,25:1) */
  --lgt: #eaf3f9;           /* fundo suave azulado: Nota, linha de total */
  --zebra: #f7fafc;         /* linhas pares das tabelas */
  --pessego: #fdeee3;       /* fundo do destaque Atenção */
  --nevoa: #9db8cb;         /* apoio sobre navy (8,0:1) */
  --capa-texto: #c6d6e2;    /* subtítulo e link sobre navy (11,2:1) */
  --capa-fio: #1c4058;      /* fio sobre navy (decoração) */
  --branco: #ffffff;
  --brilho-sol-max: 0.16;   /* teto do brilho laranja da capa */
  --contraluz-max: 0.22;    /* teto da contraluz azulada da capa */

  /* ESCOLHAS DO PROPOSTAS (DS1b), o sistema não as traz; contraste medido de
     novo aqui (`docs/relatorios/design-system-desenho.md` §3):
     apoio-claro    = o `cinza` da marca (#8e9093, 3,2:1) ESCURECIDO: 6,15:1
                      sobre branco, 5,47 sobre `lgt`, 5,42 sobre `pessego`
     controle-claro = borda de controle: 4,27:1 sobre branco (mínimo 3:1)
     ok-claro / erro-claro = verde e vermelho escuros de estado: 6,50 e 6,54
                      sobre branco, 5,60 e 5,53 sobre o fundo de cada um
     org-texto      = o `org` escurecido para o texto pequeno de atenção:
                      6,33 sobre branco, 5,58 sobre `pessego` */
  --apoio-claro: #566370;
  --controle-claro: #6f7c88;
  --ok-claro: #1b6b43;
  --erro-claro: var(--estado-erro);
  --org-texto: #a3410a;
  /* AS CORES DE INTERFACE da D-VIS-03 (`tokens.json` v14): `estado-erro` é o
     valor que o portal já usava como `erro-claro` (DS1b), agora com o nome do
     sistema, e o `erro-claro` passa a ponte para ele; `erro-forte` é o hover
     do perigo na confirmação (branco: 8,49:1). */
  --estado-erro: #b3261e;
  --erro-forte: #902522;
  /* estado sobre o NAVY (só a capa): os do tema Escuro do Propostas, 9,1:1 e
     8,0:1 sobre `navy` */
  --ok-escuro: #6fd3a3;
  --erro-escuro: #f79c8b;

  /* Os tokens POR TEMA, no tema Claro (papel). */
  --fundo: var(--branco);
  --fundo-suave: var(--lgt);
  --texto: var(--ink);
  --texto-apoio: var(--apoio-claro);  /* o do sistema desde a v14 (D-VIS-03): #566370, 6,15:1;
                                         era ESCOLHA DS1b, quando o JSON dizia `cinza` (3,2:1) */
  --titulo: var(--navy);
  --subtitulo: var(--blu);
  --fio: var(--linha);
  --acento: var(--org);
  --foco: var(--blu);                 /* anel sólido de 2 px (8,1:1) */
  --controle-borda: var(--controle-claro);

  /* Fundos de ESTADO, derivados da cor do estado sobre o branco (10 %), nunca
     um terceiro tom solto — a mesma regra do Propostas; a borda suave, 45 %.
     O `erro-bg` é o do sistema (v14, o hover do perigo na tela): #f7e9e9, a
     mesma derivação com o meio ponto do azul arredondado para cima (era e8). */
  --ok-bg: #e8f0ec;   --ok-fg: var(--ok-claro);     --ok-borda: #98bcaa;
  --erro-bg: #f7e9e9; --erro-fg: var(--erro-claro); --erro-borda: #dd9d9a;
  /* Atenção é o par do sistema: `org` sobre `pessego`, com o texto em
     `org-texto` (o `org` puro reprova como texto). */
  --alerta-bg: var(--pessego); --alerta-fg: var(--org-texto); --alerta-borda: #f8ae85;
  --info-bg: var(--lgt);  --info-fg: var(--blu);    --info-borda: #a6c2d6;

  /* Espessuras (`tokens.json`, `espessura`). */
  --traco-cabelo: 0.67px;
  --traco-fio: 0.8px;
  --traco-moldura: 1.07px;
  --traco-acento: 2.13px;
  --traco-barra: 2.93px;
  --traco-destaque: 3.2px;
  /* A FORMA (`tokens.json` v14, `radius`, `shadow` e `interface`): a D-VIS-03
     (13/10/2026) e a emenda do PO de 26/10/2026 — "o layout tem ficado
     excessivamente com tantos de quina viva". Canto SÓ por token, nunca
     literal; cada elemento usa o token do seu papel:
       botão                                  `raio-botao`     6 px
       campo, lista de escolha, busca,
         controle segmentado                  `raio-controle`  6 px
       cartão, painel, filtro, aviso
         (Destaque), painel da conversa       `raio-cartao`   10 px
       retângulo da barra de blocos           `raio-bloco`     8 px
       selo, etiqueta, pílula de nome         `raio-pilula`  999 px
       tabela, menu lateral, indicador,
         marcador, barra de progresso         `raio-reto`      0
     SOMBRA SÓ EM BOTÃO, em navy a 10–14 %: cartões, painéis, campos e avisos
     continuam sem sombra, separados por fio. (O `inset` das barras de acento
     da linha e do cabeçalho da tabela não é sombra: é a barra de 6 px.) */
  --raio-reto: 0;
  --raio-botao: 6px;
  --raio-controle: 6px;
  --raio-cartao: 10px;
  --raio-bloco: 8px;
  --raio-pilula: 999px;
  --sombra-botao-leve: 0 1px 2px rgba(6, 32, 51, 0.10);
  --sombra-botao: 0 1px 2px rgba(6, 32, 51, 0.12), 0 2px 4px rgba(6, 32, 51, 0.10);
  --sombra-botao-alta: 0 2px 4px rgba(6, 32, 51, 0.14), 0 4px 10px rgba(6, 32, 51, 0.12);
  --alvo-de-toque: 44px;      /* altura mínima de botão no celular (até 640 px) */

  /* Famílias (`tokens.json`, `type.families`). */
  --font-sans: "Barlow", "Liberation Sans", Arial, sans-serif;
  --font-cond: "Barlow Condensed", "Liberation Sans Narrow", "Arial Narrow", sans-serif;
  --font-mono: "JetBrains Mono", "Liberation Mono", Consolas, monospace;
  /* ESCOLHA DO PROPOSTAS (DS1): a escala é de papel (pontos); na tela o corpo
     vai a 16 px e os títulos ficam nos valores do sistema (`secao` 22,67 px;
     o h1 da tela 34 px, 3/4 do `capa-titulo`). */
  --t-h1: 34px;
  --t-h2: 22.67px;
  --t-rotulo: 10.67px;     /* `rotulo`: caixa alta, peso 600 */
  --t-selo: 10.67px;

  /* ===================================== 2 · A PONTE: o nome do portal, o
     valor do sistema. Componente novo usa o nome do sistema. */
  --azul: var(--blu);               /* primeiro plano: link, código, marca */
  --azul-escuro: var(--navy);       /* era #123A5E: texto forte de rótulo */
  --azul-sup: var(--blu);           /* FUNDO de botão/selecionado, com branco por cima */
  --laranja: var(--org);            /* SINAL (ponto, barra, borda), nunca texto */
  --accent: var(--org);
  /* `--cinza`, `--faint` e `--texto-3` eram três cinzas de texto que a Fase
     11.9 já tinha deixado quase iguais (5,49 / 4,75); viram um só, o apoio do
     sistema. O cinza da MARCA (#8e9093) continua só no logotipo. */
  --cinza: var(--texto-apoio);
  --faint: var(--texto-apoio);
  --texto-2: var(--texto-apoio);
  --texto-3: var(--texto-apoio);
  --texto-inv: var(--branco);       /* sobre navy e sobre `blu` */
  --texto-sobre-moldura: var(--nevoa);
  --superficie: var(--fundo);       /* cartão: papel, separado por FIO, sem sombra */
  --superficie-2: var(--zebra);     /* recuo: filtros, chips, zebra */
  --superficie-3: var(--linha);     /* trilho de barra de progresso */
  --line: var(--fio);
  --borda: var(--fio);
  --line2: var(--fio);
  --line-in: var(--controle-borda); /* borda de campo: o `fio` reprova como contorno */
  --hover-suave: var(--lgt);
  /* A MOLDURA (decisão do PO, regra universal): o que sobra dos lados do
     conteúdo em tela larga é navy, como a barra. Agora o navy do sistema. */
  --moldura: var(--navy);
  --ok: var(--ok-claro);
  --erro: var(--erro-claro);
  --alerta: var(--org);
  --verde: var(--ok);
  --muted: var(--texto);
  /* Red flags: o par de estado, com a barra do Destaque (`traco-destaque`). */
  --flag-r-bg: var(--erro-bg);      --flag-r-borda: var(--erro-borda);
  --flag-r-ac: var(--erro-fg);      --flag-r-chip: var(--erro-bg);
  --flag-r-ic: var(--erro-fg);
  --flag-o-bg: var(--alerta-bg);    --flag-o-borda: var(--alerta-borda);
  --flag-o-ac: var(--org);          --flag-o-chip: var(--alerta-bg);
  --flag-o-ic: var(--alerta-fg);
  --flag-ac-w: var(--traco-destaque);
  /* Quadro Kanban: três camadas chapadas (o sistema não tem quadro; ESCOLHA):
     fundo `lgt`, coluna `zebra`, cartão branco, todos com fio. */
  --board-bg: var(--lgt);
  --board-col: var(--zebra);
  --board-borda: var(--fio);
  /* Véus: o navy do sistema (ESCOLHA do CRM, o `::backdrop` dos diálogos). */
  --veu: rgba(6, 32, 51, .82);
  --veu-modal: rgba(6, 32, 51, .55);
  /* Raio e sombra: os tokens `--r-card`, `--r-ctl`, `--r-lg` (10 a 16 px),
     `--sh` e `--sh-forte` SAÍRAM na `017` (cantos retos em tudo); desde a
     emenda de 26/10 o canto é pelos `--raio-*` e a sombra só de botão, no
     bloco da FORMA, acima. */
  /* Séries dos gráficos (Chart.js lê via getComputedStyle): o sistema não tem
     paleta categórica (ESCOLHA): a primeira é o `blu`; as outras, as que o
     portal já tinha medido contra superfície clara. */
  --serie-1: var(--blu);  --serie-2: #C96A08;  --serie-3: #2E8B6A;
  --serie-4: #8E44AD;     --serie-5: #B4700A;
  --grafico-grade: var(--linha);
  --marca-dagua: #14476F;   /* §12 forense: legível-mas-discreta (inalterada) */
  --realce: #FFE2B8;        /* `<mark>` da busca e o realce da navegação */

  /* Distância entre a borda da JANELA e a face direita do conteúdo, medida por
     `tratativa.js`; aqui o padrão para quando o JS não roda. */
  --folga-conteudo: 22px;

  /* Escala de espaçamento */
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;

  color-scheme: light;
}

* { box-sizing: border-box; }
/* Controle de formulário NÃO herda a fonte do corpo por padrão do navegador:
   sem isto, todo botão que não declara a família (o A/NA, os do menu, o
   fechar do painel) sairia na fonte do sistema, e não na Barlow. */
button, input, select, textarea { font-family: inherit; }

body {
  margin: 0;
  /* Barlow para tudo (o sistema). Corpo a 16 px: ESCOLHA do Propostas (DS1),
     a escala do sistema é de papel. */
  font-family: var(--font-sans);
  background: var(--fundo);
  color: var(--texto);
  line-height: 1.55;
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
}

/* Container central consistente (~1100px) em todas as telas.
   O antigo `header.topo` (barra superior azul, pre-redesign v4) foi removido na
   faxina da Fase 15: o shell hoje e .side + .topbar. */
main.conteudo { max-width: 1100px; margin: 2rem auto; padding: 0 1.2rem; }
footer.rodape { padding-left: max(1.2rem, calc((100% - 1100px) / 2)); padding-right: max(1.2rem, calc((100% - 1100px) / 2)); }

/* TÍTULOS do sistema. `h1`: Barlow Condensed 700 (`capa-titulo`/`secao`), SEM
   caixa alta automática — o h1 leva dado digitado (nome de projeto, "75 kWp"), e
   o guia manda preservar as unidades. `h2`: o `secao` do sistema, caixa alta
   por CSS e o fio por baixo (`traco-moldura` em `linha`). O tamanho de cada
   contêiner continua sendo da regra dele; aqui é o desenho. O `<small>` dentro
   do h2 é complemento (contagem, rodada, envio) e volta à caixa e à família do
   corpo. */
h1 { color: var(--titulo); font-family: var(--font-cond); font-size: var(--t-h1); font-weight: 700; letter-spacing: 0.4px; line-height: 1.1; }
h2 { color: var(--titulo); font-family: var(--font-cond); font-size: var(--t-h2); font-weight: 700; letter-spacing: 0.53px; line-height: 1.15;
  text-transform: uppercase; padding-bottom: 0.3rem; border-bottom: var(--traco-moldura) solid var(--fio); }
h1 small, h2 small { font-family: var(--font-sans); font-weight: 400; text-transform: none; letter-spacing: 0; }
a { color: var(--azul); }
/* FOCO de teclado: o anel sólido de 2 px do sistema, em `blu` sobre o claro
   (8,1:1); toda superfície navy com algo focável troca `--foco` para `org`
   (5,5:1): o menu, a capa, a barra do total e a topbar do celular.
   `test_o_FOCO_sobre_navy_e_org` pergunta à cascata, par a par. */
:focus-visible { outline: var(--traco-acento) solid var(--foco); outline-offset: 2px; }

.cartao {
  background: var(--superficie);
  border: 1px solid var(--borda);
  border-radius: var(--raio-cartao);
  padding: var(--sp-5);
  margin-bottom: 1rem;
}

form p { margin: 0.8rem 0; }
form label { display: block; font-weight: 600; margin-bottom: 0.3rem; font-size: 0.85rem; color: var(--cinza); }
input[type="text"], input[type="password"], input[type="email"],
input[type="search"], input[type="number"], input[type="date"],
input[type="datetime-local"], select, textarea {
  width: 100%;
  max-width: 420px;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--line-in);
  border-radius: var(--raio-controle);
  font-size: 0.95rem;
  font-family: inherit;
  color: var(--texto);
  background: var(--superficie);
  transition: border-color .15s;
}
/* O foco do CAMPO é o anel sólido de 2 px do sistema, por FORA da borda; a
   borda fica a do controle — sem brilho, sem sombra, e o campo não "encolhe".
   (Antes: borda azul e halo por sombra.) */
input:focus, select:focus, textarea:focus {
  outline: var(--traco-acento) solid var(--foco);
  outline-offset: 1px;
  border-color: var(--controle-borda);
}

/* ===== OS BOTÕES — a D-VIS-03 (13/10/2026) e a emenda de 26/10/2026 =====
   Instrução `docs/revisao/024`. Fonte: `docs/design-system/componentes/Botoes/`
   e a seção "Botões (D-VIS-03)" de `docs/design-system/componentes/bundle.css`
   (cópia de leitura, versão 14 do artefato). A FORMA é a do CRM — o canto
   `--raio-botao` e a sombra discreta em navy `--sombra-botao*`, a ÚNICA sombra
   do portal —, a paleta é a do sistema, e há QUATRO NÍVEIS, um por papel:

     principal   `.botao` (e o submit sem classe)  a ação que conclui a área
     secundário  `.botao.botao-secundario`         apoio: Voltar, Limpar, filtros
     perigo      `.botao.botao-perigo`             destrutiva: CONTORNO na tela,
                                                   CHEIO só na confirmação
     texto/link  `.botao.botao-texto`              Cancelar, fechar (×), ações
                                                   em linha de tabela

   UMA SÓ AÇÃO PRINCIPAL POR ÁREA. A classificação de cada botão do RFP e do
   BM, com o motivo, está em `docs/relatorios/design-system-desenho.md` §9.

   ⚠️ O PRINCIPAL se chama `.botao`, e não `.botao-acao` como no sistema: o
   portal já o usava em todos os templates, e o nome do sistema ao lado seria
   um segundo nome sem consumidor (regra 17). Os três modificadores têm os
   nomes do sistema.

   ⚠️ OS MODIFICADORES PRECISAM DO `.botao.` (0,2,0): a regra do principal casa
   por `button[type="submit"]` (0,1,1), que vence uma classe sozinha (0,1,0) —
   sem o prefixo, o MESMO par de classes sai de uma cor num `<summary>` e de
   outra num submit, defeito que o PO já viu. Pela mesma razão, a classe de
   TAMANHO de um componente (`.mini-salvar`, `.painel-fechar`…) vem com o
   `.botao.` na regra dele, mais abaixo.

   ⚠️ O ESTADO VENCE O NÍVEL: o hover não vale em botão desabilitado (o
   `:not(…)` de cada um), e o desabilitado vem DEPOIS dos quatro níveis. O
   desabilitado do sistema é fundo `fio` e texto `texto-apoio` (4,92:1), SEM
   OPACIDADE: opacidade mistura o texto com o fundo — o defeito que o A/NA já
   teve (`test_o_toggle_de_aderencia_nao_apaga_o_dado_com_opacidade`).
   O OCUPADO do sistema (`aria-busy` com o anel `.giro`) não foi criado: nenhum
   botão do portal fica ocupado hoje (regra 17). */
.botao, button[type="submit"], input[type="submit"] {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  /* o PRINCIPAL: `blu` chapado, texto branco 8,14:1, o fio do próprio fundo
     (o cheio tem a MESMA caixa do secundário, que tem borda de 1px) */
  background: var(--blu);
  color: var(--branco);
  border: 1px solid var(--blu);
  border-radius: var(--raio-botao);
  box-shadow: var(--sombra-botao);
  padding: 0.62rem 1.25rem;
  font-size: 0.92rem;
  font-weight: 600;
  font-family: inherit;
  /* <button> herda a entrelinha do agente do usuário e <a> herda a do corpo:
     sem fixar, o MESMO botão sai com alturas diferentes conforme a tag. */
  line-height: 1.25;
  cursor: pointer;
  text-decoration: none;
  /* transição só de cor, borda e sombra: nada se move */
  transition: background-color .15s, border-color .15s, box-shadow .15s, color .15s;
}
/* hover `navy` (16,64:1) com a sombra alta; pressionado volta à leve */
.botao:hover:not(:disabled, [aria-disabled="true"], .bloqueado, .botao-desabilitado),
button[type="submit"]:hover:not(:disabled, [aria-disabled="true"]),
input[type="submit"]:hover:not(:disabled, [aria-disabled="true"]) {
  background: var(--navy); border-color: var(--navy); box-shadow: var(--sombra-botao-alta); }
.botao:active, button[type="submit"]:active, input[type="submit"]:active { box-shadow: var(--sombra-botao-leve); }
/* SECUNDÁRIO: `fundo-suave` com a borda de controle (3,8:1 sobre ele) e o
   texto `titulo` (14,81:1); hover `fio`, borda `texto`. */
.botao.botao-secundario { background: var(--fundo-suave); border-color: var(--controle-borda); color: var(--titulo);
  box-shadow: var(--sombra-botao-leve); }
.botao.botao-secundario:hover:not(:disabled, [aria-disabled="true"], .bloqueado, .botao-desabilitado) {
  background: var(--fio); border-color: var(--texto); box-shadow: var(--sombra-botao-leve); }
/* PERIGO: ação que retira, desfaz ou exclui. Na TELA ele só abre a
   confirmação, e é CONTORNO (`estado-erro` sobre branco, 6,54:1; o tingido
   `erro-bg` no hover); CHEIO só o botão que CONFIRMA, dentro dela — o alarme
   cresce do primeiro clique para o segundo, nunca o contrário. A confirmação
   é um `[role="dialog"]` (as telas sobrepostas) ou um `.confirmacao` (o painel
   que abre na própria página, como o da reprovação técnica). */
.botao.botao-perigo { background: var(--branco); border-color: var(--estado-erro); color: var(--estado-erro);
  box-shadow: var(--sombra-botao-leve); }
.botao.botao-perigo:hover:not(:disabled, [aria-disabled="true"], .bloqueado, .botao-desabilitado) {
  background: var(--erro-bg); border-color: var(--estado-erro); box-shadow: var(--sombra-botao-leve); }
[role="dialog"] .botao.botao-perigo, [role="alertdialog"] .botao.botao-perigo, .confirmacao .botao.botao-perigo {
  background: var(--estado-erro); border-color: var(--estado-erro); color: var(--branco); }
[role="dialog"] .botao.botao-perigo:hover:not(:disabled, [aria-disabled="true"], .bloqueado, .botao-desabilitado),
[role="alertdialog"] .botao.botao-perigo:hover:not(:disabled, [aria-disabled="true"], .bloqueado, .botao-desabilitado),
.confirmacao .botao.botao-perigo:hover:not(:disabled, [aria-disabled="true"], .bloqueado, .botao-desabilitado) {
  background: var(--erro-forte); border-color: var(--erro-forte); }
/* TEXTO/LINK: sem fundo, sem borda, sem sombra, `subtitulo` (8,14:1);
   sublinha no hover. */
.botao.botao-texto { padding: 2px; background: none; border-color: transparent; color: var(--subtitulo);
  font-weight: 500; box-shadow: none; }
.botao.botao-texto:hover:not(:disabled, [aria-disabled="true"], .bloqueado, .botao-desabilitado) {
  background: none; border-color: transparent; box-shadow: none;
  text-decoration: underline; text-underline-offset: 3px; }
/* DESABILITADO (e o `span` que faz as vezes de botão travado: `.bloqueado`,
   `.botao-desabilitado`). Depois dos quatro níveis, de propósito. */
.botao:disabled, .botao[aria-disabled="true"], .botao.bloqueado, .botao.botao-desabilitado,
button[type="submit"]:disabled, input[type="submit"]:disabled {
  background: var(--fio); border-color: var(--fio); color: var(--texto-apoio); box-shadow: none;
  cursor: not-allowed; }
.botao.botao-texto:disabled, .botao.botao-texto[aria-disabled="true"] {
  background: none; border-color: transparent; color: var(--texto-apoio); text-decoration: none; }
/* Celular (até 640 px): o alvo de toque de 44 px nos quatro níveis, inclusive
   no link de ação. */
@media (max-width: 640px) {
  .botao, button[type="submit"], input[type="submit"], .rodape-total .enviar { min-height: var(--alvo-de-toque); }
}

/* Checkbox alinhado na mesma linha do rótulo (item 3 do PO) */
p.campo-checkbox { display: flex; align-items: center; gap: 0.55rem; }
p.campo-checkbox label { margin: 0; font-weight: 600; }
p.campo-checkbox input[type="checkbox"] { width: 1.1rem; height: 1.1rem; accent-color: var(--azul); }
/* Radio e checkbox em TODA tela (o BM inclusive) na cor do sistema, a mesma do
   `campo-checkbox` acima: sem isto o navegador pinta o marcado com o azul do
   sistema operacional, ao lado de campos já no desenho novo. */
input[type="radio"], input[type="checkbox"] { accent-color: var(--azul); }
/* O BOTÃO DO SELETOR DE ARQUIVO (`docs/revisao/033` item 16, P10): sem regra, o navegador o desenhava nativo
   (cinza, borda em relevo, Arial) ao lado do «Anexar». Tem o SECUNDÁRIO COMPACTO (`botao botao-secundario
   acao-linha`) e a fonte do campo; o canto é `raio-controle`, porque ele é parte do campo, e não um botão do
   portal — e por isso fica SEM sombra (sombra só em botão, `rfp/tests/test_padrao_visual.py`). O único campo de
   arquivo do portal é o do anexo do BM. */
input[type="file"]::file-selector-button {
  margin-right: 0.6rem; background: var(--fundo-suave); color: var(--titulo);
  border: 1px solid var(--controle-borda); border-radius: var(--raio-controle);
  padding: 6px 15px; font-family: inherit; font-size: 0.82rem; font-weight: 600; line-height: 1.25;
  cursor: pointer; transition: background-color .15s, border-color .15s; }
input[type="file"]::file-selector-button:hover { background: var(--fio); border-color: var(--texto); }

.erros, .errorlist { color: var(--erro); margin: 0.3rem 0; padding-left: 1.1rem; }
/* `.aviso` é COR de texto de atenção (num `h2` da tela de envio e numa nota da
   guia do BM), e não caixa: o `org` puro reprova como texto (3,0:1), então é o
   `org-texto` (6,33:1). */
.aviso { color: var(--alerta-fg); }
.ok { color: var(--ok); }

details.termo {
  border: 1px solid var(--borda);
  border-radius: var(--raio-cartao);
  padding: 0.6rem 0.9rem;
  margin: 0.6rem 0;
  background: var(--superficie);
}
details.termo summary { cursor: pointer; font-weight: 600; color: var(--azul); }
details.termo .texto { font-size: 0.9rem; max-height: 16rem; overflow-y: auto; margin-top: 0.6rem; }

/* TABELA do sistema: cabeçalho branco 600 sobre `navy` (16,6:1), sem caixa
   alta, com o filete `org` na primeira coluna; fio fino entre linhas; zebra. */
table.lista {
  width: 100%; border-collapse: collapse; background: var(--superficie);
  font-variant-numeric: tabular-nums;
}
table.lista th, table.lista td { padding: 0.65rem 0.9rem; border-bottom: var(--traco-cabelo) solid var(--fio); text-align: left; }
table.lista th { background: var(--navy); color: var(--texto-inv); font-size: 0.85rem; font-weight: 600; }
table.lista th:first-child { border-left: var(--traco-acento) solid var(--org); }
table.lista tbody tr:nth-child(even) { background: var(--zebra); }
table.lista tbody tr:hover { background: var(--hover-suave); }
/* A mesma tabela do sistema para as tabelas SEM classe: as cinco seções da
   tela da guia do BM (`data-secao`) e a da correção do envio da RFP saíam com
   o desenho cru do navegador. Coluna de número (`.numero`) à direita, como o
   guia manda para colunas numéricas. */
.conteudo table:not([class]) { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; font-size: 0.9rem; }
.conteudo table:not([class]) th, .conteudo table:not([class]) td { padding: 8px 10px; border-bottom: var(--traco-cabelo) solid var(--fio); text-align: left; vertical-align: top; }
/* ⚠️ O cabeçalho navy é só do `thead`. A linha de total da guia do BM põe o
   rótulo num `th` dentro do `tfoot` ("Total", "Valor total da NF…", "Total
   geral", "Acumulado", "Saldo de recebimento…"); com `th` solto, o rótulo saía
   como cabeçalho navy cobrindo o `colspan` e os valores da mesma linha em
   `lgt` — duas aparências numa linha só (relatório do qa da `017`, §7.1). */
.conteudo table:not([class]) thead th { background: var(--navy); color: var(--texto-inv); font-weight: 600; }
.conteudo table:not([class]) thead th:first-child { border-left: var(--traco-acento) solid var(--org); }
.conteudo table:not([class]) tbody tr:nth-child(even) td { background: var(--zebra); }
.conteudo table:not([class]) .numero { text-align: right; white-space: nowrap; }
/* a linha de total do sistema (`tr.total` do Design System): `lgt`, 600 em
   `navy`, fio `org` em cima — a linha INTEIRA, o rótulo (`th`) incluído. */
.conteudo table:not([class]) tfoot th,
.conteudo table:not([class]) tfoot td { background: var(--lgt); font-weight: 600; color: var(--navy); border-top: var(--traco-acento) solid var(--org); }

/* ETIQUETA do sistema (selo de estado): retangular, caixa alta 10,67 px,
   espaçamento largo, CONTORNO e texto na cor do estado sobre o papel — a
   mesma régua do `.etiqueta` do Propostas. Vale para `.badge` e
   `.status-pill`. Rascunho e reaberta = atenção; enviada = sucesso. */
.badge { display: inline-flex; align-items: center; padding: 3px 8px; border: var(--traco-fio) solid var(--controle-borda);
  background: var(--fundo); color: var(--texto-apoio); font-size: var(--t-selo); font-weight: 600; letter-spacing: 1.4px;
  line-height: 1.2; text-transform: uppercase; white-space: nowrap; }
.badge.nao-iniciada { color: var(--texto-apoio); border-color: var(--controle-borda); }
.badge.rascunho { color: var(--alerta-fg); border-color: var(--org); }
.badge.enviada { color: var(--ok-fg); border-color: var(--ok-fg); }
.badge.reaberta { color: var(--alerta-fg); border-color: var(--org); }

footer.rodape { text-align: center; color: var(--cinza); font-size: 0.8rem; margin: 2.5rem 0 1.5rem; }
footer.rodape p { margin: 0.25rem 0; }
footer.rodape .acesso-info { color: var(--azul-escuro); }

/* ===== Fase 3 — Tela de preenchimento =====
   O layout em 2 colunas (.forn-grid + aside com .bloco-nav/.sec-item/.tot-aside
   e main.preench) foi substituido pela LISTA CONTINUA (.escopo) na Fase 3.10 e
   saiu na faxina da Fase 15. O que a lista continua usa vive em .b-resumo /
   .s-resumo / .area / .secao-lista, mais abaixo. */
.aside-prazo { font-size: 0.78rem; color: var(--cinza); margin-top: 2px; }
.banner { border-radius: var(--raio-cartao); padding: 10px 14px; margin-bottom: 14px; font-size: 0.9rem; }
.banner-prazo { background: var(--erro-bg); border: 1px solid var(--erro); color: var(--erro); }

.progress-wrap { display: flex; align-items: center; gap: 16px; background: var(--superficie); border: 1px solid var(--line); border-radius: var(--raio-cartao); padding: 12px 16px; margin-bottom: 14px; }
.progress-info { font-size: 0.85rem; color: var(--cinza); white-space: nowrap; }
.progress-info b { font-size: 16px; color: var(--azul-escuro); margin: 0 4px; }
.trilho { flex: 1; height: 10px; background: var(--borda); border-radius: var(--raio-reto); overflow: hidden; }
.barra { height: 10px; background: var(--laranja); transition: width 0.4s; }
.salvo { color: var(--ok); font-size: 12px; white-space: nowrap; }

.busca-wrap { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.busca-wrap input[type="search"] { flex: 1; max-width: 480px; padding: 0.6rem 0.8rem; border: 1px solid var(--line-in); border-radius: var(--raio-controle); font-size: 0.9rem; }
.busca-info { font-size: 0.8rem; color: var(--cinza); }
mark { background: var(--realce); }

h2.bloco { color: var(--azul-escuro); font-size: 1.05rem; margin: 6px 0 10px; }

table.itens { width: 100%; border-collapse: separate; border-spacing: 0; background: var(--superficie); border: 1px solid var(--line); border-radius: var(--raio-reto); overflow: hidden; }
/* Cabeçalho do sistema: branco 600 sobre `navy`, sem caixa alta, o filete `org`
   na primeira coluna. ⚠️ O filete é BARRA INTERNA (`inset`), e não
   `border-left`: a tabela é `table-layout: fixed` com `border-collapse:
   separate`, e uma borda de 2 px na primeira célula tiraria largura das
   colunas de texto (descrição e requisito, piso de 388 px, regra 20). */
table.itens th { background: var(--navy); color: var(--texto-inv); font-size: 0.8rem; font-weight: 600; letter-spacing: 0.02em; padding: 9px 12px; text-align: left; border-bottom: var(--traco-fio) solid var(--navy); }
table.itens th:first-child { box-shadow: inset var(--traco-acento) 0 0 var(--org); }
table.itens td { padding: 12px; border-bottom: 1px solid var(--line2); vertical-align: top; font-size: 0.9rem; }
tr.item-row td { border-bottom: none; }
tr.obs-row td { background: var(--superficie-2); padding-top: 0; }
/* ZEBRADO — linha sim, linha nao (PO, 14/08): com descricao e requisito longos,
   o olho perde a linha ao atravessar da esquerda para a direita.

   Cada item e um `<tbody>` proprio, entao a alternancia e por `nth-of-type`
   entre tbodies e nao por `nth-child` de `<tr>` — contar linhas pegaria a
   `obs-row` do parecer e inverteria a faixa dali para baixo.

   ⚠️⚠️ O ESTADO VENCE A ZEBRA (veredito `018`, item 5, 09/10/2026). Esta
   regra dizia "fica antes das regras de realce, que tem mais especificidade" —
   e era o contrario: com `nth-of-type` e as classes, ela pesava (0,4,4), mais
   que o fundo de `falta-justificativa` (0,2,3) e o do diff (`.item-mudou`,
   0,1,1), e nas linhas PARES o zebrado apagava o sinal de "aqui tem o que
   analisar". Agora o seletor inteiro, menos o `td`, vai num `:where()`, que
   pesa ZERO: a zebra fica em (0,0,1), e QUALQUER regra de estado com uma classe
   vence, em qualquer posicao do arquivo. Trava:
   `test_o_ESTADO_vence_a_zebra_nas_linhas_pares`.

   ⚠️ A faixa e SOBREPOSICAO com alfa (--zebra), nao um tom fixo. Com tom fixo
   ela media 1,07 nos dois temas e o PO achou "suave demais" no escuro; subir o
   tom esbarrava nos tons de realce, que ficam logo acima. Com alfa da para
   calibrar cada tema por si: 1,08 no claro e 1,18 no escuro. */
:where(table.itens tbody.grupo-item:nth-of-type(even) tr.item-row) > td { background: var(--zebra); }
/* Algarismos TABULARES no numero do item, como todo numero do portal em coluna
   (veredito `018`, item 3): "44.44.44" mede 54,8 px com eles (60,1 sem), e a
   coluna Item fica em 79 px (`cab_itens.html`). */
.cod { color: var(--azul); font-weight: 700; white-space: nowrap; font-variant-numeric: tabular-nums; }
/* Descricao x requisito: colunas VIZINHAS de largura igual, como eram na
   planilha de origem (PO, validacao da 15).

   `table-layout: fixed` porque a alternativa MEDIU MAL: com as duas colunas em
   50% os 100% estouram (as outras somam 520px em valor fixo) e o navegador
   espremia TODAS na mesma proporcao — o campo de valor unitario caiu de 130px
   para 63px, largura em que nao cabe um preco. Nada na suite via isso.

   No layout fixo os px declarados no `<th>` sao honrados ao pe da letra e o
   que sobra e dividido em partes iguais entre as colunas sem largura — que sao
   exatamente estas duas. Igualdade exata, sem cravar pixel. */
table.itens { table-layout: fixed; }
/* Mesmo corpo de texto da descricao — sao colunas PARES, e reduzir uma delas
   diria que vale menos, que e o contrario da leitura em paralelo. (O 0.8rem que
   a antiga `.req` tinha nem valeria aqui: `table.itens td` e mais especifico e
   ganharia em silencio.) A cor mais suave basta para diferenciar: medido em
   5,27 no claro e 7,65 no escuro, AA nos dois. */
td.req { color: var(--texto-2); }
/* Texto longo sem espaco (codigo de norma, URL) nao pode alargar a coluna nem
   vazar: no layout fixo a largura nao cede, entao a quebra e obrigatoria. */
table.itens td.spec, td.req { overflow-wrap: break-word; }
/* ⚠️ SEM `white-space: nowrap`. Ele convivia com a tabela de largura
   automatica, que alargava a coluna para caber. Desde que a tabela virou
   `table-layout: fixed`, a largura NAO cede: unidade longa ("ÁREA (hectares)")
   transbordava 59px por baixo da celula vizinha e a unidade sumia da tela.
   Regressao introduzida junto com as colunas descricao/requisito. */
.qtd { font-variant-numeric: tabular-nums; overflow-wrap: break-word; }
img.fig { height: 86px; border: 1px solid var(--borda); border-radius: var(--raio-reto); margin-top: 6px; cursor: zoom-in; display: block; }
.leg { font-size: 0.72rem; color: var(--cinza); margin-top: 2px; }

input.vu { width: 100%; padding: 0.5rem 0.7rem 0.5rem 2.1rem; border: 1px solid var(--line-in); border-radius: var(--raio-controle); text-align: right; font-variant-numeric: tabular-nums; font-size: 0.9rem; transition: border-color .15s, box-shadow .15s; }
/* Simbologia de moeda no campo (apontamento do PO). E um ELEMENTO, nao um
   pseudo: pseudo nao tem caixa mensuravel e o alinhamento com o numero so dava
   para acertar no chute — foi o que o PO viu, "aparece o R$ mas esta
   desalinhado".

   O truque do alinhamento: a caixa do rotulo REPETE a do input (mesmo topo,
   mesmo padding vertical, mesma borda transparente, mesma metrica de fonte).
   Com as duas caixas identicas, as duas linhas de texto caem no mesmo lugar
   sem nenhum ajuste manual. */
td.vu-cel { position: relative; }
.vu-moeda { position: absolute; left: 12px; top: 12px;
  padding: 0.5rem 0 0.5rem 0.7rem; border: 1px solid transparent;
  font-size: 0.9rem; line-height: normal; color: var(--texto-2);
  pointer-events: none; }
input.vu:focus { outline: var(--traco-acento) solid var(--foco); outline-offset: 1px; border-color: var(--controle-borda); }
input.vu.expr { border-color: var(--azul); background: var(--hover-suave); text-align: left; }
.vu-hint { font-size: 0.68rem; color: var(--faint); margin-top: 4px; }
/* Valor NAO RECONHECIDO (docs/revisao/003): o texto da pessoa fica no campo,
   a borda e o fundo marcam, e a mensagem diz o que fazer. So tokens de erro que
   ja existem (os mesmos da faixa de falha), nos dois temas. Vence o :focus.
   ⚠️ A COR DO TEXTO vem junto com o fundo, e e o PAR da faixa de falha
   (--erro-fg sobre --erro-bg): fundo de erro sem cor de texto deixava o texto
   herdado, escuro, sobre o fundo de erro escuro -- contraste 1,27 no tema
   escuro, medido pelo `qa` na 004. Pelos tokens: 5,01 (claro) e 7,95 (escuro),
   calculados, nao medidos no navegador. Trava:
   test_o_campo_invalido_DEFINE_a_cor_do_texto. */
input.vu[aria-invalid="true"], input.vu[aria-invalid="true"]:focus {
  border-color: var(--erro-fg); background: var(--erro-bg); color: var(--erro-fg);
  text-align: left; }
.vu-invalido { font-size: 0.72rem; color: var(--erro-fg); margin-top: 4px; line-height: 1.35; }
/* 006, quarta rodada: a recusa do envio VAZIO, dentro da caixa (preenchimento.js, recusarEnvioVazio). */
.recusa-do-envio { font-size: 0.72rem; color: var(--erro-fg); margin: 4px 0 0; line-height: 1.35; }
/* O total e TEXTO puro numa linha cujos vizinhos sao CONTROLES: o texto do
   input comeca 9px abaixo do topo da celula (padding 0.5rem + 1px de borda), e
   o do toggle na mesma altura (3px do trilho + 0.4rem do botao). Sem compensar,
   o total flutuava 9px acima dos dois — apontamento do PO. O calc amarra a
   compensacao as MESMAS medidas do input; mexer nele move os dois juntos. */
/* ⚠️⚠️ VALOR MAIOR QUE A COLUNA QUEBRA LINHA, NUNCA SOME (veredito `018`, item
   2, 09/10/2026). A coluna reserva a casa das CENTENAS DE MILHOES
   ("R$ 999.999.999,99", 117,7 px nos 118 uteis de 142); o campo aceita ate
   999 bilhoes (`max_digits=14`). Com `table-layout: fixed` a celula nao alarga,
   entao o que nao cabe tem de DESCER: SEM `white-space: nowrap` (com ele o
   numero passava por baixo da coluna vizinha), quebra primeiro no espaco depois
   do "R$" ("R$ 1.000.000.000,00", 129,4 px -> "R$" / "1.000.000.000,00", 109,5),
   e `overflow-wrap: anywhere` e a saida do numero que nem sozinho cabe
   ("999.999.999.999,99", 125,2 px). Sem `overflow` nem `text-overflow`: nenhum
   algarismo escondido. Trava: `test_o_TOTAL_maior_que_a_coluna_quebra_e_nunca_esconde_algarismo`. */
.vt { text-align: right; font-variant-numeric: tabular-nums; font-weight: 700; overflow-wrap: anywhere; color: var(--navy); }
/* ⚠️ Seletor com `table.itens` de proposito: `table.itens td { padding: 12px }`
   e MAIS especifico (0,1,2) que `.vt` (0,1,0), entao um `padding-top` solto na
   classe seria ignorado em silencio. Mesma armadilha do `font-size` da coluna
   de requisito, e eu cai nela duas vezes. */
table.itens td.vt { padding-top: calc(12px + 0.5rem + 1px); }

/* ⚠️⚠️ ESTADO DE GRAVACAO — entrega 1, etapa 2, e SEM COLUNA PROPRIA.

   Regra 20 do CLAUDE.md (PO, 26/08): ESTADO RARO NAO PAGA COLUNA PERMANENTE.
   A primeira versao desta etapa deu a ele uma coluna de 134px; medido, ela
   levava descricao e requisito de 388px para 321px — abaixo dos 324px pelos
   quais tres arranjos de chat ja tinham sido recusados.

   A marca mora na celula de `Qtd · Un`, que tem 104px usaveis contra os 92px
   que `✓ 24/08 14:32` mede, e 66px de folga vertical. Custo de altura medido
   antes/depois na tela real: ZERO. */
.marca-estado { margin-top: 4px; font-size: 0.82rem; line-height: 1.3; }
table.itens .estado-salvo { color: var(--ok); white-space: nowrap; }

/* A linha que nao gravou ganha barra de acento de 6px na PRIMEIRA celula.
   Fundo colorido esta nos "becos sem saida" do CLAUDE.md: o melhor tingimento
   desta paleta da contraste 1,27 (escuro) e 1,14 (claro), invisivel. */
table.itens tbody.grupo-item[data-nao-salvo="1"] tr.item-row > td.cod {
  box-shadow: inset 6px 0 0 var(--erro);
}
/* "salvando" esmaece a marca: e transitorio e nao deve competir com a falha,
   que e a unica que exige acao. */
table.itens tbody.grupo-item[data-estado="salvando"] .marca-estado {
  color: var(--texto-3);
}

/* ⚠️⚠️ A FAIXA DA FALHA — largura inteira, embaixo da linha do item.
   "Uma mensagem de 134px de largura vira 254px de altura; a mesma mensagem em
   1434px vira uma linha de texto." Ela so existe quando ha falha, entao custa
   ZERO no caso comum. */
table.itens tr.linha-da-falha > td {
  background: var(--erro-bg);
  border-bottom: 1px solid var(--erro-borda);
  color: var(--erro-fg);
  padding: 8px 12px;
}
/* TRES CANAIS: cor (as duas regras acima), icone e texto (no HTML). */
table.itens .falha-aviso { font-weight: 700; white-space: nowrap; }
table.itens .falha-texto { color: var(--erro-fg); }
/* A SAÍDA da faixa é ação em linha de tabela: o TEXTO/LINK da D-VIS-03
   (`botao botao-texto`, no `preenchimento.js`). Aqui só o lugar e a letra da
   faixa. */
table.itens .falha-retry {
  margin-left: 10px;
  font: inherit;
  font-weight: 600;
}

/* ⚠️⚠️ O RECADO DA TRAVA DO ENVIO — entrega 1, etapa 3.

   Ele fica NO RODAPE, ao lado do botao, porque e ali que a pessoa clica: recado
   que explica por que o envio nao anda tem de estar onde o envio esta.

   ⚠️ E ele NAO usa a cor de erro cheia. A faixa da linha ja e vermelha; repetir
   o mesmo peso aqui poria dois alarmes de mesma intensidade competindo, e o que
   exige acao e a LINHA. Aqui e aviso e caminho, nao alarme. */
.recado-do-envio:empty { display: none; }
.recado-do-envio {
  /* Superfície clara DENTRO da barra navy: os links daqui voltam ao foco `blu`. */
  --foco: var(--blu);
  flex: 1 1 100%;
  order: 2;
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--erro-fg);
  background: var(--erro-bg);
  border: 1px solid var(--erro-borda);
  border-radius: var(--raio-cartao);
  padding: 6px 10px;
}
/* ⚠️ Os nomes das linhas pendentes sao LINKS de verdade — sublinhados e
   focalizaveis. Condicao 1 do PO: "diz QUAIS linhas estao pendentes e LEVA ate
   elas"; algo que leva e um link, e link que nao parece link ninguem clica. */
.recado-do-envio .ir-para-pendente {
  color: inherit;
  font-weight: 700;
  text-decoration: underline;
}

/* ⚠️ O envio TRAVADO nao some: ele continua clicavel e o clique LEVA ate a
   primeira pendente. Recusa sem caminho e o pior desfecho desta tela. O
   atributo aria-disabled diz a quem usa leitor de tela o que a cor diz a quem
   enxerga — e a cor e a do DESABILITADO da D-VIS-03 (fundo `fio`, texto
   `texto-apoio`, 4,92:1), sem a opacidade de antes (opacidade mistura o texto
   com o fundo). O cursor de ajuda e o recado ao lado dizem que o clique ainda
   leva a algum lugar. */
.rodape-total a.enviar.travado {
  background: var(--fio);
  border-color: var(--fio);
  color: var(--texto-apoio);
  box-shadow: none;
  cursor: help;
}

.toggle { display: inline-flex; gap: 0; background: var(--borda); border-radius: var(--raio-controle); padding: 3px; }
/* Borda de 2px SEMPRE, transparente quando nao selecionado: a selecionada
   ganha cor sem mudar o tamanho do botao. Antes o nao-selecionado tinha
   `border: 0` e o selecionado 1px, entao os dois nao tinham a mesma altura.
   O padding compensa os 2px para o controle nao crescer na coluna de 118px. */
.toggle button { flex: 1; padding: calc(0.4rem - 2px) calc(0.75rem - 2px); border: 2px solid transparent; background: transparent; border-radius: var(--raio-controle); cursor: pointer; font-weight: 700; font-size: 0.82rem; color: var(--muted); transition: .12s; }
/* A/NA com FUNDO de cor (pedido do PO): antes era fundo neutro com texto
   colorido e a leitura de relance nao acontecia. Usa o PAR de tokens em vez de
   branco sobre cor forte -- no tema escuro --ok e --erro sao CLAROS, e branco
   sobre eles reprova em contraste (erro que eu ja cometi duas vezes hoje). */
/* ⚠️ Borda na cor FORTE (--ok-fg/--erro-fg), nao na `--*-borda` suave. No tema
   claro o preenchimento do chip dava 1,05 contra o trilho — o chip praticamente
   nao existia, e foi o que o PO viu ("continua muito suave"). O texto ja
   passava; o que faltava era o COMPONENTE se distinguir, criterio de 3:1.
   Com a cor forte: 4,27 e 4,77 no claro, 7,15 e 5,65 no escuro.
   Escurecer o trilho foi medido e nao resolve (1,05 -> 1,30 no melhor caso).
   E o mesmo padrao de `.recusa-veredito`, que ja esta na tela do saneamento. */
.toggle button.a.on { background: var(--ok-bg); color: var(--ok-fg); border-color: var(--ok-fg); }
.toggle button.na.on { background: var(--erro-bg); color: var(--erro-fg); border-color: var(--erro-fg); }
.toggle button:not(.on):hover { color: var(--navy); }
/* ⚠️ SEM `opacity` no desabilitado. Ela valia 0.55, e opacidade MISTURA o texto
   com o fundo: a aderencia — o dado que mais importa da linha — saia em 2,39 no
   tema claro e 3,38 no escuro, medido compondo a mistura (a cor nominal dava
   5,01 e 7,95 e enganava). Nas telas de leitura, que sao a vista integral e o
   saneamento, TODO botao esta desabilitado; apagar o dado ali nao sinaliza
   "nao editavel", so esconde a resposta. O nao-editavel ja se le pelo cursor e
   pela ausencia de hover. Apontamento do PO na validacao da 15. */
.toggle button:disabled { cursor: default; }
/* ⚠️ Sem baixar a cor do NAO selecionado. Tentei `--texto-2` para dar
   hierarquia e deu 4,40 no claro — reprova AA por pouco, que e como um defeito
   destes volta. A hierarquia ja existe e e mais forte que cor: o selecionado
   ganha FUNDO, borda e sombra; o outro fica sem chip nenhum. */

/* Campos DESABILITADOS (proposta em leitura: pós-envio, item fora do pleito,
   vista do admin). Sem isto o navegador aplica o estilo nativo — fundo claro
   e texto cinza — que ignora os tokens e fica ilegível no tema escuro
   (valor unitário quase invisível; PO 08/08). Também remove a aparência
   nativa, que no Windows pinta o campo de cinza. */
input:disabled, textarea:disabled, select:disabled,
.vu:disabled, .obs-box textarea:disabled {
  -webkit-appearance: none; appearance: none;
  background: var(--superficie-2);
  color: var(--texto);
  border-color: var(--borda);
  opacity: 1;                      /* opacity nativa some com o texto */
  -webkit-text-fill-color: var(--texto);   /* Safari/Chrome ignoram color em :disabled */
  cursor: default;
}
input:disabled::placeholder, textarea:disabled::placeholder { color: var(--texto-3); }

/* Bar de ações da linha (observação / perguntar) — conjunto padronizado */
.acoes-linha { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 8px 0 2px; }
.acoes-linha .obs-box, .acoes-linha .esc-box { flex-basis: 100%; }
/* "Adicionar observação" e "Perguntar sobre este item" ABREM uma caixa: são
   o SECUNDÁRIO da D-VIS-03 (`botao botao-secundario acao-linha`); o que
   conclui é o "Lançar"/"Enviar pergunta" de dentro dela. O ícone diz qual é
   qual — o tingido de antes (azul e âmbar) saiu com a paleta do nível. Aqui
   só o tamanho, compacto. */
.botao.acao-linha { gap: 6px; padding: 6px 15px; font-size: 0.82rem; }
.acao-linha .acao-ico { font-size: 0.95rem; line-height: 1; }
.obs-box { border: 1px solid var(--line); border-radius: var(--raio-cartao); padding: 11px 12px; margin: 6px 0 10px; background: var(--superficie); }
.obs-box.just { border-color: var(--alerta-borda); background: var(--alerta-bg); }
.obs-box .cab { font-size: 0.78rem; font-weight: 700; color: var(--navy); display: flex; justify-content: space-between; align-items: center; }
/* max-width:none: a regra genérica de inputs (420px) capava o width:100% —
   com o escopo em largura cheia a caixa ficava perdida à esquerda (PO, 07/08) */
.obs-box textarea { width: 100%; max-width: none; margin-top: 8px; padding: 0.55rem 0.7rem; border: 1px solid var(--line-in); border-radius: var(--raio-controle); font: inherit; font-size: 0.88rem; resize: vertical; transition: border-color .15s, box-shadow .15s; }
.obs-box textarea:focus { outline: var(--traco-acento) solid var(--foco); outline-offset: 1px; border-color: var(--controle-borda); }
.obs-box textarea.preenchido { border-color: var(--ok-borda); }
.estado { font-size: 0.72rem; font-weight: 600; }
.estado.vazio { color: var(--cinza); }
.estado.sujo { color: var(--alerta-fg); }
.estado.salvo { color: var(--ok); }
.obs-rodape { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 4px; }
.obs-rodape .chars { margin-right: auto; }  /* empurra "✓ salvo" + Salvar para a direita */
.chars { font-size: 0.72rem; color: var(--cinza); }
/* "Lançar", "Enviar pergunta", "Responder"…: o PRINCIPAL da caixa, compacto
   (`botao mini-salvar`). O `.botao.` vence o `button[type="submit"]` dos que
   são submit — sem ele, o "Responder" saía do tamanho cheio. */
.botao.mini-salvar { padding: 0.3rem 0.9rem; font-size: 0.8rem; }
.just-msg { color: var(--erro); font-size: 0.76rem; margin-top: 4px; font-weight: 600; }

.preco-lote { background: var(--superficie); border: 1px solid var(--borda); border-radius: var(--raio-cartao); padding: 14px 16px; margin-top: 14px; max-width: 380px; }
.preco-lote label { font-weight: 600; font-size: 0.85rem; color: var(--azul-escuro); display: block; margin-bottom: 6px; }

/* ⚠️ `flex-wrap` (`docs/revisao/033` item 15, P9): sem ele o recado do envio, de base 100 %, dividia a linha com o
   «Enviar» e o espremia até quebrar em duas linhas (medido: 114 × 68 px, rodapé de 65 a 110). Com a quebra, o
   recado vai inteiro para a linha de baixo; o espaço entre linhas é 8 px, e só existe quando há recado. */
.rodape-total { --foco: var(--org); position: fixed; bottom: 0; left: 0; right: 0; background: var(--navy); color: var(--texto-inv); z-index: 50; display: flex; flex-wrap: wrap; align-items: center; gap: 8px 34px; padding: 10px 26px; }
.rodape-total .t { font-size: 12px; opacity: 0.75; }
.rodape-total .v { font-size: 17px; font-weight: 700; font-variant-numeric: tabular-nums; }
/* ⚠️ LARANJA NUNCA É BOTÃO: o Enviar era laranja; é o primário `blu`, com fio
   `capa-texto` para a forma do botão se ler sobre o navy da barra (`blu` sobre
   `navy` dá só 2,0:1; o fio, 11,2:1). */
/* D-VIS-03 (`024`): o canto e a sombra do botão; o PESO — o principal, a
   única ação da barra — é o que o PO decidiu e fica. Antes dos 100% ele é o
   DESABILITADO do sistema (fundo `fio`, texto `texto-apoio`, 4,92:1), e não
   mais o `blu` a 45% de opacidade. O hover vai ao `blu2` (branco 5,51:1): o do
   sistema, `navy`, apagaria o botão na barra navy.
   O botão não encolhe nem quebra o texto (`flex: none`, `nowrap`; `033` item 15). */
.rodape-total .enviar { flex: none; white-space: nowrap; margin-left: auto; background: var(--fio); color: var(--texto-apoio); border: 1px solid var(--fio);
  border-radius: var(--raio-botao); box-shadow: none; padding: 0.6rem 1.6rem; font-weight: 700; font-size: 0.95rem;
  text-decoration: none; pointer-events: none;
  transition: background-color .15s, border-color .15s, box-shadow .15s, color .15s; }
.rodape-total .enviar.ativo { background: var(--blu); color: var(--branco); border-color: var(--capa-texto);
  box-shadow: var(--sombra-botao); pointer-events: auto; }
.rodape-total .enviar.ativo:hover:not(.travado) { background: var(--blu2); }
/* Escopo tem barra fixa de ação própria — esconde o rodapé do app (evita colisão) */
main.conteudo.escopo-page ~ footer.rodape { display: none; }
/* âncora da marca d'água: sem isto o `absolute` sobe até a viewport e volta
   a cobrir a barra lateral (PO 08/08). */
main.conteudo.escopo-page, main.conteudo.confidencial { position: relative; overflow: clip; }

/* Fase 15: veu pelo TOKEN (o literal cravado deixava o lightbox sem escurecer
   no tema escuro — achado da faxina). */
.lightbox { position: fixed; inset: 0; background: var(--veu); display: none; align-items: center; justify-content: center; z-index: 100; cursor: zoom-out; }
.lightbox.on { display: flex; }
.lightbox img { max-width: 88vw; max-height: 80vh; border-radius: var(--raio-reto); background: var(--superficie); }

/* O @media (max-width:600px) que existia aqui so continha regras do
   `header.topo` — saiu junto com ele na faxina da Fase 15. */

/* ⚠️⚠️ A JANELA MÍNIMA — o TERCEIRO DEGRAU (instrução `018` §2.3; PO, 09/10/2026:
   "três degraus"). Abaixo da janela em que descrição e requisito ficariam com
   menos de 388 px LADO A LADO (o piso da regra 20), os dois viram UMA coluna,
   um sobre o outro, com a largura das duas somadas; o requisito embaixo, com o
   rótulo, e o cabeçalho diz "Descrição e requisito".

   O DEGRAU É CONTA, não escolha, e é UM POR TIPO DE RFP (veredito `018`, item
   4): 776 (2 × 388) + as colunas fixas DAQUELA tabela + o que a página come
   fora da tabela com o menu RECOLHIDO, que é o padrão abaixo de 1800 px (66 do
   menu + 130 de paddings, bordas e rolagem, medidos pelo `qa`, adendo A.3.2).
     · SERVIÇOS (preço por item; `cab_itens.html`: 79 + 112 + 167 + 142 + 135 =
       635) → 1607;
     · EQUIPAMENTO (preço por lote, sem as duas colunas de dinheiro: 79 + 112 +
       135 = 326) → 1298. Com o degrau de serviços ela empilharia entre 1298 e
       1607 sem precisar, tirando a leitura em paralelo à toa.
   Quem distingue as duas é `:has(td.vu-cel)`: a célula do valor unitário só
   existe em RFP de preço por item (`linha_item.html`, `{% if
   rfp.preco_por_item %}`). Os dois blocos têm AS MESMAS regras, um com o
   escopo `:has(td.vu-cel)` e o outro com `:not(:has(td.vu-cel))` — disjuntos,
   para nenhum vencer o outro pela especificidade. Alargar coluna fixa move o
   degrau — e `test_o_degrau_do_empilhamento_acompanha_as_colunas_fixas` cobra
   os dois.

   ⚠️⚠️ SÓ CSS, SOBRE O DOM QUE EXISTE: o painel da tratativa continua no `tbody`
   e os campos continuam postando com `hx-include="closest tbody"`. O mecanismo
   é a regra das CÉLULAS ANÔNIMAS da tabela (CSS 2.1 §17.2.1): a descrição e o
   requisito viram BLOCOS, e filhos de linha que não são célula, vizinhos, são
   embrulhados numa ÚNICA célula anônima — a linha passa a ter uma célula a
   menos, na coluna 2, e os dois blocos empilham dentro dela.

   ⚠️⚠️ `td.spec:NOT(.cod)`: a célula do NÚMERO do item também tem a classe
   `spec` (`<td class="cod spec">`). Com `td.spec` puro ela virava bloco junto,
   e os TRÊS vizinhos (número, descrição, requisito) iam para UMA célula anônima
   na coluna 1 — a do número, 79 px — com todas as outras células deslocadas uma
   coluna para a esquerda. Achado em 09/10 lendo o template, antes da medida do
   `qa` no navegador; trava: `test_o_empilhamento_mantem_a_contagem_de_colunas_da_grade`.

   ⚠️ E A CONTAGEM DE COLUNAS NÃO MUDA: a linha do parecer (`colspan` 7/5 no
   template) e a faixa da falha (`colspan` = os `th` do cabeçalho, no JS) contam
   as colunas de sempre. Sumir com o `th` do requisito deixaria a grade com uma a
   menos, e o `colspan` criaria uma coluna fantasma SEM largura declarada — que o
   layout fixo repartiria com a da descrição. Por isso o cabeçalho ganha, no
   fim, uma célula vazia de LARGURA ZERO (`thead tr::after`): a grade continua
   com 7/5 colunas, e a última não ocupa nada.

   Os fundos (zebra, falta de justificativa, mudança do diff) são do `td`; a
   célula anônima não tem fundo, e onde ela é mais alta que os dois blocos
   apareceria o branco. As três regras vão também para a LINHA, e com a mesma
   regra das do `td`: o ESTADO VENCE A ZEBRA (a zebra num `:where()`, que pesa
   zero; veredito `018`, item 5). */
@media (min-width: 901px) and (max-width: 1606.98px) {
  table.itens:has(td.vu-cel) thead th:nth-child(3) { display: none; }
  table.itens:has(td.vu-cel) thead th:nth-child(2)::after { content: " e requisito"; }
  table.itens:has(td.vu-cel) thead tr::after { content: ""; display: table-cell; width: 0; padding: 0; border: 0; }
  table.itens:has(td.vu-cel) tr.item-row > td.spec:not(.cod),
  table.itens:has(td.vu-cel) tr.item-row > td.req { display: block; }
  table.itens:has(td.vu-cel) tr.item-row > td.spec:not(.cod) { padding-bottom: 6px; }
  table.itens:has(td.vu-cel) tr.item-row > td.req { padding-top: 6px; }
  table.itens:has(td.vu-cel) tr.item-row > td.req::before { content: "Requisito técnico mínimo"; display: block;
    margin-bottom: 2px; font-size: .72rem; font-weight: 700; letter-spacing: .03em;
    text-transform: uppercase; color: var(--texto-apoio); }
  :where(table.itens:has(td.vu-cel) tbody.grupo-item:nth-of-type(even)) tr.item-row { background: var(--zebra); }
  table.itens:has(td.vu-cel) tbody.falta-justificativa tr.item-row { background: var(--erro-bg); }
  table.itens:has(td.vu-cel) tr.item-row.item-mudou { background: var(--info-bg); }
}
@media (min-width: 901px) and (max-width: 1297.98px) {
  table.itens:not(:has(td.vu-cel)) thead th:nth-child(3) { display: none; }
  table.itens:not(:has(td.vu-cel)) thead th:nth-child(2)::after { content: " e requisito"; }
  table.itens:not(:has(td.vu-cel)) thead tr::after { content: ""; display: table-cell; width: 0; padding: 0; border: 0; }
  table.itens:not(:has(td.vu-cel)) tr.item-row > td.spec:not(.cod),
  table.itens:not(:has(td.vu-cel)) tr.item-row > td.req { display: block; }
  table.itens:not(:has(td.vu-cel)) tr.item-row > td.spec:not(.cod) { padding-bottom: 6px; }
  table.itens:not(:has(td.vu-cel)) tr.item-row > td.req { padding-top: 6px; }
  table.itens:not(:has(td.vu-cel)) tr.item-row > td.req::before { content: "Requisito técnico mínimo"; display: block;
    margin-bottom: 2px; font-size: .72rem; font-weight: 700; letter-spacing: .03em;
    text-transform: uppercase; color: var(--texto-apoio); }
  :where(table.itens:not(:has(td.vu-cel)) tbody.grupo-item:nth-of-type(even)) tr.item-row { background: var(--zebra); }
  table.itens:not(:has(td.vu-cel)) tbody.falta-justificativa tr.item-row { background: var(--erro-bg); }
  table.itens:not(:has(td.vu-cel)) tr.item-row.item-mudou { background: var(--info-bg); }
}

@media (max-width: 900px) {
  table.itens thead { display: none; }
  table.itens tr { display: block; }
  table.itens tr.item-row { border-top: 8px solid var(--fundo-suave); }
  table.itens td { display: block; border-bottom: none; padding: 6px 14px; }
  /* O thead some aqui (a tabela vira cartao), entao o requisito perderia o
     rotulo que agora e a coluna dele — volta pelo ::before, mesmo idioma de
     qtd e total. A descricao segue sem rotulo: e o texto de abertura da linha.
     E o reempilhamento das duas colunas: neste corte td ja e display:block. */
  table.itens td.req::before { content: "Requisito técnico mínimo: "; font-weight: 600; color: var(--cinza); }
  table.itens td.qtd::before { content: "Qtd · Un: "; font-weight: 600; color: var(--cinza); }
  table.itens td .vu { width: 100%; text-align: left; }
  /* Aqui a celula vira bloco e o "R$" posicionado nao teria a que se ancorar —
     vira rotulo, no mesmo idioma de qtd e total. */
  table.itens td.vu-cel { position: static; }
  table.itens td.vu-cel::before { content: "Valor unit. (R$): "; position: static;
    font-weight: 600; color: var(--cinza); font-size: inherit; }
  table.itens td .vu { padding-left: 0.7rem; }
  /* O total volta ao padding do bloco: nao ha input ao lado com que alinhar. */
  table.itens td.vt { padding-top: 6px; }
  table.itens td.vt::before { content: "Total: "; font-weight: 600; color: var(--cinza); }
  /* ⚠️ A marca de estado mora DENTRO da celula de qtd, que ja tem rotulo
     proprio aqui ("Qtd · Un: "). Ela nao precisa de rotulo separado — e uma
     segunda linha da mesma celula, e no cartao ela fica logo abaixo da
     quantidade, que e onde a pessoa acabou de olhar. */
  .rodape-total { flex-wrap: wrap; gap: 6px 18px; padding: 10px 14px; align-items: center; }
  .rodape-total > div { flex: 1 1 40%; min-width: 0; }
  .rodape-total .t { font-size: 11px; }
  .rodape-total .v { font-size: 15px; }
  /* Enviar ganha a linha inteira embaixo (nao disputa espaco) */
  .rodape-total .enviar { order: 3; margin-left: 0; width: 100%; text-align: center; box-sizing: border-box; }
  .rodape-total .enviar { padding: 0.7rem; }
  .progress-wrap { flex-direction: column; align-items: stretch; gap: 8px; padding: 11px 14px; }
  .progress-info { white-space: normal; }
  .trilho { width: 100%; }
  /* Avisos com botão: no mobile o texto usa a largura, o botão vai pra baixo à DIREITA */
  .aviso-card { flex-wrap: wrap; align-items: flex-start; }
  .aviso-card .aviso-txt { flex: 1 1 60%; }
  .aviso-card .botao { order: 3; flex: 0 0 auto; margin-top: 12px; margin-left: auto; }
  .escopo { padding-bottom: 160px; }
}

/* ===== Fase 3.10 — Escopo em lista contínua (decisão do PO, estilo Excel) ===== */
/* PO 08/08: a marca d'água cobria a tela toda (barra lateral inclusive) e
   ficava feia. Ancorada aqui, cobre só o escopo — que é o texto protegido
   pela medida §12. O overflow:hidden recorta a diagonal na borda. */
.escopo { position: relative; overflow-x: clip; }
/* PO (07/08): o teto de 1100px desperdiçava a tela — o bloco de preenchimento
   acompanha a largura do painel (main.largo). Sem teto o mobile não muda:
   o main já limita antes. */
.escopo { margin: 0 auto; padding: 0 0 130px; }
@media (min-width: 901px) { .escopo { padding: 0 16px 130px; } }
.escopo-cab h1 { margin-bottom: 0.1rem; }
.escopo-cab h1 small { color: var(--cinza); font-weight: 400; font-size: 0.85rem; }

/* ===== A BARRA DE BLOCOS (entrega 2, etapa 2) =====
   Era a sanfona `details.area`, um por bloco. Agora: a barra fixa ao rolar e
   UM bloco visível (`.bloco-painel`); os outros ficam no DOM com
   `hidden="until-found"` (o painel escondido, logo abaixo).
   ⚠️ Só tokens que já existiam — o visual é do PO (desenho §9), e esta etapa
   não inventa cor.
   ⚠️ `z-index: 10`: abaixo da topbar (20), do rodapé (50) e do painel da
   tratativa (69/70), que é `position: fixed` e tem de cobrir a barra. */
.barra-de-blocos { position: sticky; top: 0; z-index: 10; margin-bottom: 4px; background: var(--fundo);
  --bb-folga-cima: 40px; --bb-folga-baixo: 40px; }
/* O PAINEL ESCONDIDO (veredito `012`, item 1) — do comportamento comum, nas
   duas telas: `hidden="until-found"`, para o Ctrl+F do navegador achar texto
   nele. O navegador o esconde com `content-visibility: hidden` (e não com
   `display: none`, que a busca não atravessa): o CONTEÚDO some, mas a caixa
   do painel — borda, sombra, margem — continuaria desenhada, vazia. Aqui ela
   some também. ⚠️ Nenhuma regra pode pôr `display: none` no painel escondido:
   seria o Ctrl+F deixando de achar, calado. */
[data-bloco-painel][hidden="until-found"] { margin: 0; padding: 0; border: 0; box-shadow: none; }
/* O sentinela da barra compacta (instrução `009` §1.1): 1px, devolvido. */
.bb-sentinela { height: 1px; margin-bottom: -1px; }
/* O trilho rola na horizontal; a barra, não — o aviso da espera fica embaixo
   do trilho, preso no topo com ela e fora da rolagem (veredito `002`, item 1). */
.bb-trilho { display: flex; gap: 8px; overflow-x: auto; padding: 8px 0 10px; }
/* CENTRALIZADO QUANDO CABE, e alinhado ao começo quando transborda (instrução
   `010` §1, decisão do PO): margem AUTOMÁTICA antes do primeiro botão e depois
   do último. Com espaço sobrando, as duas margens repartem a sobra e o conjunto
   fica no centro; SEM espaço, margem automática vale ZERO (a sobra negativa não
   vai para ela — CSS Flexbox, §8.1) e o conjunto começa na borda esquerda,
   rolável até o fim.
   ⚠️⚠️ NUNCA `justify-content: center` no trilho: num contêiner que transborda
   ele joga metade do excesso para a ESQUERDA, fora do alcance da rolagem — o
   bloco 1 ficaria inalcançável, a cegueira do §3 do PO na forma mais literal.
   O `safe center` do CSS faz o mesmo que as margens, mas chegou aos navegadores
   bem depois; a margem automática é do flexbox desde sempre. */
.barra-bloco:first-child { margin-left: auto; }
.barra-bloco:last-child { margin-right: auto; }
.bb-espera { margin: -4px 0 8px; font-size: 0.8rem; font-weight: 600; color: var(--azul-escuro); }
.bb-espera:empty { display: none; }
@media (max-width: 900px) { .barra-de-blocos { top: 56px; } } /* abaixo da topbar */
/* ===== O DESENHO DO PO (instrução `008`, 2026-09-23) =====
   Cada bloco é UM botão, o alvo do clique inteiro, com o RETÂNGULO (número,
   alertas, caixa d'água, contagem) e a PÍLULA do nome, fora dele, alternando em
   cima e embaixo (`bb-pilula-cima` / `bb-pilula-baixo`, classe do botão).

   A GEOMETRIA, e ela é o que impede a barra de "pular":
   · todo botão tem a MESMA largura (120px), selecionado ou não — trocar de
     bloco não desloca nenhum retângulo nem nenhuma pílula;
   · o botão reserva uma folga em cima e outra embaixo (`padding` vertical)
     para as pílulas; o retângulo fica no meio. ⚠️ A folga de cada lado é a
     da pílula MAIS ALTA daquele lado, medida pelo `barra_de_blocos.js`
     (`--bb-folga-cima`, `--bb-folga-baixo`; instrução `009` §1.2); os 40px
     aqui são só o primeiro desenho, antes da medida — cabem duas linhas;
   · a pílula mede até DOIS blocos (`200% + 8px`, o `gap` do trilho) e é
     centrada no seu retângulo. Pílulas do mesmo lado estão a dois blocos de
     distância, então duas vizinhas do mesmo lado nunca se tocam;
   · a primeira e a última pílula encostam na borda do seu botão, e medem um
     bloco e meio: centradas, meia pílula ficaria fora do trilho (que rola, e
     corta o que passa da borda), e com dois blocos a primeira encostaria na
     terceira;
   · `z-index: 1` na pílula: ela passa por cima da área vazia do botão vizinho,
     e o clique nela tem de ser dela.
   ⚠️ Só tokens que já existem. O selecionado usa o par do botão cheio
   (`--azul-sup` com `--texto-inv`), no retângulo e na pílula. */
/* ⚠️ `flex: none`: filho de flex é blockificado e ESTICA (armadilha 14). */
.barra-bloco { flex: none; width: 120px; position: relative; padding: var(--bb-folga-cima) 0 var(--bb-folga-baixo); margin: 0; cursor: pointer;
  text-align: left; font: inherit; color: inherit; background: none; border: 0; }
.barra-bloco:focus-visible { outline: none; }
.barra-bloco:focus-visible .bb-retangulo { outline: 2px solid var(--azul); outline-offset: 2px; }
.bb-retangulo { display: block; position: relative; margin-top: 6px; margin-bottom: 6px; padding: 7px 10px 8px;
  background: var(--superficie); border: 1px solid var(--line); border-radius: var(--raio-bloco); }
.bb-retangulo.completo { background: var(--ok-bg); }
.barra-bloco:hover .bb-retangulo, .barra-bloco:hover .bb-pilula { border-color: var(--azul); }
/* o traço curto que liga a pílula ao retângulo, no centro dele */
.bb-retangulo::before { content: ""; position: absolute; left: 50%; height: 10px; border-left: 1px solid var(--line-in); }
.bb-pilula-cima .bb-retangulo::before { bottom: 100%; }
.bb-pilula-baixo .bb-retangulo::before { top: 100%; }
.bb-linha { display: flex; align-items: baseline; gap: 6px; }
.bb-num { font-weight: 700; color: var(--azul-escuro); }
.bb-check { color: var(--ok-fg); font-weight: 700; }
.bb-sinais { margin-left: auto; display: flex; gap: 5px; }
.bb-marca { font-weight: 700; color: var(--azul); }
.bb-estado { display: block; margin-top: 5px; }
.bb-nivel { display: block; height: 4px; background: var(--superficie-3); border-radius: var(--raio-reto); }
.bb-nivel span { display: block; height: 4px; background: var(--laranja); border-radius: var(--raio-reto); }
.bb-retangulo.completo .bb-nivel span { background: var(--ok); }
.bb-contagem { display: block; font-size: 0.72rem; color: var(--cinza); margin-top: 3px; font-variant-numeric: tabular-nums; }
/* A PÍLULA: até TRÊS linhas (instrução `009` §1.2), reticência no fim, o nome
   inteiro no `title`. Ela encosta a 4px do traço que a liga ao retângulo — a
   folga do lado dela, menos 4px. */
.bb-pilula { position: absolute; z-index: 1; left: 50%; transform: translateX(-50%);
  width: max-content; max-width: calc(200% + 8px); padding: 2px 9px;
  background: var(--superficie); color: var(--azul-escuro); border: 1px solid var(--line-in); border-radius: var(--raio-pilula);
  font-size: 0.72rem; font-weight: 600; line-height: 1.2; text-align: center;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden; }
.bb-pilula-cima .bb-pilula { bottom: calc(100% - var(--bb-folga-cima) + 4px); }
.bb-pilula-baixo .bb-pilula { top: calc(100% - var(--bb-folga-baixo) + 4px); }
.barra-bloco:first-child .bb-pilula { left: 0; transform: none; max-width: calc(150% + 4px); }
.barra-bloco:last-child .bb-pilula { left: auto; right: 0; transform: none; max-width: calc(150% + 4px); }
.barra-bloco:only-child .bb-pilula { max-width: 100%; }
/* AS PONTAS USAM A MARGEM (instrução `010` §1.3): com o conjunto centralizado
   e margem dos dois lados de pelo menos meio bloco e meio espaço (o quanto a
   pílula de dois blocos passa do seu botão), a primeira e a última pílula
   voltam a ser como as do meio — dois blocos, centradas no retângulo. A classe
   é do `barra_de_blocos.js`, que MEDE a margem: o CSS não sabe se o conjunto
   cabe. Sem margem (janela estreita, muitos blocos), valem as de cima: um bloco
   e meio, encostadas na borda — centradas, sairiam do trilho, que corta o que
   passa da borda. */
.bb-pontas-com-margem .barra-bloco:first-child .bb-pilula,
.bb-pontas-com-margem .barra-bloco:last-child .bb-pilula { left: 50%; right: auto; transform: translateX(-50%); max-width: calc(200% + 8px); }
/* O SELECIONADO: mais ALTO (o retângulo ocupa a folga vertical que os outros
   deixam), cor e fundo próprios — ⚠️ e NADA que mexa em posição ou largura:
   `test_o_selecionado_NAO_muda_de_largura` lê estas regras. */
.barra-bloco[aria-current="true"] .bb-retangulo { margin-top: 0; margin-bottom: 0; padding-top: 13px; padding-bottom: 14px;
  background: var(--azul-sup); border-color: var(--azul-sup); color: var(--texto-inv); }
.barra-bloco[aria-current="true"] .bb-retangulo::before { height: 4px; }
.barra-bloco[aria-current="true"] .bb-num,
.barra-bloco[aria-current="true"] .bb-check,
.barra-bloco[aria-current="true"] .bb-marca,
.barra-bloco[aria-current="true"] .bb-contagem { color: var(--texto-inv); }
.barra-bloco[aria-current="true"] .bb-pilula { background: var(--azul-sup); border-color: var(--azul-sup); color: var(--texto-inv); }
/* A BARRA COMPACTA (instrução `009` §1.1): presa no topo, só os retângulos. A
   classe `bb-compacta` é do `barra_de_blocos.js`, pelo sentinela.
   · o botão perde as folgas das pílulas, e a barra as DEVOLVE em margem: a
     altura que ela ocupa no fluxo não muda, e nada abaixo dela salta;
   · a pílula some SÓ da vista — recolhida como o texto de leitor de tela, e não
     `display: none`: o nome continua no botão (e no `title` dele);
   · ⚠️ o aviso da espera (`bb-espera`) NÃO é tocado: é ele que impede a troca
     silenciosa, e continua visível na compacta. */
.barra-de-blocos.bb-compacta { margin-bottom: calc(4px + var(--bb-folga-cima) + var(--bb-folga-baixo)); }
.bb-compacta .barra-bloco { padding-top: 0; padding-bottom: 0; }
.bb-compacta .bb-retangulo::before { display: none; }
.bb-compacta .bb-pilula { top: 0; bottom: auto; width: 1px; height: 1px; padding: 0; border: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* Texto só para leitor de tela: o símbolo da marca é `aria-hidden`, e o título
   dele é o que se lê. */
.bb-leitor { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* As marcas que IMPEDEM O ENVIO (`!` e `⚠`, instrução `005` §2.1) — vermelhas,
   pelo critério do desenho §2.4. Em selo, com o par da faixa de erro: sobre o
   fundo do selecionado (`--azul-sup`) o vermelho puro some, o selo não. */
.bb-marca-erro { color: var(--erro-fg); background: var(--erro-bg); border: 1px solid var(--erro-borda);
  border-radius: var(--raio-pilula); padding: 0 4px; line-height: 1.25; }
.barra-bloco[aria-current="true"] .bb-marca-erro { color: var(--erro-fg); }

.bloco-painel { border: 1px solid var(--line); border-radius: var(--raio-cartao); margin-bottom: 10px; background: var(--superficie); }
/* O «← Bloco anterior» à esquerda e o «Próximo bloco →» à direita, no fim do
   painel (instruções `005` §2.3 e `010` §0.1) — o par de navegação de um
   formulário em etapas. `margin-left: auto` no «Próximo»: no primeiro painel,
   sem o «Anterior», ele continua à direita. */
.bloco-rodape { display: flex; align-items: center; gap: 10px; padding: 10px 14px; border-top: 1px solid var(--line); }
.bloco-rodape .bloco-proximo { margin-left: auto; }
/* o cabeçalho tem fundo próprio: os cantos de cima acompanham o painel, senão
   o fundo dele pinta por cima da curva da borda */
.bloco-cab { padding: 12px 14px; background: var(--hover-suave); border-bottom: 1px solid var(--line);
  border-radius: var(--raio-cartao) var(--raio-cartao) var(--raio-reto) var(--raio-reto); }
.b-resumo { display: block; }
.b-resumo .b-tit { display: block; font-weight: 700; font-size: 0.92rem; color: var(--azul-escuro); }
.b-resumo .b-info { display: block; font-size: 0.76rem; color: var(--cinza); margin: 2px 0 5px; }
.b-resumo .b-info b { color: var(--azul-escuro); }
.b-resumo .mini, .s-resumo .mini { display: block; height: 3px; background: var(--superficie-3); border-radius: var(--raio-reto); }
.b-resumo .mini span, .s-resumo .mini span { display: block; height: 3px; background: var(--laranja); border-radius: var(--raio-reto); }

.area-conteudo { padding: 8px 10px; }
details.secao-lista { border: 1px solid var(--line); border-radius: var(--raio-cartao); margin-bottom: 8px; background: var(--superficie); }
details.secao-lista > summary { list-style: none; cursor: pointer; padding: 9px 12px; position: relative; }
details.secao-lista > summary::-webkit-details-marker { display: none; }
details.secao-lista > summary::after { content: "▾"; position: absolute; right: 12px; top: 9px; color: var(--cinza); font-size: 0.8rem; transition: transform 0.2s; }
details.secao-lista[open] > summary::after { transform: rotate(180deg); }
details.secao-lista[open] > summary { background: var(--superficie-2); border-bottom: 1px solid var(--borda);
  border-radius: var(--raio-cartao) var(--raio-cartao) var(--raio-reto) var(--raio-reto); }
.s-resumo { display: block; padding-right: 20px; }
.s-resumo .l1 { display: flex; align-items: center; gap: 7px; font-size: 0.86rem; }
.s-resumo .dot { width: 9px; height: 9px; background: var(--linha); flex: none; }
.s-resumo .dot.part { background: var(--laranja); }
.s-resumo .dot.full { background: var(--ok); }
.s-resumo .s-tit { font-weight: 600; color: var(--texto); }
.s-resumo .l2 { display: flex; justify-content: space-between; font-size: 0.76rem; color: var(--cinza); margin: 3px 0 4px 16px; }
.s-resumo .soma { color: var(--azul-escuro); font-weight: 700; font-variant-numeric: tabular-nums; }
.s-resumo .mini { margin-left: 16px; }

/* Tabelas largas rolam dentro do próprio cartão no mobile (revisão final) */
.rolagem-x { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.rolagem-x table { min-width: 560px; }

/* Ações do envio: lado a lado com quebra — nunca sobrepostos */
.acoes-envio { display: flex; gap: 0.8rem; flex-wrap: wrap; align-items: center; }

/* Barrinha de operadores junto ao campo de valor (teclado numérico mobile) */
.op-barra { display: flex; gap: 6px; margin-top: 6px; }
/* as teclas são o SECUNDÁRIO da D-VIS-03 (`botao botao-secundario`, no
   `preenchimento.js`); aqui só o tamanho */
.op-barra .botao { flex: 1; min-width: 40px; justify-content: center; padding: 0.5rem 0; font-size: 1.05rem; font-weight: 700; touch-action: manipulation; }
@media (min-width: 901px) { .op-barra { display: none; } } /* desktop tem teclado físico */

.itens-container { padding: 6px 10px 10px; }
.itens-container .carregando { color: var(--cinza); font-size: 0.85rem; padding: 8px; }
.itens-container table.itens { border: none; }
.itens-container .preco-lote { margin: 10px 4px 4px; }

/* Apresentação da RFP + termo de habilitação (Fase 3a, spec §6.2.1) */
.apresentacao { max-width: 860px; margin: 0 auto; }
.apresentacao h2 { color: var(--azul-escuro); font-size: 1.05rem; margin-top: 0; }
.texto-preservado { white-space: pre-line; }
.termo li { margin: 0.55em 0; }
.aceite-linha { display: flex; gap: 0.6rem; align-items: flex-start; margin: 0.8rem 0; font-weight: 600; }
.aceite-linha input { margin-top: 3px; }
.aceite-ok { color: var(--verde, var(--ok-fg)); font-weight: 700; }

/* Aviso de plausibilidade (§8.1a camada 1) — consultivo, nunca bloqueia */
.aviso-fraca { margin-top: 6px; padding: 6px 10px; border-radius: var(--raio-cartao); background: var(--alerta-bg); border-left: var(--traco-destaque) solid var(--org); color: var(--alerta-fg); font-size: 0.82rem; }

/* Esclarecimentos (§6.3.1) */
.esc-box { margin-top: 8px; padding: 10px 12px; border-radius: var(--raio-cartao); background: var(--alerta-bg); border: var(--traco-cabelo) solid var(--alerta-borda); border-left: var(--traco-destaque) solid var(--org); }
.esc-box .cab { font-size: 0.82rem; font-weight: 600; color: var(--alerta-fg); margin-bottom: 4px; }
.esc-box textarea { width: 100%; max-width: none; box-sizing: border-box; padding: 0.45rem 0.6rem; border: 1px solid var(--borda); border-radius: var(--raio-controle); font: inherit; font-size: 0.85rem; resize: vertical; }
.esc-ok { margin-top: 8px; padding: 8px 10px; border-radius: var(--raio-cartao); background: var(--ok-bg); border-left: var(--traco-destaque) solid var(--ok-fg); color: var(--ok-fg); font-size: 0.85rem; }
.esc-pub { border-bottom: 1px solid var(--borda); padding: 8px 0; }
.esc-pub .perg { color: var(--azul-escuro); }

/* Link de volta à apresentação/termo/esclarecimentos a partir do escopo */
.esc-ajuda { color: var(--cinza); font-size: 0.82rem; margin: 2px 0 8px; }
.esc-geral .esc-box { margin-top: 8px; max-width: none; width: 100%; box-sizing: border-box; }  /* PO 07/08: caixa pequena */
.esc-geral textarea { width: 100%; box-sizing: border-box; }

/* Formulários de autenticação (login, reset…) — cartão centrado estilo
   ClientOS: respiro generoso, inputs altos e arredondados, botão sólido. */
.auth-wrap { max-width: 400px; margin: 6vh auto 0; }
.auth-wrap h1 { text-align: center; font-size: 1.9rem; margin: 0 0 var(--sp-5); }
.auth-wrap .cartao { padding: var(--sp-6) var(--sp-5); }
.auth-wrap form p { margin: 0 0 var(--sp-4); }
.auth-wrap label { font-size: .8rem; font-weight: 600; color: var(--texto-2); margin-bottom: 6px; }
.auth-wrap input[type="text"], .auth-wrap input[type="email"], .auth-wrap input[type="password"] {
  width: 100%; max-width: none; box-sizing: border-box; padding: 0.8rem 0.95rem;
  border-radius: var(--raio-controle); font-size: 0.98rem; }
/* botão primário ocupa a largura, alto contraste */
.auth-wrap button[type="submit"], .auth-wrap .botao { width: 100%; justify-content: center;
  padding: 0.85rem; font-size: 0.98rem; margin-top: var(--sp-2); }
.auth-wrap > p, .auth-wrap .cartao > p:last-child { text-align: center; }
.auth-wrap a { color: var(--azul); }
/* o "Cancelar" da caixa: TEXTO/LINK (`botao botao-texto mini-cancelar`) */
.botao.mini-cancelar { font-size: 0.8rem; margin-left: 6px; }
.esc-eco { margin: 6px 0; padding: 6px 10px; background: var(--superficie); border-radius: var(--raio-controle); font-style: italic; }
.esc-ok small { display: block; margin-top: 4px; color: var(--cinza); font-style: normal; }

/* A TRATATIVA do item: o texto do fornecedor e a conversa sobre ele, LADO A
   LADO (PO, 14/08). O chat vinha ACIMA da justificativa e ali nao se lia — o
   questionamento e SOBRE aquele desvio, entao nasce colado ao texto que o
   motivou.

   `auto-fit` e nao duas colunas fixas: sem chat, o texto do fornecedor ocupa a
   linha inteira em vez de deixar metade vazia. O minmax faz o que o PO pediu —
   "a depender do espaco horizontal" ficam lado a lado, e no estreito a conversa
   desce, que e a mesma ordem de leitura, em coluna.

   `min-width: 0` nas colunas: sem ele, texto longo sem espaco estoura a faixa
   do grid em vez de quebrar dentro dela. */
/* A TRATATIVA do item — bloco COLAPSÁVEL em largura cheia, na linha de baixo.
   Fechada por padrão; o `summary` é o selo.

   ⚠️ Ela ja foi a oitava COLUNA do item, e durou algumas horas. O PO: "ficou
   muito estreita e muito alta por conta dos varios blocos... muito espaco
   sobrando sob a descricao e os requisitos". Os tres defeitos vinham do mesmo
   lugar: um chat de 380px nao e um chat, a altura dele esticava a linha
   inteira, e as colunas de texto caiam de 555 para 324px para lhe dar espaco.

   Em largura cheia as threads cabem LADO A LADO em vez de empilhadas — e a
   linha do item volta a ser baixa, porque a conversa so aparece se for aberta. */
.tratativa > summary { list-style: none; cursor: pointer; }
.tratativa > summary::-webkit-details-marker { display: none; }
.conv-selo { display: inline-flex; align-items: center; gap: 8px; padding: 4px 12px; border-radius: var(--raio-pilula); background: var(--superficie); border: 1px solid var(--borda); color: var(--texto-2); font-size: .76rem; font-weight: 700; }
.conv-selo::before { content: "▸"; color: var(--cinza); }
.tratativa[open] > .conv-selo::before { content: "▾"; }
.conv-selo:hover { border-color: var(--azul); color: var(--azul); }
.conv-n { background: var(--info-bg); color: var(--azul); border-radius: var(--raio-pilula); padding: 0 8px; font-variant-numeric: tabular-nums; }
.conv-vazio { color: var(--cinza); font-weight: 600; }
/* ===== O PAINEL DA TRATATIVA =====
   Cartao FLUTUANTE do lado direito, sobre a pagina, com o fundo esmaecido — e
   nao uma faixa colada de ponta a ponta (PO, 14/08: "esse lance de aparecer um
   bloco todo numa faixa colada"). A altura e a do CONTEUDO, com teto; so os
   blocos de chat que existirem aparecem.

   O painel sai da tabela SEM sair do DOM: `position: fixed` reposiciona, e o
   elemento continua dentro do `tbody`. E isso que mantem o preenchimento
   funcionando — os campos postam com `hx-include="closest tbody"` e o
   csrf_token vive no tbody. */
.tratativa[open] > .tratativa-painel {
  position: fixed; top: 50%; transform: translateY(-50%); z-index: 70;
  /* A face direita do painel fica DENTRO da face direita do CONTEUDO (PO).
     `--folga-conteudo` e a distancia entre a borda da janela e a face do
     `main`, medida por `tratativa.js` e reposta a cada resize.

     ⚠️ TRES voltas ate entender o problema, e as duas primeiras erraram o ALVO,
     nao o numero. Eu ancorava na JANELA, e a janela nao e a referencia: numa
     tela larga o `main` bate no teto de `--larg-trabalho` (2150px) e fica
     CENTRADO, sobrando moldura dos dois lados — entao um painel preso ao
     viewport passava POR FORA da face do conteudo, que foi o que o PO viu.
     Na minha tela de medicao o `main` enchia a largura e a folga era zero, e o
     defeito nao reproduzia. Fixo ou proporcional, nada ancorado na janela
     resolveria.

     O token tem PADRAO no `:root` (o padding do `main`), para o caso de o JS
     nao rodar: pior que o certo, melhor que passando por fora. */
  right: calc(var(--folga-conteudo) + 40px);
  width: min(660px, calc(100vw - 48px)); box-sizing: border-box;
  max-height: min(78vh, 760px); overflow-y: auto;
  background: var(--superficie); border: 1px solid var(--controle-borda); border-top: var(--traco-acento) solid var(--navy);
  border-radius: var(--raio-cartao);
  padding: 0 18px 20px;
}
@media (max-width: 900px) {
  .tratativa[open] > .tratativa-painel { right: 12px; left: 12px; width: auto; transform: none; top: 8vh; }
}
/* Veu: e um ::before do proprio <details>, entao clicar nele tem o <details>
   como alvo — e assim `tratativa.js` distingue do clique dentro do painel. */
.tratativa[open]::before { content: ""; position: fixed; inset: 0; z-index: 69; background: var(--veu-modal); }
.painel-topo { position: sticky; top: 0; z-index: 1; display: flex; align-items: baseline; gap: 10px;
  background: var(--superficie); border-bottom: 1px solid var(--line); margin: 0 -18px 14px; padding: 14px 18px 12px; }
.painel-topo b { color: var(--navy); font-size: .95rem; white-space: nowrap; }
.painel-desc { color: var(--texto-2); font-size: .82rem; flex: 1; min-width: 0; }
/* o × que fecha: TEXTO/LINK (`botao botao-texto painel-fechar`), com o alvo de
   30 px */
.botao.painel-fechar { flex: none; justify-content: center; width: 30px; height: 30px; padding: 0;
  font-size: 1.1rem; line-height: 1; align-self: center; }
.tratativa-threads { display: flex; flex-direction: column; gap: var(--sp-3); }
.tratativa-threads > * { min-width: 0; }

/* O SELO vive na celula da ADERENCIA, embaixo do A/NA (PO): e ali que se decide
   o item, entao e dali que se abre a conversa. A celula tem ~94px uteis — daí o
   rotulo curto e o numero num chip. */
.tratativa { margin-top: 8px; }
.conv-selo { display: inline-flex; align-items: center; gap: 6px; padding: 3px 9px; border-radius: var(--raio-pilula);
  background: var(--superficie); border: 1px solid var(--borda); color: var(--texto-2);
  font-size: .7rem; font-weight: 700; white-space: nowrap; }
.conv-selo:hover { border-color: var(--azul); color: var(--azul); }
.conv-n { background: var(--info-bg); color: var(--azul); border-radius: var(--raio-pilula); padding: 0 6px; font-variant-numeric: tabular-nums; }
.conv-selo-pendente { border-color: var(--erro-fg); color: var(--erro-fg); }
.conv-falta { background: var(--erro-bg); color: var(--erro-fg); border-radius: var(--raio-pilula); padding: 0 7px; }

/* A LINHA do subitem tem de SALTAR AOS OLHOS quando ha algo a analisar (PO).
   ⚠️ Medido: FUNDO nao resolve. O melhor tom disponivel da 1,27 contra a
   superficie da tabela no escuro e 1,14 no claro — e o `--info-bg` que eu usara
   antes dava 1,00 no escuro, ou seja, invisivel. Fundo tingido nesta paleta e
   sempre sutil.

   Quem tem forca e a BARRA DE ACENTO: `--azul` mede 6,0 no escuro e 7,04 no
   claro, `--erro-fg` 7,28 e 5,72 — bem acima do piso de 3,0 de componente. Por
   isso a barra ficou larga (6px) e o SELO ganhou a cor do estado.

   ⚠️ O fundo NEUTRO de realce saiu de vez quando o zebrado entrou: os dois
   disputavam a mesma faixa estreita de tons e um anulava o outro. Ficou so no
   `falta-justificativa`, que usa `--erro-bg` — ali a diferenca e de MATIZ
   (avermelhado), nao de claridade, entao se le por cima do zebrado. */
tbody.tem-tratativa tr.item-row > td:first-child { box-shadow: inset 6px 0 0 var(--azul); }
tbody.tem-tratativa .conv-selo { background: var(--info-bg); border-color: var(--azul); color: var(--azul); }

tbody.ponto-questionado tr.item-row > td:first-child { box-shadow: inset 6px 0 0 var(--alerta-fg); }
tbody.ponto-questionado .conv-selo { background: var(--alerta-bg); border-color: var(--alerta-fg); color: var(--alerta-fg); }

/* Falta a justificativa obrigatoria: o estado que mais precisa saltar, porque
   trava o envio do fornecedor. */
tbody.falta-justificativa tr.item-row > td { background: var(--erro-bg); }
tbody.falta-justificativa tr.item-row > td:first-child { box-shadow: inset 6px 0 0 var(--erro-fg); }
.tratativa-threads .item-chat { margin-top: 0; }
/* Titulo de cada thread: sem ele, duas threads coladas viram uma so aos olhos. */
.chat-tit { font-size: .72rem; font-weight: 700; color: var(--texto-2); text-transform: uppercase; letter-spacing: .03em; margin: 0 0 2px; padding-bottom: 8px; border-bottom: 1px solid var(--line); }
.chat-tit small { text-transform: none; letter-spacing: 0; color: var(--cinza); font-weight: 600; }
.chat-vazio { font-size: .8rem; color: var(--cinza); font-style: italic; }
/* O lancamento vira BALAO: mesma forma do balao do Q&A, com o canto de baixo
   RETO do lado de quem falou (o resto no `raio-cartao`, regra mais abaixo). Reusa `lancamento_bloco.html` inteiro — o
   historico de versoes e o botao Editar continuam funcionando. */
.item-chat .lanc-bloco { padding: 8px 12px; font-size: .86rem; line-height: 1.45; margin: 0; position: relative; }
.chat-outro .lanc-bloco { background: var(--superficie); border: 1px solid var(--borda); color: var(--texto); }
.chat-eu .lanc-bloco { background: var(--azul-sup); color: var(--texto-inv); }
.chat-eu .lanc-bloco .obs-texto, .chat-eu .lanc-bloco .lanc-quando { color: var(--texto-inv); }
/* ⚠️ Dentro do chat, o BALAO ja e a caixa. `.obs-texto` traz caixa propria —
   fundo, borda e raio — e o resultado era caixa DENTRO de balao, que foi o
   "sem graca" que o PO apontou na observacao. Aqui ela vira texto puro. */
.item-chat .lanc-bloco .obs-texto { margin: 0; padding: 0; background: none; border: 0; border-radius: var(--raio-reto); font-size: inherit; line-height: inherit; color: inherit; }
/* O carimbo vira METADADO de conversa: pequeno, discreto e do lado de quem
   falou — nao uma legenda de formulario atravessada embaixo. */
/* ⚠️ Sem `opacity`: a .85 que o carimbo tinha misturava o `texto-apoio` com o
   fundo e deixava "resposta atualizada em …" a 4,35 sobre branco e 3,98 sobre
   `lgt`. A cor sólida (`texto-apoio` #566370) dá 6,15 / 5,47 / 5,87 (branco,
   `lgt`, `zebra`), e o branco do balão próprio sobre `blu`, 8,14. */
.item-chat .lanc-meta { margin-top: 5px; gap: 8px; font-size: .7rem; }
.chat-eu .lanc-meta { justify-content: flex-end; }
.chat-eu .lanc-bloco .lanc-quando { color: var(--texto-inv); }
.item-chat .lanc-quando { font-size: .7rem; }
.item-chat .lanc-novo { align-self: stretch; }

/* Esclarecimentos persistentes na linha do item — formato de chat (§6.3.1) */
/* ⚠️ TRES CAMADAS, e nao duas. A tela do chat usava `--info-bg`, que no ESCURO
   e praticamente a mesma cor da superficie do painel — medido 1,00, ou seja,
   nao havia camada nenhuma e a coisa saia chapada (PO: "meio sem graca").

   Agora: painel (--superficie) > TELA do chat rebaixada (--fundo) > balao
   erguido de volta. Medido — tela vs painel 1,14 no escuro e 1,16 no claro;
   balao do outro vs tela 1,23 e 1,16; balao proprio vs tela 3,18 e 6,09.
   O balao ganha sombra para o "erguido" se ler tambem no escuro, onde
   diferenca de claridade sozinha rende pouco. */
.item-chat { margin: 4px 0 10px; padding: 12px; background: var(--fundo-suave); border: 1px solid var(--line); border-radius: var(--raio-cartao); display: flex; flex-direction: column; gap: 10px; }
.chat-msg { max-width: 88%; display: flex; flex-direction: column; }
/* O lado sai do AUTOR, relativo a quem olha — nao do TIPO da mensagem (decisao
   do PO, 13/08). As classes de antes eram `.chat-pergunta`/`.chat-resposta`:
   toda pergunta a esquerda, toda resposta a direita. Isso acertava por acaso na
   tela do fornecedor (a Alcance pergunta, ele responde = ele a direita) e
   errava na da Alcance, onde o texto DELA aparecia a esquerda enquanto o campo
   de escrever ficava a direita — a tela se contradizia. */
.chat-eu { align-self: flex-end; align-items: flex-end; }       /* quem olha */
.chat-outro { align-self: flex-start; align-items: flex-start; } /* o outro lado */
.chat-autor { font-size: 0.72rem; font-weight: 700; margin: 0 4px 3px; }
.chat-outro .chat-autor { color: var(--azul); }
/* `--laranja` e SINAL (ponto, barra, borda), nao cor de texto: media 2,47 sobre
   o fundo do chat no tema claro, bem abaixo de AA. Estava aqui desde a Fase 3a
   e passou por todas as varreduras de contraste — elas mediram telas sem
   conversa aberta, e onde nao ha bolha nao ha o que medir. `--alerta-fg` e o
   token de PRIMEIRO PLANO da mesma familia (escurecido na 14.8 justamente para
   passar em AA): 4,81 no claro, 9,04 no escuro. */
.chat-eu .chat-autor { color: var(--alerta-fg); }
/* O rabicho e o que faz o balao parecer BALAO e nao caixa. Feito com o canto
   de baixo RETO do lado de quem fala (o resto no `raio-cartao`, emenda de
   26/10) mais um triangulo em `::after`, que encosta nesse canto — dois
   elementos ja existentes, sem imagem nem SVG. */
.chat-bolha { padding: 8px 12px; font-size: 0.86rem; line-height: 1.45; position: relative; }
.chat-bolha, .item-chat .lanc-bloco { border-radius: var(--raio-cartao); }
.chat-eu .chat-bolha, .chat-eu .lanc-bloco { border-bottom-right-radius: var(--raio-reto); }
.chat-outro .chat-bolha, .chat-outro .lanc-bloco { border-bottom-left-radius: var(--raio-reto); }
.chat-msg .chat-bolha::after, .item-chat .lanc-bloco::after { content: ""; position: absolute; bottom: 0; width: 0; height: 0; border: 7px solid transparent; }
.chat-outro .chat-bolha::after, .chat-outro .lanc-bloco::after { left: -6px; border-right-color: var(--superficie); border-bottom-color: var(--superficie); border-left: 0; border-bottom-width: 0; }
.chat-eu .chat-bolha::after, .chat-eu .lanc-bloco::after { right: -6px; border-left-color: var(--azul-sup); border-bottom-color: var(--azul-sup); border-right: 0; border-bottom-width: 0; }
.chat-outro .chat-bolha { background: var(--superficie); border: 1px solid var(--borda); color: var(--texto); }
.chat-eu .chat-bolha { background: var(--azul-sup); color: var(--texto-inv); }
.chat-hora { font-size: 0.68rem; color: var(--cinza); margin: 2px 4px 0; }
.chat-aguardando { align-self: flex-end; font-size: 0.78rem; color: var(--cinza); font-style: italic; }
/* Fase 15: o fornecedor responde ao questionamento da Alcance no proprio item */
.chat-responder { align-self: stretch; display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }
.chat-responder label { font-size: .8rem; color: var(--texto-2); }
.chat-responder small { color: var(--cinza); }
.chat-responder textarea { width: 100%; }
.chat-responder .mini-salvar { align-self: flex-start; }
/* Fase 15 (formato de preenchimento): a Alcance questiona no proprio item. Do
   lado DELA — a pergunta que se vai fazer nasce onde as anteriores ficaram. */
.chat-questionar { align-self: flex-end; display: flex; flex-direction: column; gap: 6px; margin-top: 4px; width: min(100%, 560px); }
.chat-questionar label { font-size: .8rem; color: var(--texto-2); text-align: right; }
.chat-questionar small { color: var(--cinza); }
.chat-questionar textarea { width: 100%; max-width: none; box-sizing: border-box; }
.chat-questionar .mini-salvar { align-self: flex-end; }
.item-chat .acao-esc { align-self: flex-start; margin-top: 2px; }
.item-chat .esc-box { align-self: stretch; }

/* Navegação entre esclarecimentos (feedback do PO) */
.nav-esc { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin: 8px 0; }
/* filtros de navegação: o SECUNDÁRIO da D-VIS-03 (`botao botao-secundario
   nav-esc-btn`), compacto; as duas variantes guardam a cor do que elas
   contam (pergunta em aberto, respondida) */
.botao.nav-esc-btn { padding: 4px 14px; font-size: 0.82rem; }
.botao.nav-esc-btn.aberta { color: var(--alerta-fg); border-color: var(--alerta-borda); background: var(--alerta-bg); }
.botao.nav-esc-btn.respondida { color: var(--ok-fg); border-color: var(--ok-borda); background: var(--ok-bg); }
.nav-esc-dica { color: var(--cinza); font-size: 0.78rem; }
.realce-nav { animation: realce-nav 2.5s ease; }
@keyframes realce-nav { 0%, 40% { background: var(--realce); } 100% { background: transparent; } }

/* Formulário de solicitação de reabertura (§6.3.2) */
.reab-item { display: block; padding: 5px 4px; border-bottom: 1px solid var(--borda); font-size: 0.86rem; cursor: pointer; }
.reab-item:hover { background: var(--hover-suave); }
.reab-item input { margin-right: 8px; }

/* Topo do escopo — cartão de cabeçalho (feedback do PO, Fase 3b) */
.cab-card { background: var(--superficie); border: 1px solid var(--line); border-radius: var(--raio-cartao); padding: 16px 18px; margin-bottom: 14px; }
.escopo-cab-topo { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }
.escopo-cab-topo h1 { margin: 0; flex: 1 1 auto; min-width: 0; }
.escopo-cab-topo .status-pill { flex: none; margin-top: 6px; }
/* Cabecalho COMPACTO (PO, 14/08): a pill cola no titulo, e o grupo de estado vai
   para a DIREITA — "somente leitura" e, na ponta, o botao da decisao. O `h1`
   perdeu o `flex: 1` para nao empurrar a pill; quem separa e o `margin-left`
   automatico do grupo. */
.escopo-cab-topo h1 { flex: 0 1 auto; }
.cab-estado { margin-left: auto; display: flex; align-items: center; gap: 10px; flex: none; }
.cab-leitura { display: inline-flex; align-items: center; gap: 6px; padding: 3px 8px; border-radius: var(--raio-pilula);
  background: var(--fundo); color: var(--alerta-fg); border: var(--traco-fio) solid var(--org);
  font-size: var(--t-selo); font-weight: 600; letter-spacing: 1.4px; text-transform: uppercase; white-space: nowrap; }
/* O selo e o que chama: so o botao, sem a faixa explicativa, precisava de um
   sinal de que ha algo esperando (decisao do PO). */
.cab-decidir { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
/* ⚠️ AMBAR, nao vermelho (PO, 18/08). Vermelho de erro para dizer "ha um
   desconto esperando voce" faz a cor contradizer o texto: nao ha erro nenhum, ha
   uma decisao com prazo. E o mesmo defeito que o PO ja apontou duas vezes aqui —
   o ambar de atencao dizendo "esta tudo certo" e o verde com "✓" dizendo
   "Proposta desclassificada". Trocado JUNTO com o chip do card: duas cores para
   o mesmo fato seria pior que a cor errada. */
.cab-decidir-selo { display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: var(--raio-pilula); background: var(--alerta-bg); color: var(--alerta-fg);
  font-weight: 700; font-size: .72rem; }
@media (max-width: 900px) {
  .escopo-cab-topo { flex-wrap: wrap; }
  .cab-estado { margin-left: 0; width: 100%; }
}
/* Progresso e busca dividem a LINHA: nenhum dos dois precisa da largura toda, e
   eram duas faixas empilhadas antes do escopo comecar. */
.busca-linha { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: 12px; }
.busca-linha .busca-wrap { margin-bottom: 0; flex: 1 1 320px; }
.busca-linha .progress-wrap { margin-bottom: 0; flex: 1 1 380px; }
@media (max-width: 900px) { .busca-linha { flex-direction: column; align-items: stretch; } }
/* O SELO de estado da proposta: a ETIQUETA do sistema (ver `.badge`). A
   bolinha (`.dot`) sai — a etiqueta é retangular e a cor do estado está no
   contorno e no texto; o `<span class="dot">` continua no HTML (DOM intocado). */
.status-pill { display: inline-flex; align-items: center; gap: 6px; padding: 3px 8px; border-radius: var(--raio-pilula); font-size: var(--t-selo); font-weight: 600;
  letter-spacing: 1.4px; line-height: 1.2; text-transform: uppercase; white-space: nowrap;
  background: var(--fundo); color: var(--texto-apoio); border: var(--traco-fio) solid var(--controle-borda); }
.status-pill .dot { display: none; }
.status-pill.enviada { color: var(--ok-fg); border-color: var(--ok-fg); }
/* ⚠️ Fundo por TOKEN, nao cravado. #FDF1DE era literal, entao nao acompanhava o
   tema: no escuro dava uma pastilha clara com texto claro em cima — medido em
   1,51. Com o par tokenizado: 4,93 no claro e 9,04 no escuro. */
.status-pill.reaberta { color: var(--alerta-fg); border-color: var(--org); }
.status-pill.rascunho { color: var(--alerta-fg); border-color: var(--org); }
.status-pill.desclassificada { color: var(--erro-fg); border-color: var(--erro-fg); }
.escopo-acoes { display: flex; gap: 8px; flex-wrap: wrap; align-items: flex-start; margin-top: 12px; }
/* "Apresentação e termo", "Dúvida geral", "Recolher tudo": o SECUNDÁRIO da
   D-VIS-03 (`botao botao-secundario btn-topo`); aqui só o tamanho */
.botao.btn-topo { gap: 7px; padding: 8px 14px; font-size: 0.84rem; list-style: none; }
.btn-topo::-webkit-details-marker { display: none; }
.esc-geral { margin-top: 0; }
/* aberta, a dúvida geral desce para a própria linha e usa a largura toda
   (o details fecha em shrink-to-fit — sem isso a caixa encolhia ao botão) */
.escopo-acoes .esc-geral[open] { flex: 1 1 100%; }
.esc-geral .esc-box { margin-top: 8px; max-width: none; width: 100%; box-sizing: border-box; }  /* PO 07/08: caixa pequena */

/* OS AVISOS são o DESTAQUE do sistema ("cartões e caixas com borda lateral
   colorida só existem como Destaque"): fio fino no contorno, a barra de
   `traco-destaque` à esquerda na cor da variante, fundo da variante, canto
   reto. As variantes do sistema são Nota (`blu` sobre `lgt`) e Atenção (`org`
   sobre `pessego`), com o RÓTULO em caixa alta e mono, como o CRM ASEC faz
   (`notice.css`); a Norma (`navy`, com "§") não tem consumidor no portal e não
   foi criada (regra 17). Fora do sistema, e com motivo: SUCESSO (decisão do PO:
   "mensagem positiva pedia cor positiva") e ERRO (escolha do Propostas: erro
   não pode ler como atenção), na mesma caixa e sem rótulo gerado.
   O ícone redondo (`.aviso-ic`) sai: a barra é a marca, e o rótulo diz o tipo.
   O elemento continua no HTML. */
.aviso-card { display: flex; gap: 14px; align-items: center; padding: 12px 16px; margin-bottom: 14px;
  border-radius: var(--raio-cartao); border: var(--traco-cabelo) solid var(--fio); border-left: var(--traco-destaque) solid var(--blu); background: var(--fundo-suave); }
.aviso-ic { display: none; }
.aviso-txt { flex: 1; }
.aviso-txt::before { display: block; margin-bottom: 4px; font-family: var(--font-mono); font-size: var(--t-rotulo);
  font-weight: 600; letter-spacing: 2.4px; text-transform: uppercase; }
.aviso-pendente .aviso-txt::before { content: "Nota"; color: var(--blu); }
.aviso-reaberta .aviso-txt::before, .aviso-leitura .aviso-txt::before { content: "Atenção"; color: var(--alerta-fg); }
.aviso-txt strong { display: block; font-size: 0.98rem; margin-bottom: 2px; }
.aviso-meta { font-size: 0.86rem; color: var(--texto-2); }
.aviso-meta b { color: inherit; font-weight: 700; }
.aviso-card .botao { flex: none; }
.aviso-pendente { background: var(--info-bg); border-color: var(--fio); border-left-color: var(--blu); }
.aviso-pendente .aviso-txt strong { color: var(--azul-escuro); }
.aviso-reaberta { background: var(--alerta-bg); border-color: var(--alerta-borda); border-left-color: var(--org); }
.aviso-reaberta .aviso-txt strong { color: var(--alerta-fg); }
/* Variante de APROVACAO: mensagem positiva pedia cor positiva. Usar o ambar
   de 'atencao' para dizer 'esta tudo certo' fazia a cor contradizer o texto
   (apontamento do PO). */
.aviso-ok { background: var(--ok-bg); border: var(--traco-cabelo) solid var(--ok-borda); border-left: var(--traco-destaque) solid var(--ok-fg); }
.aviso-ok .aviso-txt strong { color: var(--ok-fg); }
.aviso-leitura { background: var(--alerta-bg); border-color: var(--alerta-borda); border-left-color: var(--org); }
.aviso-leitura .aviso-txt strong { color: var(--alerta-fg); }
/* Desfecho NEGATIVO (desclassificada). Mesma pele vermelha do prazo, nome
   proprio: o proximo leitor nao deve procurar prazo aqui. Nasceu porque a
   desclassificacao vinha com selo verde de "tudo certo" e a cor contradizia o
   texto — mesmo defeito que o PO ja apontara ao contrario. */
.aviso-encerrado { background: var(--erro-bg); border-color: var(--erro-borda); border-left-color: var(--erro-fg); }
.aviso-encerrado .aviso-txt strong { color: var(--erro); }
.aviso-prazo { background: var(--erro-bg); border-color: var(--erro-borda); border-left-color: var(--erro-fg); }
.aviso-prazo .aviso-txt strong { color: var(--erro); }
.reab-tipo { display: flex; gap: 0.6rem; align-items: flex-start; padding: 8px 4px; font-weight: 400; cursor: pointer; }
.reab-tipo input { margin-top: 4px; }
.obs-reabertura { color: var(--cinza); font-size: 0.85rem; margin-top: 8px; }

/* Balão in-platform (tooltip) (feedback do PO, Fase 3b). O botão
   desabilitado que vinha com ele (`.botao-desabilitado`) é o DESABILITADO da
   D-VIS-03, na regra dos botões. */
.tooltip-wrap { position: relative; display: inline-block; outline: none; }
.tooltip-balao { position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); margin-bottom: 9px; border-radius: var(--raio-cartao); background: var(--navy); color: var(--texto-inv); font-size: 0.8rem; line-height: 1.35; padding: 9px 12px; width: max-content; max-width: 250px; opacity: 0; visibility: hidden; transition: opacity .15s; z-index: 20; text-align: left; }
.tooltip-balao::after { content: ""; position: absolute; top: 100%; left: 50%; transform: translateX(-50%); border: 6px solid transparent; border-top-color: var(--azul-escuro); }
.tooltip-wrap:hover .tooltip-balao, .tooltip-wrap:focus .tooltip-balao, .tooltip-wrap:focus-within .tooltip-balao { opacity: 1; visibility: visible; }

/* Painel do admin (Fase 4) — lista de projetos */
.painel-filtros { display: flex; flex-wrap: wrap; gap: 10px 14px; align-items: flex-end; background: var(--superficie-2); border: 1px solid var(--borda); border-radius: var(--raio-cartao); padding: 12px 14px; margin-bottom: 14px; }
.painel-filtros label { margin-bottom: 0; display: flex; flex-direction: column; gap: 3px; font-size: 0.72rem; color: var(--cinza); text-transform: uppercase; letter-spacing: .02em; }
.painel-filtros input, .painel-filtros select { margin: 0; padding: 5px 8px; font-size: 0.85rem; }
.painel-filtros input[type="number"] { width: 78px; }
.painel-filtros input[type="search"] { width: 150px; }
.painel-filtros .botao { align-self: flex-end; }
/* A .painel-tabela (o painel antes de virar quadro, Fase 9) e os .badge-st/
   .dash-topo que a acompanhavam sairam na faxina da Fase 15. */
.painel-vazio-filtro { color: var(--cinza); padding: 14px 4px; }

/* Painel — cabeçalho de página (breadcrumb + título + ações) */
.phead { display: flex; align-items: flex-end; justify-content: space-between; flex-wrap: wrap; gap: 14px; margin-bottom: 22px; }
/* A TRILHA em caixa alta, espaçamento largo (a barra superior do CRM ASEC). */
.phead .bc { display: flex; align-items: center; gap: 6px; font-size: 11px; letter-spacing: 1px; text-transform: uppercase; color: var(--faint); font-weight: 600; margin-bottom: 8px; }
.phead .bc a { color: var(--cinza); text-decoration: none; } .phead .bc a:hover { color: var(--azul); }
.phead .bc span { color: var(--texto-2); }
.phead h1 { margin: 0; }
.phead .psub { margin: 5px 0 0; color: var(--cinza); font-size: 0.9rem; }
.phead .pbtns { display: flex; gap: 10px; flex-wrap: wrap; }

/* Painel — drill-down do projeto */
.tiles { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin: 4px 0 20px; }
/* Fase 15.7: o quadro do processo ficou com 3 KPIs (menor total e aderencia
   media foram para a visao irma). Sem isto, o 4o slot vazio deixava um buraco
   na fileira. */
.tiles-3 { grid-template-columns: repeat(3, 1fr); }
/* KPI compacto (feedback do PO: tile alto com vazio dentro): ícone à ESQUERDA,
   rótulo + número à direita — o mesmo conteúdo em ~1/3 da altura. */
/* O `Indicador` do sistema: fio no contorno, topo de 2 px em `navy`, o primeiro
   em `org`; o número em Barlow Condensed 700 (`indicador-valor`). */
.tile { min-width: 0; background: var(--superficie); border: var(--traco-fio) solid var(--borda); border-top: 2px solid var(--navy);
  padding: var(--sp-4) 18px;
  display: grid; grid-template-columns: auto 1fr; column-gap: 14px; align-items: center; }
.tile-val { overflow-wrap: anywhere; grid-column: 2; }
.tile-rot { grid-column: 2; }
/* tiles sem ícone (resumo do cliente): texto ocupa a largura toda */
.tile > .tile-rot:first-child, .tile > .tile-rot:first-child + .tile-val { grid-column: 1 / -1; }
.tile-chip { width: 40px; height: 40px; border-radius: var(--raio-reto); display: grid; place-items: center;
  margin-bottom: 0; grid-row: 1 / span 2; }
.tile-chip svg { width: 19px; height: 19px; stroke: currentColor; stroke-width: 1.9; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.tile-chip.b { background: var(--info-bg); color: var(--azul); }
.tile-chip.g { background: var(--ok-bg); color: var(--ok); }
.tile-chip.o { background: var(--alerta-bg); color: var(--org); }
.tile-chip.r { background: var(--erro-bg); color: var(--erro); }
.tile-rot { font-size: 0.75rem; color: var(--cinza); font-weight: 600; }
.tile-val { font-family: var(--font-cond); font-size: 1.6rem; font-weight: 700; color: var(--navy); margin-top: 2px; font-variant-numeric: tabular-nums; }
.tiles > .tile:first-child { border-top-color: var(--org); }
.tile.flag .tile-val { color: var(--erro); }
/* PO 08/08: o comparativo ficava espremido (988px, com rolagem horizontal)
   enquanto as red flags levavam 623px. As flags são cartões de texto e leem
   bem estreitas: ganham faixa contida e o comparativo fica com o resto.
   minmax(0,1fr) na 1ª coluna: sem o 0, o conteúdo largo da tabela impede o
   grid de encolher a coluna. Em ≤900px o grid vira 1 coluna (mobile intacto). */
.grid2 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, 360px); gap: 16px; align-items: start; }
.grid2 > * { min-width: 0; }  /* impede que tabelas largas estourem a largura */
.grid2-eq { grid-template-columns: 1fr 1fr; align-items: stretch; }  /* par de gráficos: blocos do MESMO tamanho, mesmo quando um tem nota */
.painel-bloco { background: var(--superficie); border: 1px solid var(--borda); border-radius: var(--raio-cartao); padding: var(--sp-5) var(--sp-5); margin-bottom: var(--sp-4); }
.painel-bloco h2 { margin: 0 0 var(--sp-4); font-size: 1.02rem; letter-spacing: -.01em; }
.tab-scroll { overflow-x: auto; }
table.comp { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
/* rótulo da dimensão (Bloco) pequeno e discreto; EMPRESAS com peso — são as
   protagonistas da comparação */
/* Cabeçalho do sistema: branco 600 sobre `navy`, filete `org` na primeira
   coluna. O rótulo da dimensão (Bloco) segue pequeno; as EMPRESAS, maiores. */
table.comp th { color: var(--texto-inv); text-align: right; padding: 10px 12px; white-space: nowrap; border-bottom: var(--traco-fio) solid var(--navy); font-size: 0.78rem; font-weight: 600; letter-spacing: .02em; background: var(--navy); }
table.comp th:first-child { text-align: left; border-left: var(--traco-acento) solid var(--org); }
table.comp th:not(:first-child) { color: var(--texto-inv); font-size: .86rem; letter-spacing: 0; }
/* selos do cabecalho: menor total / vencedora / desclassificada. Sobre o NAVY
   o selo de contorno não se leria (o verde de estado sobre navy dá ~2,6): aqui
   a etiqueta é CHEIA, o fundo tingido com o texto do estado (5,5:1 ou mais). */
table.comp th .th-pill { display: inline-block; margin-left: 7px; padding: 2px 7px; border-radius: var(--raio-pilula); font-size: var(--t-selo); font-weight: 600; letter-spacing: 1.4px; text-transform: uppercase; vertical-align: 1px; }
.th-pill.menor { background: var(--ok-bg); color: var(--ok-fg); }
.th-pill.win { background: var(--alerta-bg); color: var(--alerta-fg); }
.th-pill.out { background: var(--erro-bg); color: var(--erro-fg); }
.th-pill.envios { background: var(--info-bg); color: var(--info-fg); }
table.comp td { padding: 12px; text-align: right; border-bottom: 1px solid var(--line2); white-space: nowrap; font-variant-numeric: tabular-nums; }
/* zebra sutil + divisor fino entre as colunas de valores */
table.comp tbody tr:nth-child(even) td { background: var(--superficie-2); }
table.comp td:not(:first-child), table.comp th:not(:first-child) { border-left: 1px solid var(--borda); }
table.comp td.cel-bloco, table.comp td.cel-item { text-align: left; font-weight: 600; color: var(--navy); }
table.comp td.cel-item small { color: var(--cinza); font-weight: 400; }
table.comp tbody tr:hover td { background: var(--superficie-2); }
/* menor da linha: check + verde, SEM pintar a celula (o colunao verde
   empilhado parecia planilha — queixa do PO) */
table.comp td.min { color: var(--ok); font-weight: 700; }
/* ⚠️ Sem `opacity` no ✓: a .85 dava 4,48 na linha par (`zebra`). Na cor sólida
   do `td.min` (`ok` #1b6b43): 6,50 branco, 6,20 `zebra`, 5,60 `ok-bg` (total). */
table.comp td.min::before { content: "✓"; margin-right: 7px; font-weight: 700; }
/* no TOTAL o vencedor recebe o preenchimento — um destaque so, com forca */
/* total como FAIXA de fechamento (zebra não alcança: regra depois vence) */
/* a linha de total do sistema: `lgt`, 600 em `navy`, fio `org` em cima */
table.comp tr.total td { background: var(--lgt); border-top: var(--traco-acento) solid var(--org); border-bottom: 0; font-weight: 700; color: var(--navy); font-size: 1.02rem; padding: 14px 12px; }
table.comp tr.total td.min { background: var(--ok-bg); }
table.comp tr.rswp td { background: transparent; color: var(--texto-2); font-size: .8rem; padding: 7px 12px; border-bottom: 0; }
table.comp tr.rswp td:first-child { text-transform: uppercase; letter-spacing: .04em; font-size: .68rem; font-weight: 700; color: var(--faint); }
/* Fase 14: o "NA" da celula e marcador de desvio — sobe junto para AA */
.cel-na { color: var(--alerta-fg); font-weight: 700; }
.flags { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 9px; }
.flags li { display: flex; gap: 11px; align-items: flex-start; padding: 11px 12px; border-radius: var(--raio-cartao); font-size: 0.85rem; line-height: 1.4; border: 1px solid; border-left-width: var(--flag-ac-w); }
.flags li.r { background: var(--flag-r-bg); border-color: var(--flag-r-borda); border-left-color: var(--flag-r-ac); }
.flags li.o { background: var(--flag-o-bg); border-color: var(--flag-o-borda); border-left-color: var(--flag-o-ac); }
.flags .fic { width: 28px; height: 28px; border-radius: var(--raio-reto); display: grid; place-items: center; flex: none; }
.flags .fic svg { width: 15px; height: 15px; stroke: currentColor; stroke-width: 2; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.flags li.r .fic { background: var(--flag-r-chip); color: var(--flag-r-ic); }
.flags li.o .fic { background: var(--flag-o-chip); color: var(--flag-o-ic); }
.flags b { color: var(--navy); }
.drill-bloco { border: 1px solid var(--borda); border-radius: var(--raio-cartao); margin-bottom: 8px; }
.drill-bloco > summary { cursor: pointer; padding: 8px 12px; font-weight: 600; color: var(--azul); }
.drill-bloco > summary small { color: var(--cinza); font-weight: 400; }
.drill-bloco .tab-scroll { padding: 0 12px 12px; }
.desvios { display: flex; flex-wrap: wrap; gap: 12px; }
.desvio-card { flex: 1 1 260px; border: 1px solid var(--borda); border-radius: var(--raio-cartao); padding: 10px 12px; }
.desvio-empresa { font-weight: 700; color: var(--azul-escuro); margin-bottom: 6px; }
.desvio-n { background: var(--alerta-bg); color: var(--alerta-fg); font-size: 0.72rem; font-weight: 700; border-radius: var(--raio-pilula); padding: 1px 8px; margin-left: 6px; }
.desvio-card ul { margin: 0; padding-left: 18px; font-size: 0.82rem; color: var(--texto-2); }
/* Fase 14: resumo de desvios por bloco no topo da analise. Chips por item com
   o PAR de tokens das flags (severidade vem do dado; nada de emoji na UI). */
.desvios-topo > summary small { color: var(--texto-2); }
.desvios-topo .check-explica { padding: 0 12px; }
.desvios-topo .desvios, .desvios-topo .painel-vazio-filtro { padding: 0 12px 12px; }
.desvio-linha { margin: 4px 0; font-size: .84rem; color: var(--texto-2); line-height: 1.9; }
.desvio-item { display: inline-block; margin: 0 4px 0 2px; padding: 1px 8px; border-radius: var(--raio-pilula); font-size: .72rem; font-weight: 700; text-decoration: none; border: 1px solid; }
/* Texto do chip usa o PAR fg/bg do estado (AA nos 2 temas). A 1a escolha usava
   --flag-*-chip, que e FUNDO de icone das flags — como texto dava 1,2:1. */
.desvio-item.r { background: var(--erro-bg); color: var(--erro-fg); border-color: var(--erro-borda); }
.desvio-item.o { background: var(--alerta-bg); color: var(--alerta-fg); border-color: var(--alerta-borda); }
.desvio-analise { font-size: .78rem; margin-left: 6px; white-space: nowrap; }
.chart-box { position: relative; height: 280px; }
.chart-nota { color: var(--cinza); font-size: 0.8rem; margin-top: 8px; }
@media (max-width: 900px) {
  .grid2, .grid2-eq { grid-template-columns: 1fr; }
  .tiles, .tiles-3 { grid-template-columns: repeat(2, 1fr); }
  .phead { margin-bottom: 16px; }
}
/* Celular: tiles compactos (não podem tomar a tela toda) */
@media (max-width: 600px) {
  .tiles { gap: 10px; }
  .tile { padding: 10px 12px; column-gap: 10px; }
  .tile-chip { width: 30px; height: 30px; border-radius: var(--raio-reto); }
  .tile-chip svg { width: 16px; height: 16px; }
  .tile-rot { font-size: 0.68rem; }
  .tile-val { font-size: 1.15rem; }
  .painel-bloco { padding: 14px; }
  .phead h1 { font-size: 1.25rem; }
}

/* Kanban de "Minhas RFPs" (fornecedor) */
/* Mesmo token do shell com barra lateral: um teto so para tela de trabalho,
   com ou sem a lateral. Era 1600px cravado -- mais um dos quatro valores que
   deixavam as telas desalinhadas. */
main.conteudo.largo { max-width: var(--larg-trabalho); }
/* Mesma correcao: #EEF0F2 era cravado e media 1,74 no escuro. */
.status-pill.nao-iniciada { color: var(--texto-apoio); border-color: var(--controle-borda); }
/* A que o PO apontou: fundo #FBF0CE cravado, texto --alerta-fg. No claro dava
   4,78, no limite; no ESCURO, 1,48 — pastilha clara com texto claro. As tres
   pills de cor crua vinham da Fase 13, com a nota de que ficavam para depois. */
/* ⚠️⚠️ 24/08 — A CONTEMPLADA SAI DO AMBAR E VAI PARA O VERDE. Decisao do PO.
   Ela usava --alerta-*, o MESMO ambar de `em_negociacao` e de `rascunho`: a
   proposta VENCEDORA aparecia na cor de "atencao", e tres status diferentes
   ficavam indistinguiveis de longe numa coluna de 9 cards.
   ⚠️ Mexe SO nesta regra, e por TOKEN (--ok-*, que ja existe medido nos dois
   temas). Nenhum token foi alterado, entao o modulo de BM — que compartilha
   este arquivo — nao e afetado. */
.status-pill.contemplada { color: var(--ok-fg); border-color: var(--ok-fg); }
/* Fase 13 — estagios entre o envio e a adjudicacao. A classe vem do proprio
   valor do status, entao o nome tem underscore. Cor por token (as pills
   antigas ainda tem cor crua; nao mexo nelas nesta fase). */
.status-pill.tecnica_aprovada { color: var(--info-fg); border-color: var(--blu2); }
/* A atenção do sistema: contorno `org`, texto `org-texto` (6,33:1). O texto
   ia de `--navy` porque o laranja sobre âmbar dava 2,53 — o `org-texto` passa. */
.status-pill.em_negociacao { color: var(--alerta-fg); border-color: var(--org); }

/* Opção 2: o quadro é uma SUPERFÍCIE própria (fundo do board, estilo Trello) */
.kanban { display: flex; gap: 14px; align-items: flex-start; overflow-x: auto; background: var(--board-bg); border: 1px solid var(--board-borda); border-radius: var(--raio-cartao); padding: var(--sp-4); }
/* Board: página travada na altura da tela; a SUPERFÍCIE preenche o espaço (colunas
   naturais em cima), então o board chega até o rodapé sem scroll vertical. */
@media (min-width: 901px) {
  .app:has(main.conteudo.board) { height: 100vh; overflow: hidden; }
  main.conteudo.board { flex: 1; min-height: 0; display: flex; flex-direction: column; }
  /* PO 08/08: com muitos cards a coluna ESTOURAVA a tela em vez de rolar.
     Causa: `body.has-side main.conteudo` (0,2,2) vence `main.conteudo.board`
     (0,2,1) e impõe `flex: 1 0 auto` — flex-shrink 0 faz o main crescer até o
     conteúdo e furar o 100vh do .app, que corta o excedente no overflow:hidden.
     Aqui a especificidade é maior: o main volta a poder encolher e a rolagem
     acontece DENTRO da coluna (estilo Trello), como o desenho previa. */
  body.has-side main.conteudo.board { flex: 1 1 0%; min-height: 0; }
  .board > h1, .board > .home-hero { flex: none; }
  .board .kanban { flex: 1; min-height: 0; align-items: flex-start; }
  .board .kanban-col { max-height: 100%; }
  .board .kanban-col-corpo { overflow-y: auto; }
  /* A home da 15.6 nao e um quadro: e uma LISTA DE GRUPOS que cresce com o
     conteudo. O board trava a pagina em 100vh contando que algo la dentro
     role; o Kanban tinha isso (a coluna), a lista nao tinha nada -- e por
     isso transbordava por cima do rodape (apontamento do PO).
     A rolagem e do BLOCO, nao da pagina, como ele pediu: quem rola aqui e
     `.grupos-natureza`. Tudo o que vem antes dela (titulo, destaque, tiles,
     filtros) fica fixo no topo. */
  .board > .grupos-natureza { flex: 1; min-height: 0; overflow-y: auto; }
  .board > .tiles, .board > .painel-aguarda { flex: none; }
}
/* coluna de largura FIXA, como o Trello: em ultrawide as colunas NAO
   esticam (cards viravam tapetes — queixa do PO); o fundo do quadro usa a
   tela toda e sobra respiro a direita */
.kanban-col { flex: 0 0 330px; min-width: 330px; background: var(--board-col); border: 1px solid var(--borda); border-radius: var(--raio-cartao); display: flex; flex-direction: column; }
.kanban-col-cab { display: flex; align-items: center; gap: 8px; justify-content: space-between; padding: 12px 14px 9px; }
/* bolinha de status antes do título (referência ClientOS) */
.kanban-col-titulo { font-weight: 700; color: var(--azul-escuro); font-size: 0.85rem; display: flex; align-items: center; gap: 7px; }
.kanban-col-titulo::before { content: ""; width: 8px; height: 8px; border-radius: var(--raio-reto); background: var(--faint); }
.kanban-col:nth-child(1) .kanban-col-titulo::before { background: var(--faint); }
.kanban-col:nth-child(2) .kanban-col-titulo::before { background: var(--org-texto); }
.kanban-col:nth-child(3) .kanban-col-titulo::before { background: var(--azul); }
.kanban-col:nth-child(4) .kanban-col-titulo::before { background: var(--laranja); }
.kanban-col:nth-child(5) .kanban-col-titulo::before { background: var(--ok); }
.kanban-col:nth-child(6) .kanban-col-titulo::before { background: var(--erro); }
.kanban-col-conta { background: var(--superficie); color: var(--cinza); font-size: 0.72rem; font-weight: 700; border-radius: var(--raio-pilula); padding: 1px 9px; border: 1px solid var(--line); }
.kanban-col-corpo { padding: 2px 8px 10px; display: flex; flex-direction: column; gap: 10px; min-height: 40px; }
.kanban-vazia { color: var(--texto-2); text-align: center; padding: 10px 0; font-size: 0.86rem; }

.card-rfp { background: var(--superficie); border: 1px solid var(--borda); border-radius: var(--raio-cartao); padding: var(--sp-4) var(--sp-4) var(--sp-3); transition: transform .15s, box-shadow .15s, border-color .15s; }
/* sem sombra e sem "levantar": o hover é o fio que escurece */
.card-rfp:hover { border-color: var(--azul); }
.card-rfp-topo { display: flex; flex-direction: column; gap: 8px; }
/* código do projeto no canto (estilo TSK7 do ClientOS): monoespaçado, discreto */
.card-rfp-cod { align-self: flex-start; font-family: var(--font-mono);
  font-size: .68rem; font-weight: 600; letter-spacing: .04em; color: var(--texto-2);
  background: var(--superficie-2); border: 1px solid var(--borda); border-radius: var(--raio-pilula);
  padding: 2px 9px; }
.card-rfp-titulo { font-weight: 700; color: var(--azul); line-height: 1.3; }
.card-rfp-titulo small { color: var(--cinza); font-weight: 500; display: block; margin-top: 1px; }
.card-rfp-topo .status-pill { align-self: flex-start; }
.card-rfp-projeto { color: var(--azul-escuro); font-size: 0.84rem; font-weight: 500; margin-top: 7px; }
.card-rfp-prazo { color: var(--cinza); font-size: 0.79rem; margin-top: 2px; }
.card-rfp-chip { margin-top: 9px; background: var(--alerta-bg); color: var(--alerta-fg); font-size: 0.77rem; font-weight: 600; border-radius: var(--raio-cartao); padding: 6px 9px; }

.card-rfp-kpis { margin-top: 11px; border-top: 1px solid var(--line2); padding-top: 10px; display: flex; flex-direction: column; gap: 8px; }
.card-rfp-kpis .kpi { display: flex; flex-direction: column; gap: 2px; }
.card-rfp-kpis .kpi-rot { font-size: 0.68rem; color: var(--faint); text-transform: uppercase; letter-spacing: .03em; font-weight: 600; }
.card-rfp-kpis .kpi-val { font-size: 0.85rem; font-weight: 700; color: var(--navy); font-variant-numeric: tabular-nums; }
.card-rfp-kpis .kpi-barra { display: block; height: 6px; border-radius: var(--raio-reto); background: var(--borda); overflow: hidden; margin-top: 3px; }
.card-rfp-kpis .kpi-barra > span { display: block; height: 100%; background: var(--laranja); }
.card-rfp-kpis .kpi-linha { display: flex; gap: 14px; }
.card-rfp-kpis .kpi-linha .kpi { flex: 1; }

/* Card inteiro clicável (abre a proposta na etapa atual). As acoes em botao
   (.card-rfp-acoes) e o rodape "abrir" (.card-rfp-abrir) migraram para o
   quick-view e sairam na faxina da Fase 15. */
.card-rfp[data-href] { cursor: pointer; }
.card-rfp[data-href]:focus-visible { outline: 2px solid var(--azul); outline-offset: 2px; }

/* Quick-view da proposta — modal sobreposto (estética Trello) */
body.qv-open { overflow: hidden; }
/* Fase 15: o veu e a sombra usam o TOKEN. O literal estava cravado aqui, o
   que deixava o quick-view sem escurecer no tema escuro — o token existia
   justamente para isso e ninguem tinha plugado (achado da faxina). */
.qv-overlay { position: fixed; inset: 0; z-index: 80; display: flex; align-items: flex-start; justify-content: center; padding: 4vh 16px 4vh; background: var(--veu-modal); animation: qv-fade .15s ease; }
.qv-overlay[hidden] { display: none; }
@keyframes qv-fade { from { opacity: 0; } to { opacity: 1; } }
.qv-modal { position: relative; background: var(--superficie); border: 1px solid var(--controle-borda); border-top: var(--traco-acento) solid var(--navy); border-radius: var(--raio-cartao); width: 100%; max-width: 680px; max-height: 92vh; overflow-y: auto; padding: 28px 30px; animation: qv-pop .16s ease; }
@keyframes qv-pop { from { transform: translateY(8px) scale(.98); opacity: .5; } to { transform: none; opacity: 1; } }
/* o × do quick-view: TEXTO/LINK (`botao botao-texto qv-close`), alvo de 34 px */
.botao.qv-close { position: absolute; top: 12px; right: 12px; width: 34px; height: 34px; padding: 0; justify-content: center; }
.qv-close svg { width: 18px; height: 18px; stroke: currentColor; stroke-width: 2; fill: none; stroke-linecap: round; }
.qv-head { padding-right: 34px; margin-bottom: 6px; }
.qv-head .status-pill { margin-bottom: 10px; }
.qv-title { margin: 0; font-size: 1.15rem; font-weight: 700; color: var(--navy); line-height: 1.3; }
.qv-title small { color: var(--cinza); font-weight: 500; }
.qv-meta { color: var(--cinza); font-size: 0.86rem; margin-top: 4px; }
.qv-body .card-rfp-kpis { margin-top: 14px; }

/* Quick-view completo: stat grid + subtotais + esclarecimentos */
.qv-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 16px; }
.qv-stat { background: var(--superficie-2); border: 1px solid var(--line); border-radius: var(--raio-reto); padding: 10px 12px; display: flex; flex-direction: column; gap: 3px; }
.qv-lab { font-size: 0.68rem; text-transform: uppercase; letter-spacing: .03em; color: var(--faint); font-weight: 600; }
.qv-val { font-size: 0.95rem; font-weight: 700; color: var(--navy); font-variant-numeric: tabular-nums; }
.qv-val small { color: var(--cinza); font-weight: 500; font-size: 0.78rem; }
.qv-stat .kpi-barra { margin-top: 4px; }
.qv-sec { margin-top: 16px; }
.qv-sec-tit { font-size: 0.75rem; text-transform: uppercase; letter-spacing: .03em; color: var(--faint); font-weight: 700; margin-bottom: 8px; }
.qv-blocos { display: flex; flex-direction: column; }
.qv-bloco-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 7px 2px; border-bottom: 1px solid var(--line2); font-size: 0.87rem; }
.qv-bloco-row:last-child { border-bottom: none; }
.qv-bl-nome { color: var(--ink); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.qv-bl-val { font-weight: 700; color: var(--navy); font-variant-numeric: tabular-nums; white-space: nowrap; }
.qv-esc { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.qv-esc li { font-size: 0.85rem; color: var(--ink); display: flex; gap: 6px; align-items: baseline; }
.qv-esc b { color: var(--azul-escuro); font-weight: 700; }
.qv-esc-st { margin-left: auto; font-size: 0.68rem; font-weight: 700; text-transform: uppercase; border-radius: var(--raio-pilula); padding: 1px 8px; flex: none; }
.qv-esc-st.aberta { background: var(--alerta-bg); color: var(--alerta-fg); }
.qv-esc-st.respondida { background: var(--ok-bg); color: var(--ok); }
.qv-esc-mais { color: var(--cinza); font-size: 0.8rem; }
.qv-vazio { color: var(--cinza); font-size: 0.9rem; margin-top: 14px; }
.qv-actions { margin-top: 18px; display: flex; flex-wrap: wrap; gap: 10px; }

@media (max-width: 900px) {
  .kanban { flex-direction: column; overflow-x: visible; }
  .kanban-col { flex: 1 1 auto; width: 100%; }
}

/* ===== Redesign v4 — shell de app (sidebar) e shell público ===== */
.app { display: flex; min-height: 100vh; align-items: stretch; }
/* largura única da lateral: a barra fixa do total se apoia nela (não pode
   tapar o "Sair"), então os dois valores precisam sair do mesmo lugar */
:root {
  --side-w: 236px;
  /* Larguras do shell com barra lateral. Sao DUAS, de proposito:
     - `--larg-trabalho`: toda tela de trabalho do admin (painel, quadro geral,
       processo, comparativo, analise, comercial, saneamento, vista integral).
       Valor vem do tamanho natural das colunas do quadro, que e o conteudo
       mais largo do portal.
     - `--larg-leitura`: telas de texto corrido, onde linha longa PIORA a
       leitura (escopo, formularios simples).
     Nao criar uma terceira. Foi a proliferacao de tetos (1720/1980/2150) que
     deixou o Painel largo e a tela do projeto encolhida -- apontamento do PO
     na validacao da Fase 15. */
  --larg-trabalho: 2150px;
  --larg-leitura: 1180px;
}
html.side-collapsed { --side-w: 66px; }
/* A ESTRUTURA em navy: dentro do menu os tokens por tema voltam ao tema
   ESCURO do sistema (como o `.side` do Propostas), e o foco é `org`. */
.side {
  --fundo: var(--navy); --fundo-suave: var(--capa-topo); --texto: var(--branco);
  --texto-apoio: var(--nevoa); --titulo: var(--branco); --subtitulo: var(--capa-texto);
  --fio: var(--capa-fio); --foco: var(--org);
}
.side { width: var(--side-w); flex: none; background: var(--moldura); color: var(--texto-sobre-moldura); display: flex; flex-direction: column; padding: 16px 12px; position: sticky; top: 0; height: 100vh; overflow-y: auto; }
.side-brand { display: block; padding: 8px 8px 18px; }
.side-brand img { display: block; height: 38px; width: auto; }
/* rótulo de seção: o `rotulo` do sistema (caixa alta, espaçamento largo, 600)
   em `nevoa` (8,0:1) */
.side .navlab { font-size: var(--t-rotulo); text-transform: uppercase; letter-spacing: 1.6px; color: var(--texto-apoio); padding: 14px 10px 6px; font-weight: 600; }
.side-nav { display: flex; flex-direction: column; gap: 2px; }
/* O item: `capa-texto` (11,2:1), sem caixa; o hover é o `fundo-suave` do
   escuro. O ATIVO (como no Propostas): fundo e fio (`capa-topo` e
   `capa-fio`), branco 600, e o MARCADOR QUADRADO de 6 px em `org` — o
   "quadrado de 1,6 mm" das listas do sistema. Nada de degradê nem de barra
   arredondada. Os ícones continuam (o Propostas os mantém), traço fino. */
.side-nav a { position: relative; display: flex; align-items: center; gap: 11px; padding: 9px 11px 9px 24px; border: var(--traco-fio) solid transparent; color: var(--subtitulo); text-decoration: none; font-weight: 500; font-size: .95rem; transition: background-color .13s, color .13s; }
.side-nav a:hover { background: var(--fundo-suave); color: var(--texto); }
.side-nav a.on { background: var(--fundo-suave); border-color: var(--fio); color: var(--texto); font-weight: 600; }
.side-nav a.on::before { content: ""; position: absolute; left: 9px; top: 50%; width: 6px; height: 6px; margin-top: -3px; background: var(--org); }
.side-nav a.on .ic { color: var(--org); }
.side .ic { width: 18px; height: 18px; stroke: currentColor; stroke-width: 1.9; fill: none; stroke-linecap: round; stroke-linejoin: round; flex: none; }
/* Menu de conta (Fase 8): gatilho no rodapé + dropdown que abre para cima */
.side-account { margin-top: auto; position: relative; }
.su-trigger { width: 100%; display: flex; align-items: center; gap: 10px; padding: 9px;
  border: var(--traco-fio) solid var(--fio); background: transparent; color: inherit;
  cursor: pointer; font: inherit; text-align: left; }
.su-trigger:hover { background: var(--fundo-suave); }
.side-account.on .su-trigger { background: var(--fundo-suave); }
.side-avatar { width: 32px; height: 32px; border-radius: var(--raio-reto); background: var(--azul-sup); display: grid; place-items: center; color: var(--texto-inv); font-weight: 700; font-size: .8rem; flex: none; }
.su-info { min-width: 0; flex: 1; }
.su-nm { font-size: .82rem; color: var(--texto-inv); font-weight: 600; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.su-rl { font-size: .69rem; color: var(--texto-sobre-moldura); }
.su-chev { width: 16px; height: 16px; flex: none; stroke: var(--nevoa); stroke-width: 2; fill: none;
  stroke-linecap: round; stroke-linejoin: round; transition: transform .15s; }
.su-trigger[aria-expanded="true"] .su-chev { transform: rotate(180deg); }
.su-menu { position: absolute; left: 0; right: 0; bottom: calc(100% + 6px);
  background: var(--capa-topo); border: 1px solid var(--capa-fio);
  padding: 5px; z-index: 20; }
/* ⚠️ O "Sair" é um SUBMIT (formulário POST) e cairia na regra do botão
   principal — canto e sombra. Ele é item do MENU LATERAL, que continua reto e
   sem sombra (emenda de 26/10): canto, sombra e altura voltam aqui, nos três
   estados em que a regra do botão os põe. */
.su-menu a, .su-menu button { width: 100%; display: flex; align-items: center; gap: 9px;
  padding: 8px 10px; border: 0; background: transparent;
  color: var(--capa-texto); font: inherit; font-size: .85rem; text-decoration: none; cursor: pointer; text-align: left;
  border-radius: var(--raio-reto); box-shadow: none; min-height: 0; }
.su-menu a:hover, .su-menu button:hover { background: var(--navy); color: var(--texto-inv); box-shadow: none; }
.su-menu button:active { box-shadow: none; }
.su-menu svg { width: 16px; height: 16px; flex: none; stroke: currentColor; stroke-width: 1.9;
  fill: none; stroke-linecap: round; stroke-linejoin: round; }
.su-menu form { margin: 4px 0 0; padding-top: 4px; border-top: 1px solid var(--capa-fio); }
/* O menu da conta do BM só tem o "Sair" (`bm/_menu.html`): sem item acima, o
   fio que separa o Sair dos outros ficaria solto no alto do menu. */
.su-menu form:first-child { margin-top: 0; padding-top: 0; border-top: 0; }

/* REGRA UNIVERSAL (PO): em qualquer tela logada, o conteúdo fica num painel
   claro CENTRADO; o que sobrar dos lados em telas largas preenche com o navy
   da barra — moldura simétrica, para nenhum perfil ver conteúdo "encostado". */
.main { flex: 1; min-width: 0; display: flex; flex-direction: column; overflow-x: clip; background: var(--moldura); }
.topbar { height: 56px; display: flex; align-items: center; gap: 12px; padding: 0 20px; border-bottom: 1px solid var(--line); background: var(--fundo); position: sticky; top: 0; z-index: 20; }
/* No desktop a topbar fica vazia (marca/nav na sidebar) — esconde a faixa branca */
@media (min-width: 901px) { .topbar { display: none; } }
.side-toggle { display: none; background: var(--superficie); border: 1px solid var(--line); border-radius: var(--raio-reto); width: 38px; height: 38px; place-items: center; cursor: pointer; color: var(--cinza); }
.side-toggle:hover { color: var(--azul); border-color: var(--borda); }
.side-toggle .ic { width: 20px; height: 20px; stroke: currentColor; stroke-width: 2; fill: none; stroke-linecap: round; }
.tb-logo { display: none; }
.tb-logo img { display: block; }

/* Topo da barra: logo (completo/símbolo) + seta de recolher */
.side-top { display: flex; align-items: center; justify-content: space-between; gap: 6px; padding: 2px 4px 12px; }
.side-brand { display: flex; align-items: center; }
.side-brand .brand-full { display: block; height: 34px; width: auto; }
.side-brand .brand-mark { display: none; width: 30px; height: 30px; }
.side-collapse { flex: none; width: 28px; height: 28px; display: grid; place-items: center; border: var(--traco-fio) solid var(--capa-fio); background: transparent; color: var(--texto-sobre-moldura); cursor: pointer; }
.side-collapse:hover { background: var(--capa-topo); color: var(--texto-inv); }
.side-collapse .chev { width: 18px; height: 18px; stroke: currentColor; stroke-width: 2; fill: none; stroke-linecap: round; stroke-linejoin: round; transition: transform .15s; }

/* Desktop: rail recolhido (só símbolo do logo + ícones) — estilo Trello */
@media (min-width: 901px) {
  html.side-collapsed .side { padding: 16px 10px; }  /* largura vem de --side-w */
  html.side-collapsed .side-top { flex-direction: column; gap: 10px; padding: 2px 0 12px; }
  html.side-collapsed .brand-full { display: none; }
  html.side-collapsed .brand-mark { display: block; }
  html.side-collapsed .side-collapse .chev { transform: rotate(180deg); }
  html.side-collapsed .navlab { display: none; }
  html.side-collapsed .side-nav a { justify-content: center; gap: 0; padding: 9px; }
  /* no trilho de 66 px o marcador do ativo encosta na borda, sem tocar o ícone */
  html.side-collapsed .side-nav a.on::before { left: 3px; }
  html.side-collapsed .side-nav .lbl,
  html.side-collapsed .side-nav .badge { display: none; }
  html.side-collapsed .su-trigger { justify-content: center; padding: 8px 0; }
  html.side-collapsed .su-info, html.side-collapsed .su-chev { display: none; }
  /* recolhido: o menu estoura a largura do rail e o overflow da barra o
     CORTAVA (aparecia "por baixo" do navy — PO, 07/08). position:fixed escapa
     do clip: o containing block passa a ser a viewport. */
  html.side-collapsed .su-menu { position: fixed; left: 10px; right: auto; bottom: 70px; min-width: 190px; }
  /* rail e moldura são o mesmo navy; sem um traço, recolhido "parece que a
     barra continua lá" (PO, 07/08) */
  html.side-collapsed .side { border-right: 1px solid var(--capa-fio); }
/* PO 08/08: no escuro o rail se confundia com o painel — a separação
   passa a existir sempre, não só com a barra recolhida. */
.side { border-right: 1px solid var(--capa-fio); }

  /* A barra fixa do total do escopo é `left: 0` e atravessava por cima da
     barra lateral, tapando o bloco do usuário e o "Sair". No desktop ela
     começa depois da lateral; no mobile a lateral é gaveta, então segue 0. */
  body.has-side .rodape-total { left: var(--side-w); }
}

body.has-side main.conteudo { max-width: var(--larg-leitura); margin: 0 auto;
  padding: 26px 30px; width: 100%; background: var(--fundo); flex: 1 0 auto; }
/* ⚠️ UMA largura para TODA tela de trabalho do admin (PO, validação da 15:
   "padronize todas as telas para mesma largura").

   Aqui havia QUATRO tetos, cada um nascido de um pedido diferente e todos
   certos isoladamente: `largo` 1720, `comparativo` 1980 (a tabela cabia sem
   rolar), `board` 2150 (tamanho natural das colunas). O efeito somado era o
   que ele viu: o Painel largo e a tela do projeto encolhida, com margens
   enormes dos lados — e eu vinha corrigindo caso a caso, o que só trocava
   qual par ficava desalinhado.

   Agora é um token só. Mexer nele move todas as telas juntas; acrescentar um
   quinto teto para uma tela específica é reabrir exatamente este defeito. */
body.has-side main.conteudo.largo,
body.has-side main.conteudo.comparativo,
body.has-side main.conteudo.board { max-width: var(--larg-trabalho); padding: 22px 22px; }
/* Recolher a barra tem de DAR espaço (PO, 07/08): o painel claro absorve a
   largura liberada (236−66px) em vez de só engordar a moldura navy. Vale para
   a tela de LEITURA; as de trabalho já usam o teto único, que não muda. */
html.side-collapsed body.has-side main.conteudo { max-width: 1350px; }
html.side-collapsed body.has-side main.conteudo.largo,
html.side-collapsed body.has-side main.conteudo.comparativo,
html.side-collapsed body.has-side main.conteudo.board { max-width: var(--larg-trabalho); }

/* Scrollbars finas e modernas (estilo Trello) */
* { scrollbar-width: thin; scrollbar-color: var(--nevoa) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--nevoa); border: 2px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-thumb:hover { background: var(--controle-borda); }
/* Barra escura dentro da sidebar navy */
.side::-webkit-scrollbar-thumb { background: var(--capa-fio); }
/* o rodapé fica sobre a MOLDURA navy: `nevoa` (8,0:1) e `capa-texto` (11,2:1) */
body.has-side footer.rodape { padding: 14px 30px 20px; margin-top: 0; color: var(--nevoa); }
body.has-side footer.rodape .acesso-info { color: var(--capa-texto); }
.side-bd { display: none; }

@media (max-width: 900px) {
  .side { position: fixed; left: 0; top: 0; z-index: 60; transform: translateX(-100%); transition: transform .2s; }
  body.side-open .side { transform: translateX(0); }
  .side-bd { display: block; position: fixed; inset: 0; background: var(--veu-modal); z-index: 50; opacity: 0; visibility: hidden; transition: opacity .2s; }
  body.side-open .side-bd { opacity: 1; visibility: visible; }
  .side-toggle { display: grid; }
  .side-collapse { display: none; }  /* rail é só desktop */
  /* Drawer: 100dvh (nao 100vh) para o rodape com o Sair ficar visivel sem rolar */
  .side { width: 250px; height: 100dvh; padding-bottom: 22px; }
  .tb-logo { display: block; }
  body.has-side main.conteudo { padding: 18px 16px; }
  /* No mobile a topbar vira barra escura (navy), como a sidebar — o logo branco aparece */
  .topbar { --foco: var(--org); background: var(--navy); border-bottom: none; }
  .side-toggle { background: transparent; border-color: var(--capa-fio); color: var(--texto-inv); }
  .side-toggle:hover { background: var(--capa-topo); color: var(--texto-inv); }
}

/* Shell público (login, senha, convite, bloqueado) */
.public { min-height: 100vh; display: flex; flex-direction: column; }
.public-top { display: flex; align-items: center; justify-content: center; padding: 34px 20px 4px; }
/* logotipo real da marca: colorido no claro, branco no escuro (auth-dark) */
.pt-marca { height: 46px; width: auto; display: block; }
.pt-marca-branca { display: none; }
body.auth-dark .pt-marca-cor { display: none; }
body.auth-dark .pt-marca-branca { display: block; }
body.is-public main.conteudo { flex: 1; max-width: 620px; margin: 0 auto; padding: 14px 20px 40px; width: 100%; }
body.is-public footer.rodape { margin: 8px 0 20px; }

/* ===== Fase 5 — marca d'água forense (§12) ===== */
.marca-dagua { position: absolute; inset: 0; z-index: 9000; pointer-events: none; overflow: hidden;
  transform: rotate(-42deg); transform-origin: center; opacity: 0.05; }
.marca-dagua .mw-row { white-space: nowrap; line-height: 3.6; }
/* padrão "tijolo": linhas pares começam ~meia frase deslocadas (menos repetitivo) */
.marca-dagua .mw-row:nth-child(even) { margin-left: -17em; }
.marca-dagua .mw-t { color: var(--marca-dagua); font-size: 12.5px; font-weight: 600; padding: 0 44px; letter-spacing: .02em; user-select: none; }
@media print {
  .marca-dagua { opacity: 0.22; position: fixed; }
}

/* ===== Fase 5 — atrito de cópia (§12 medida 4) ===== */
main.conteudo.confidencial, .escopo { -webkit-user-select: none; user-select: none; }
/* campos do fornecedor seguem livres */
main.conteudo.confidencial input, main.conteudo.confidencial textarea,
main.conteudo.confidencial [contenteditable="true"],
.escopo input, .escopo textarea { -webkit-user-select: text; user-select: text; }

.print-aviso { display: none; }
@media print {
  .side, .topbar, footer.rodape { display: none !important; }
  main.conteudo.confidencial > *:not(.marca-dagua):not(.print-aviso) { display: none !important; }
  .print-aviso { display: block !important; text-align: center; padding: 26vh 24px 0; color: var(--texto-2); }
  .print-aviso strong { font-size: 1.25rem; }
  .print-aviso p { margin-top: 12px; color: var(--texto-2); }
  .print-aviso .pa-id { color: var(--texto-2); margin-top: 20px; font-size: .9rem; }
  .marca-dagua { display: flex !important; opacity: 0.22; }
}

/* ===== §12 medida 3 — atividade de leitura do escopo (painel) ===== */
.leituras { display: flex; flex-direction: column; gap: 12px; }
.leitura-card { border: 1px solid var(--borda); border-radius: var(--raio-cartao); padding: var(--sp-4) var(--sp-4); }
/* destaque, NÃO veredito: chama o olho sem rotular de "suspeito" */
.leitura-card.atipico { border-color: var(--alerta-borda); background: var(--alerta-bg); }
.lc-cab { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.lc-emp { font-weight: 700; color: var(--navy); }
.lc-tag { font-size: .7rem; font-weight: 700; text-transform: uppercase; border-radius: var(--raio-pilula);
  letter-spacing: .04em; color: var(--alerta-fg); background: var(--fundo); border: var(--traco-fio) solid var(--org); padding: 3px 9px; }
.lc-nums { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 8px; margin-bottom: 12px; }
/* cada métrica é um bloco fechado: sem isso viram uma tira de textos soltos
   quando a grade colapsa numa coluna só (celular) */
.lc-nums > div { display: flex; flex-direction: column; justify-content: center;
  background: var(--superficie-2); border-radius: var(--raio-reto); padding: 9px 11px; min-height: 58px; }
.leitura-card.atipico .lc-nums > div { background: var(--fundo); }
.lc-nums b { font-size: 1.15rem; color: var(--navy); line-height: 1.2; }
.lc-nums span { font-size: .74rem; color: var(--cinza); line-height: 1.3; }
.lc-nums small { display: block; color: var(--texto-2); }
.lc-quem { width: 100%; border-collapse: collapse; font-size: .82rem; }
.lc-quem th { text-align: left; font-size: .7rem; text-transform: uppercase;
  letter-spacing: .04em; color: var(--cinza); border-bottom: 1px solid var(--line); padding: 5px 6px; }
.lc-quem td { padding: 6px; border-bottom: 1px solid var(--borda); vertical-align: top; }
.lc-quem small { display: block; color: var(--cinza); }
.lc-ips .ip { display: inline-block; font-family: var(--font-mono); font-size: .76rem;
  background: var(--superficie-2); border-radius: var(--raio-pilula); padding: 2px 7px; margin: 0 4px 4px 0; }
.lc-ips .ip i { color: var(--cinza); font-style: normal; }
@media (max-width: 640px) {
  /* 2 colunas fixas: o auto-fit colapsa para 1 no celular e vira uma tira
     vertical de 6 blocos. A janela de datas é larga e ocupa a linha toda. */
  .lc-nums { grid-template-columns: 1fr 1fr; }
  .lc-nums .lc-janela { grid-column: 1 / -1; }

  .lc-quem, .lc-quem tbody, .lc-quem tr, .lc-quem td { display: block; }
  .lc-quem thead { display: none; }
  .lc-quem tr { padding: 10px 0; border-bottom: 1px solid var(--line); }
  .lc-quem tr:last-child { border-bottom: 0; }
  .lc-quem td { border: 0; padding: 3px 0; }
  /* o cabeçalho some no celular: sem este rótulo o número fica órfão */
  .lc-quem td[data-rot]::before { content: attr(data-rot); display: block;
    font-size: .66rem; text-transform: uppercase; letter-spacing: .05em;
    color: var(--cinza); margin-top: 6px; }
}
.lc-quem .lc-falha { color: var(--erro-fg); font-weight: 600; }

/* ===== Painel — registros (espelho do log, decisão do PO) ===== */
.log-abas { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 14px; }
.log-abas a { display: flex; align-items: center; gap: 7px; padding: 8px 14px;
  border: 1px solid var(--line); border-radius: var(--raio-controle); background: var(--superficie);
  color: var(--navy); text-decoration: none; font-weight: 600; font-size: .84rem; }
.log-abas a span { font-size: .72rem; color: var(--cinza); background: var(--superficie-2);
  border-radius: var(--raio-pilula); padding: 1px 8px; }
.log-abas a.on { background: var(--navy); color: var(--texto-inv); border-color: var(--navy); }
.log-abas a.on span { background: var(--capa-topo); color: var(--texto-inv); }
.log-filtros { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px;
  background: var(--superficie); border: 1px solid var(--line); border-radius: var(--raio-cartao);
  padding: 12px 14px; margin-bottom: 14px; }
/* margin-bottom: 0 anula a regra global `form label` (0.3rem): ela empurrava
   a caixa do rotulo para cima e o botao Filtrar ficava ~5px mais baixo. */
.log-filtros label { margin-bottom: 0; display: flex; flex-direction: column; gap: 4px;
  font-size: .7rem; text-transform: uppercase; letter-spacing: .04em; color: var(--cinza); }
.log-filtros input, .log-filtros select { border: 1px solid var(--line-in);
  border-radius: var(--raio-controle); padding: .45rem .6rem; font: inherit; font-size: .85rem; }
/* Filtrar + Limpar como um par: o align-self:center do Limpar o fazia
   flutuar acima do botao (o bloco de filtros e mais alto que ele). */
.log-acoes { display: flex; align-items: center; gap: 14px; }
.log-tab { width: 100%; border-collapse: collapse; font-size: .82rem; }
/* cabeçalho do sistema: branco 600 sobre navy, filete `org` na primeira */
.log-tab th { text-align: left; padding: 9px 10px; color: var(--texto-inv); background: var(--navy);
  font-size: .78rem; font-weight: 600; letter-spacing: .02em;
  border-bottom: var(--traco-fio) solid var(--navy); white-space: nowrap; }
.log-tab th:first-child { border-left: var(--traco-acento) solid var(--org); }
.log-tab tbody tr:nth-child(even) td { background: var(--zebra); }
.log-tab td { text-align: left; vertical-align: top; padding: 9px 10px;
  border-bottom: 1px solid var(--line2); }
.log-ts, .log-ip, .log-ua { font-family: var(--font-mono); font-size: .76rem; white-space: nowrap; }
.log-ua { color: var(--cinza); white-space: normal; }
.log-obj { color: var(--texto-2); }
.log-acao { background: var(--info-bg); color: var(--info-fg); border-radius: var(--raio-pilula);
  padding: 2px 8px; font-size: .74rem; font-weight: 600; white-space: nowrap; }
.log-aberta { color: var(--alerta-fg); font-size: .76rem; }
.log-bloqueio { background: var(--erro-bg); }
.log-tab small { display: block; color: var(--cinza); font-size: .72rem; }
.log-pag { display: flex; align-items: center; justify-content: center; gap: 14px;
  margin-top: 12px; font-size: .82rem; color: var(--cinza); }
@media (max-width: 640px) { .log-filtros label { flex: 1 1 100%; } }

/* ===== Fase 6 — quadro do contratante (reusa .kanban/.card-rfp) ===== */
/* o card virou <a>: precisa anular a decoração de link herdada */
/* REGRESSAO da 15.6, apontada pelo PO na validacao: esta regra estava presa a
   `.kanban`. Quando a capa deixou de ser quadro, os cards da home sairam do
   escopo e voltaram ao estilo de LINK CRU — titulo, datas e contratante todos
   sublinhados e azuis. O card e um <a> inteiro; o sublinhado pertence ao texto
   que se le, nao ao bloco que se clica. Vale para qualquer card-link. */
.card-rfp[href] { display: block; text-decoration: none; color: inherit; }
.cli-kpis { display: flex; gap: 16px; margin-top: 10px; flex-wrap: wrap; }
.cli-kpis > div { display: flex; flex-direction: column; min-width: 0; }
.cli-kpis b { font-size: 1.02rem; color: var(--navy); line-height: 1.2; }
.cli-kpis span { font-size: .71rem; color: var(--cinza); }
.cli-vencedora { margin-top: 9px; background: var(--ok-bg); color: var(--ok-fg); font-size: .78rem;
  font-weight: 600; border-radius: var(--raio-cartao); padding: 5px 9px; }
.cli-rfp-nome { margin-top: 9px; font-size: .78rem; color: var(--cinza); }
.cli-rfp-nome small { color: var(--texto-2); }

/* ===== Fase 9 — Kanban do painel (reusa .kanban/.card-rfp) ===== */
/* A regra `.kanban-painel .kanban-col:nth-child(4)` (bolinha neutra na 4a
   coluna) MORREU na 15.6: a capa deixou de ser quadro e ninguem mais emite a
   classe `kanban-painel`. Removida na 15.8. Vale o registro do que ela
   ensinava: aquele override existia porque a 4a posicao herda `--laranja` da
   regra global, e o laranja e a cor de menor contraste da paleta no tema
   claro (2,57 sobre o fundo da coluna). */
/* O layout 100vh do board (media 901+) espreme flex-children sem flex:none —
   a barra de filtros não pode ser esmagada quando a altura aperta. */
.board > .painel-filtros { flex: none; }
/* Fase 15.7 — as duas VISOES IRMAS (home: natureza x quadro geral; certame:
   processo x comparativo). Servem as QUATRO telas.

   ⚠️ Eram abas de texto: cinza, sem fundo, sem borda, e so a ativa ganhava um
   risquinho de 2px embaixo. O PO (17/08): *"estes dois botoes ficam muito
   escondidos, quase nao da pra ver que existem essas duas opcoes de
   visualizacao"*. O defeito nao era contraste do texto — era AFFORDANCE:
   nada ali dizia "isto e clicavel e tem outro lado".

   Virou CONTROLE SEGMENTADO: caixa com borda visivel envolvendo os dois, e o
   lado ativo com fundo cheio. Le como chave de duas posicoes de longe, que e
   o que faltava.

   O fundo cheio usa `--azul-sup` com `--texto-inv`, o par ja usado pelo botao
   primario: e o unico azul da paleta medido nos DOIS temas (7,04 claro /
   5,45 escuro). `--azul` cru serviria no claro e afundaria no escuro, onde ele
   e #6FA8DC. */
/* ⚠️ `align-self` e `flex: none` NAO sao decoracao: o Quadro geral roda dentro
   de `.board`, que e um flex em coluna. Filho de flex e BLOCKIFICADO — o
   `inline-flex` vira `flex` e a caixa estica na largura toda (medido: 1000px),
   que e o oposto de um controle segmentado. Sem isto, a mesma regra da dois
   desenhos diferentes nas duas telas irmas. */
.visoes-irmas { display: inline-flex; align-self: flex-start; flex: none;
                gap: 3px; margin: 0 0 18px; padding: 3px;
                background: var(--superficie); border: 1px solid var(--borda);
                border-radius: var(--raio-controle); }
.visoes-irmas a { display: block; padding: 7px 15px 8px; text-decoration: none;
                  color: var(--texto-2); font-weight: 700; font-size: .88rem;
                  border-radius: var(--raio-controle); transition: background .15s, color .15s; }
.visoes-irmas a span { display: block; font-weight: 500; font-size: .73rem; color: var(--texto-3); margin-top: 1px; }
.visoes-irmas a:hover { color: var(--azul-escuro); background: var(--fundo); }
/* Depois do :hover de proposito — passar o mouse no lado ativo nao pode
   apaga-lo, que era o efeito de deixar o hover ganhar por ordem. */
.visoes-irmas a.ativa, .visoes-irmas a.ativa:hover { background: var(--azul-sup); color: var(--texto-inv); }
.visoes-irmas a.ativa span { color: var(--texto-inv); }
@media (max-width: 600px) {
  .visoes-irmas { display: flex; }         /* ocupa a linha; dois lados iguais */
  .visoes-irmas a { flex: 1 1 0; text-align: center; }
  .visoes-irmas a span { display: none; }  /* no celular so o rotulo cabe */
}
/* Fase 15.6 — home agrupada por NATUREZA (substitui o Kanban da capa).
   Grade fluida: os cards do painel tem largura minima confortavel e o numero
   de colunas cai sozinho conforme a tela, sem media query. */
.grupos-natureza { display: flex; flex-direction: column; gap: 26px; }
.grupo-nat-cab { display: flex; align-items: center; gap: 10px; margin-bottom: 11px;
                 padding-bottom: 7px; border-bottom: 1px solid var(--borda); }
.grupo-nat-cab h2 { font-size: 1.05rem; font-weight: 700; color: var(--azul-escuro); margin: 0; padding: 0; border-bottom: 0; }
.grupo-nat-conta { background: var(--superficie); color: var(--cinza); font-size: .72rem;
                   font-weight: 700; border-radius: var(--raio-pilula); padding: 1px 9px; border: 1px solid var(--line); }
.grupo-nat-corpo { display: grid; grid-template-columns: repeat(auto-fill, minmax(310px, 1fr)); gap: 12px; }
/* Linha de destaque da capa: o numero que o PO procura ao abrir a tela. */
.painel-aguarda { margin: -4px 0 16px; font-size: .86rem; color: var(--texto); }
.painel-aguarda b { color: var(--alerta-fg); font-size: 1.05rem; }
.painel-aguarda span { color: var(--cinza); font-size: .78rem; }
/* Resumo do processo no card: UM chip por etapa, e a etapa que espera pela
   Alcance diz isso dentro do proprio chip. Havia aqui um chip separado de
   "aguardando voce", que com a analise tecnica vazia repetia o numero da etapa
   ao lado — dois alertas para um motivo so (PO, validacao da 15). */
.cardp-etapas { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.cardp-etapa { background: var(--superficie); color: var(--texto); border: 1px solid var(--line);
               border-radius: var(--raio-pilula); padding: 1px 9px; font-size: .7rem; font-weight: 700; }
.cardp-etapa span { color: var(--cinza); font-weight: 600; }
/* ⚠️ Seletor DUPLO de proposito: as duas classes convivem no mesmo chip agora,
   e `.cardp-aguarda` sozinho tem a mesma especificidade de `.cardp-etapa` —
   perderia por vir antes na folha. O mesmo vale para o `span` interno, que
   herdaria o cinza da regra acima e apagaria o destaque. */
.cardp-etapa.cardp-aguarda { background: var(--alerta-bg); color: var(--alerta-fg);
                             border-color: var(--alerta-borda); }
.cardp-etapa.cardp-aguarda span { color: var(--alerta-fg); }
.cardp-datas { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-top: 10px; }
.cardp-datas span { display: block; font-size: .66rem; color: var(--cinza); text-transform: uppercase; letter-spacing: .04em; }
.cardp-datas b { font-size: .82rem; color: var(--navy); }
.cardp-props { margin-top: 9px; font-size: .78rem; color: var(--cinza); }
.cardp-props b { color: var(--navy); }
/* Reenvio no card da capa: chamada discreta, mas que se enxerga varrendo o
   quadro (pedido do PO — nao pode depender de memoria). */
.cardp-reenvio { margin-top: 7px; display: inline-block; font-size: .72rem; font-weight: 700;
  border-radius: var(--raio-pilula); padding: 2px 10px; background: var(--alerta-bg); color: var(--alerta-fg);
  border: 1px solid var(--alerta-borda); }

/* Fase 9 — vista integral da proposta (admin, somente leitura) */
/* A TRILHA em caixa alta (CRM ASEC): a do painel da proposta e a do BM. */
.pp-trilha { font-size: 11px; letter-spacing: 1px; text-transform: uppercase; font-weight: 600; color: var(--cinza); margin-bottom: 8px; }
.pp-trilha a { color: var(--azul); text-decoration: none; }
.pp-trilha a:hover { text-decoration: underline; }
.pp-cab { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
.pp-stats { display: flex; gap: 26px; flex-wrap: wrap; }
.pp-stats span { display: block; font-size: .68rem; color: var(--cinza); text-transform: uppercase; letter-spacing: .04em; }
.pp-stats b { font-size: .95rem; color: var(--navy); }
.pp-flag { flex-basis: 100%; background: var(--flag-r-bg); color: var(--erro-fg); border-radius: var(--raio-cartao); padding: 8px 12px; font-size: .85rem; font-weight: 600; }
.linha-tempo { list-style: none; margin: 0; padding: 0; }
.linha-tempo li { display: flex; gap: 14px; padding: 6px 0; border-bottom: 1px solid var(--borda); font-size: .88rem; }
.linha-tempo li:last-child { border-bottom: 0; }
.linha-tempo b { flex: 0 0 130px; color: var(--navy); font-variant-numeric: tabular-nums; }
/* Cabecalho do escopo na vista integral, com o recolher/expandir tudo */
.pp-escopo-cab { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; margin-top: var(--sp-5); }
.pp-escopo-cab h2 { margin: 0; font-size: 1.02rem; color: var(--azul-escuro); }
.pp-bloco { margin-top: var(--sp-5); }
.pp-bloco-cab { font-size: 1.02rem; color: var(--azul-escuro); margin-bottom: 8px; }
.pp-bloco-cab small { color: var(--cinza); font-weight: 400; }
.pp-secao { background: var(--superficie); border: 1px solid var(--borda); border-radius: var(--raio-cartao); margin-bottom: 10px; overflow: hidden; }
.pp-secao > summary { cursor: pointer; padding: 11px 16px; display: flex; justify-content: space-between; gap: 12px; align-items: baseline; }
.pp-secao > summary b { color: var(--azul-escuro); font-size: .92rem; }
.pp-secao > summary small { color: var(--cinza); white-space: nowrap; }
.pp-secao[open] > summary { border-bottom: 1px solid var(--borda); }
.pp-secao .itens { margin: 0; }
.pp-lista { display: flex; flex-direction: column; }
.pp-lista-linha { display: flex; align-items: center; gap: 14px; padding: 9px 0; border-bottom: 1px solid var(--borda); }
.pp-lista-linha:last-child { border-bottom: 0; }
.pp-lista-linha b { flex: 1; color: var(--navy); font-size: .92rem; }
.pp-lista-flag { background: var(--erro-bg); color: var(--erro-fg); font-size: .72rem; font-weight: 700; border-radius: var(--raio-pilula); padding: 2px 10px; }
/* Fase 14: selo contador — laranja quando nenhum desvio e de item essencial */
.pp-lista-flag.o { background: var(--alerta-bg); color: var(--alerta-fg); }
/* Contagem de envios na lista de propostas: com mais de um envio o selo
   destaca e vira link para a comparação dos dois últimos. */
.pp-lista-envios { font-size: .72rem; font-weight: 700; border-radius: var(--raio-pilula); padding: 2px 10px; background: var(--superficie-2); color: var(--texto-2); white-space: nowrap; }
.pp-lista-envios.destaque { background: var(--info-bg); color: var(--info-fg); border: 1px solid var(--info-borda); text-decoration: none; }
.pp-lista-envios.destaque:hover { text-decoration: underline; }

/* ===== Fase 10 — lançamentos datados (blocos fixos + edição versionada) ===== */
.lanc-bloco { margin-top: 8px; }
.lanc-bloco + .lanc-bloco { margin-top: 10px; }
.lanc-meta { display: flex; align-items: center; gap: 12px; margin-top: 4px; }
.lanc-quando { font-size: .72rem; color: var(--cinza); }
/* "Editar" e "Cancelar" do lançamento: TEXTO/LINK (`botao botao-texto
   lanc-editar`), na letra miúda da linha do carimbo */
.botao.lanc-editar, .botao.lanc-cancelar { padding: 0; font-size: .75rem; }
.lanc-edicao { margin-top: 6px; }
.lanc-novo { margin-top: 10px; }
.lanc-hist { margin-top: 6px; }
.lanc-hist > summary { cursor: pointer; font-size: .74rem; color: var(--cinza); font-weight: 600; }
.lanc-hist-item { margin-top: 6px; opacity: .75; }
/* vista integral: texto do fornecedor como REGISTRO fixo, não campo */
.obs-texto { margin-top: 8px; padding: 0.55rem 0.7rem; background: var(--superficie); border: 1px solid var(--borda); border-radius: var(--raio-controle); font-size: 0.88rem; line-height: 1.5; color: var(--navy); }
.obs-texto-vazia { color: var(--erro-fg); font-style: italic; }
.obs-quando { margin-top: 4px; font-size: 0.72rem; color: var(--cinza); }

/* ===== Fase 7 — aviso de certame encerrado ===== */
.encerrada-aviso { max-width: 620px; margin: 8vh auto 0; text-align: center; padding: 32px 28px; }
.encerrada-aviso .ea-ic { font-size: 2.2rem; line-height: 1; margin-bottom: 10px; }
.encerrada-aviso h1 { font-size: 1.35rem; margin: 0 0 14px; }
.encerrada-aviso p { color: var(--texto-2); font-size: .92rem; line-height: 1.55; margin: 0 0 12px; }
.encerrada-aviso .ea-ok { background: var(--ok-bg); color: var(--ok-fg); border-radius: var(--raio-cartao);
  padding: 11px 14px; margin: 18px 0 20px; }

/* ===== Fase 8 — saudação/contador da home (fornecedor e contratante) ===== */
.home-hero { margin-bottom: var(--sp-5); }
.home-hero h1 { margin: 0; font-size: var(--t-h1); }
.home-hero .home-sub { margin: 6px 0 0; color: var(--texto-2); font-size: .98rem; }
.home-hero .home-sub b { color: var(--texto); font-variant-numeric: tabular-nums; }

/* ===== A CAPA: as telas de entrada (`body.auth-dark`) =====
   O estilo de CAPA do Design System, como o Propostas fez no adendo de
   04/10/2026 (D-VIS-02): `/entrar/` e as telas de senha (esqueci, enviado,
   redefinir, redefinida) — exatamente as que já levavam `auth-dark`. As
   públicas claras (convite, primeiro acesso, bloqueado) NÃO mudam de lado.

   Do sistema: degradê de 145° de `capa-topo` a `deep`, brilho de
   `laranja-marca` com o teto `brilho-sol-max`, contraluz azulada, logotipo
   branco sem respiro, textos em branco, `capa-texto` e `nevoa`.
   ⚠️ ESCOLHA DO PO NO PROPOSTAS, reaproveitada e marcada como tal: o sol NO ALTO
   E AO CENTRO (no sistema ele fica no canto inferior direito), visível no teto
   de 16 %, e a contraluz pela METADE do teto (11 %). O botão Entrar é o
   primário `blu` (o PO escolheu o azul no Propostas).

   O escopo troca os TOKENS por tema para os do tema Escuro, como o `.side`.
   ⚠️ E redeclara os nomes da PONTE: custom property herda o valor JÁ
   RESOLVIDO onde foi declarada, então `--cinza: var(--texto-apoio)` resolvido
   no `:root` continuaria o cinza do papel aqui dentro. */
body.auth-dark {
  --fundo: var(--navy);
  --fundo-suave: var(--capa-topo);
  --texto: var(--branco);
  --texto-apoio: var(--nevoa);
  --titulo: var(--branco);
  --subtitulo: var(--capa-texto);
  --fio: var(--capa-fio);
  --foco: var(--org);                /* 5,5:1 sobre navy */
  --controle-borda: var(--nevoa);    /* borda de campo sobre navy: 8,0:1 */
  --texto-2: var(--nevoa);
  --texto-3: var(--nevoa);
  --faint: var(--nevoa);
  --cinza: var(--nevoa);
  --azul: var(--capa-texto);         /* link sobre navy: 11,2:1 (o `blu` dá 2,0) */
  --azul-escuro: var(--branco);
  --borda: var(--capa-fio);
  --line: var(--capa-fio);
  --line-in: var(--nevoa);
  --superficie: transparent;
  --erro: var(--erro-escuro);
  --erro-fg: var(--erro-escuro);
  --ok: var(--ok-escuro);
  color-scheme: dark;
  background:
    radial-gradient(ellipse 60rem 45rem at 50% 0%,
      color-mix(in srgb, var(--laranja-marca) calc(var(--brilho-sol-max) * 100%), transparent) 0%,
      color-mix(in srgb, var(--laranja-marca) calc(var(--brilho-sol-max) * 44%), transparent) 30%,
      transparent 62%),
    radial-gradient(circle 230mm at 0 0,
      color-mix(in srgb, var(--contraluz) calc(var(--contraluz-max) * 50%), transparent) 0%,
      transparent 58%),
    linear-gradient(145deg, var(--capa-topo) 0%, var(--deep) 100%);
  background-color: var(--deep);
}
/* PO 08/08: nas telas de acesso o rodapé ficava colado no fim da página,
   longe do conteúdo. A causa era o main esticar para preencher os 100vh
   (flex: 1 0 auto) e empurrar o rodapé; aqui ele fica com altura natural. */
body.auth-dark main.conteudo { flex: 0 0 auto; }
body.auth-dark footer.rodape { margin: 1.6rem 0 2.5rem; }
/* Conjunto logo+formulário CENTRADO na vertical (o bloco ficava pendurado no
   topo em telas altas): margin-top:auto no header + margin-bottom:auto no
   rodapé centram o grupo logo+form+rodapé. */
body.auth-dark .public-top { margin-top: auto; padding: 20px 20px 10px; }
body.auth-dark main.conteudo.public-main { flex: 0 0 auto; }
body.auth-dark footer.rodape { margin-bottom: auto; }
/* O logotipo se dimensiona pela LARGURA (pedido do PO). 324 px é o tamanho do
   DESENHO de antes: o arquivo antigo tinha respiro (360 px de caixa, 324 de
   desenho); o novo é recortado ao desenho. */
body.auth-dark .pt-marca { width: min(324px, 80vw); height: auto; }
body.auth-dark .auth-wrap { margin: 0 auto; }
body.auth-dark .auth-wrap h1 { color: var(--titulo); }
/* O cartão deixa de ser placa: a luz passa por trás do formulário, que flutua
   no fundo. Fica o filete `org` de acento no alto (o do Propostas). */
/* na capa o cartão é só o FILETE: reto, senão o filete se curva nas pontas */
body.auth-dark .auth-wrap .cartao { background: transparent; border: 0; border-top: var(--traco-acento) solid var(--org); border-radius: var(--raio-reto); padding: var(--sp-5) 0 0; }
body.auth-dark .auth-wrap p { color: var(--capa-texto); }
body.auth-dark .auth-wrap label { color: var(--nevoa); }
body.auth-dark .auth-wrap a { color: var(--capa-texto); }
body.auth-dark .auth-wrap a:hover { color: var(--branco); }
/* ⚠️ O "Entrar" de `senha_redefinida` é um `<a class="botao">`, e o link da
   capa (acima, 0,2,2) vencia a cor do botão (0,1,0): o texto saía
   `capa-texto` sobre o `blu`. O principal é branco (8,14:1). Achado na `024`. */
body.auth-dark .auth-wrap a.botao, body.auth-dark .auth-wrap a.botao:hover { color: var(--branco); }
/* NA CAPA o fundo é navy: o hover do sistema (navy) apagaria o botão no fundo.
   Ali o principal clareia para o `blu2` (branco 5,51:1), como já fazia. O
   "Entrar" é o principal `blu`, escolha do PO no Propostas, e fica. */
body.auth-dark .botao:hover:not(:disabled, [aria-disabled="true"], .bloqueado, .botao-desabilitado),
body.auth-dark button[type="submit"]:hover:not(:disabled, [aria-disabled="true"]) {
  background: var(--blu2); border-color: var(--blu2); }
body.auth-dark .auth-wrap .erros { color: var(--erro-escuro); }
body.auth-dark .auth-wrap .ok { color: var(--ok-escuro); }
body.auth-dark .auth-wrap input[type="text"],
body.auth-dark .auth-wrap input[type="email"],
body.auth-dark .auth-wrap input[type="password"] {
  background: transparent; border-color: var(--nevoa); color: var(--branco); }
body.auth-dark .auth-wrap input::placeholder { color: var(--nevoa); }
/* autofill do Chrome pinta amarelo — o preenchimento por dentro (inset) é o
   único jeito de devolver o fundo da capa; não é sombra de desenho. */
body.auth-dark .auth-wrap input:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 60px var(--capa-topo) inset; -webkit-text-fill-color: var(--branco); }
body.auth-dark footer.rodape, body.auth-dark footer.rodape .acesso-info { color: var(--nevoa); }

/* ===== Fase 12 — comparação entre envios (retrato congelado) ===== */
/* Cor SEMPRE por token: test_tokens_css reprova token usado sem declaração. */
.dif-seletor h2, .dif-cartao h2 { font-size: 1.02rem; color: var(--azul-escuro); margin: 0 0 10px; }
.dif-seletor h2 small, .dif-cartao h2 small { display: block; font-weight: 400; font-size: .76rem; color: var(--cinza); margin-top: 2px; }
.dif-seletor-campos { display: flex; gap: var(--sp-3); flex-wrap: wrap; align-items: flex-end; }
.dif-seletor-campos label { display: flex; flex-direction: column; gap: 4px; font-size: .72rem; color: var(--cinza); text-transform: uppercase; letter-spacing: .04em; }
.dif-seletor-campos select { min-width: 250px; }
.dif-aviso { background: var(--alerta-bg); color: var(--alerta-fg); border: 1px solid var(--alerta-borda); border-radius: var(--raio-cartao); padding: 10px 12px; font-size: .86rem; margin: 0; }
.dif-igual { color: var(--cinza); font-size: .88rem; margin: 0; }
.dif-contagem { display: flex; gap: 26px; flex-wrap: wrap; margin-bottom: var(--sp-3); }
.dif-contagem span { display: block; font-size: .68rem; color: var(--cinza); text-transform: uppercase; letter-spacing: .04em; }
.dif-contagem b { font-size: .95rem; color: var(--navy); }
.dif-sub { font-size: .92rem; color: var(--azul-escuro); margin: var(--sp-4) 0 8px; }
.dif-tabela td { vertical-align: top; }
/* De/Para campo por campo: o valor manda na leitura, o rotulo do campo apoia,
   e uma linha separa visualmente um item do proximo. */
.dif-campo { color: var(--cinza); font-size: .78rem; white-space: nowrap; }
.dif-valor { color: var(--navy); font-variant-numeric: tabular-nums; }
.dif-nota { color: var(--cinza); font-size: .7rem; }
.dif-tabela tr.dif-item-inicio > td { border-top: 1px solid var(--borda); }
.dif-tabela .cel-item b { color: var(--navy); }
.dif-tabela .cel-item small { display: block; color: var(--cinza); font-size: .76rem; line-height: 1.4; }
.dif-selo { display: inline-block; background: var(--info-bg); color: var(--info-fg); border: 1px solid var(--info-borda); border-radius: var(--raio-pilula); padding: 1px 9px; font-size: .7rem; font-weight: 700; margin: 1px 3px 1px 0; }
.dif-ausente { color: var(--cinza); font-style: italic; font-size: .8rem; }
.dif-atalho { color: var(--azul); font-size: .76rem; font-weight: 600; text-decoration: none; margin-left: 8px; white-space: nowrap; }
.dif-atalho:hover { text-decoration: underline; }
/* Marcador na própria linha do item (só com comparação ativa) */
.item-mudou > td { background: var(--info-bg); }
/* O marcador do diff mora na célula da DESCRIÇÃO, em linha própria acima do
   texto (era a do número, 52 px, e as etiquetas transbordavam por cima da
   descrição). Estado raro não paga coluna (regra 20). */
.dif-marca { margin-bottom: 6px; }
.dif-marca-antes { color: var(--cinza); font-size: .7rem; margin-top: 3px; line-height: 1.4; }
/* Rótulo de procedência do dado: "estado atual" x "como enviado" */
.fonte-dado { display: block; font-weight: 400; font-size: .76rem; color: var(--cinza); margin-top: 2px; }

/* ===== Fase 13 — janela de aprovacao tecnica (checklist do gate) ===== */
.check-lista { list-style: none; margin: 0 0 var(--sp-4); padding: 0; display: flex; flex-direction: column; gap: 10px; }
.check-item { display: flex; gap: 12px; align-items: flex-start; padding: 12px 14px; border-radius: var(--raio-cartao); border: 1px solid var(--borda); background: var(--superficie); }
.check-item.ok { background: var(--ok-bg); border-color: var(--ok-borda); }
.check-item.pendente { background: var(--alerta-bg); border-color: var(--alerta-borda); }
/* Nao atendida mas NAO bloqueante (proposta que ja seguiu): tom neutro, sem
   ambar de alerta -- senao a tela se contradiz com o aviso de que nada trava. */
.check-item.neutro { background: var(--superficie-2); border-color: var(--borda); }
.check-item.neutro .check-marca { color: var(--texto-2); border-color: var(--borda); }
/* Todas as etiquetas com a largura da MAIOR (PO, 14/08): sao tres — ATENDIDO,
   FALTA ATENDER e SEM REGISTRO —, e com largura livre cada uma empurrava o
   titulo da condicao para um ponto diferente, deixando a coluna de textos
   serrilhada. Com a largura fixada pela maior, os titulos alinham.
   `text-align: center` para o texto curto nao encostar a esquerda da pilula.
   ⚠️ Em PX, e nao em `ch`: com 13ch a maior etiqueta ("FALTA ATENDER", 13
   caracteres) media 114px e estourava os 95px que o ch dava — maiuscula com
   `letter-spacing` mede bem mais que a largura nominal do caractere. */
.check-marca { flex: none; font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; border-radius: var(--raio-pilula); padding: 3px 10px;
  min-width: 120px; box-sizing: border-box; text-align: center; }
/* Branco sobre acento reprovou na medicao (1,82 no escuro, 2,79 no claro):
   no escuro --ok e --laranja sao CLAROS. O selo passa a ser contorno, com a
   cor forte no texto sobre a superficie do card. */
.check-marca { background: var(--superficie); border: 1px solid var(--borda); }
/* --alerta-fg sobre branco da 4,48 (o ambar fraco ja registrado na Fase 11):
   o texto vai de --navy nos dois selos e o semantico fica na BORDA. */
.check-marca { color: var(--navy); }
.check-item.ok .check-marca { border-color: var(--ok-borda); }
.check-item.pendente .check-marca { border-color: var(--alerta-borda); }
.check-corpo { flex: 1; min-width: 0; }
.check-corpo > b { color: var(--navy); font-size: .92rem; }
.check-detalhe { color: var(--texto-2); font-size: .82rem; margin-top: 4px; line-height: 1.5; }
/* Fase 14: "Como agir" — a instrucao de uso, separada do "o que e" */
.check-agir { color: var(--texto); font-size: .82rem; margin-top: 6px; line-height: 1.5; }
.check-agir > b { color: var(--navy); }
/* Reavaliacao por item: recolhida — desvio decidido mostra a decisao, e
   editar e um clique deliberado */
.reavaliar-linha { margin-top: 8px; }
/* Mesmo defeito de token da 15.8, PRE-EXISTENTE (Fase 14): `--azul-sup` como
   cor de texto reprova AA no tema escuro. Corrigido junto — deixar um link
   sub-AA conhecido enquanto se declara a trava seria trava de mentira. */
.reavaliar-linha > summary { cursor: pointer; font-size: .8rem; font-weight: 600; color: var(--azul); }
.reavaliar-linha > summary small { color: var(--texto-2); font-weight: 400; }
/* Verdito em PAR (PO, 12/08): aprovar e reprovar com o MESMO tamanho, lado
   a lado. Fechado, o Reprovar e o PERIGO NA TELA da D-VIS-03 (`<summary
   class="botao botao-perigo">`, o contorno); aberto, ocupa a linha e vira o
   painel do motivo — a CONFIRMACAO (`.confirmacao` no formulario), onde o
   "Reprovar e desclassificar" e o perigo CHEIO. */
.verdito { display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; }
.reprovar-bloco { margin: 0; flex: 0 0 auto; }
.reprovar-bloco[open] { flex: 1 1 100%; border: 1px solid var(--erro-borda); border-radius: var(--raio-cartao); }
/* aberto, o summary vira o TITULO do painel: sem caixa propria (sem fundo, que
   pintaria por cima da curva da borda do painel) e sem sombra */
.reprovar-bloco[open] > summary { border: 0; width: 100%; background: none; box-shadow: none; }
.reprovar-bloco .check-form { padding: 0 12px 12px; }
.reprovar-trancado { padding: 0 12px 12px; margin: 0; }
/* Fase 15 — saneamento: chip do ponto de atencao e a caixa de devolucao.
   Pares de estado ja vetados; "observacao que descaracteriza" usa o ambar
   (e alerta, nao recusa declarada). */
.recusa-tipo-obs { display: inline-block; margin-left: 8px; padding: 1px 8px; border-radius: var(--raio-pilula); font-size: .68rem; font-weight: 700; vertical-align: 2px; text-transform: uppercase; letter-spacing: .03em; background: var(--alerta-bg); color: var(--alerta-fg); border: 1px solid var(--alerta-borda); }
.recusa-questionada { border-color: var(--info-borda); }
/* Ponto de atencao no formato de preenchimento (Fase 15). Os chips dizem POR
   QUE o item esta na lista e ficam na celula da descricao — a do numero (52px
   ate a `018`, 85 desde 09/10) nao os comporta. `margin-left` zerado no primeiro: no card eles vinham
   depois do numero, aqui abrem a celula. */
.ponto-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 6px; }
.ponto-chips > span { margin-left: 0; }
/* Lista de observacoes a ler: o texto e o protagonista, entao ele fica em
   destaque e o item vira cabecalho. */
.obs-leitura { display: flex; flex-direction: column; gap: 10px; margin-top: var(--sp-3); }
.obs-leitura-linha { background: var(--superficie-2); border: 1px solid var(--borda); border-left: 4px solid var(--acento); border-radius: var(--raio-cartao); padding: 10px 12px; }
.obs-leitura-item { font-size: .84rem; color: var(--texto-2); margin-bottom: 6px; }
.obs-leitura-item b { color: var(--azul); margin-right: 6px; }
.obs-leitura-texto { font-size: .9rem; color: var(--texto); line-height: 1.5; }
.obs-leitura-selo { display: inline-block; margin-left: 8px; padding: 1px 8px; border-radius: var(--raio-pilula); font-size: .66rem; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; background: var(--alerta-bg); color: var(--alerta-fg); border: 1px solid var(--alerta-borda); }
.obs-leitura-req { margin-top: 8px; }
.obs-leitura-req > summary { cursor: pointer; font-size: .78rem; color: var(--azul); }
.obs-leitura-req p { margin: 6px 0 0; font-size: .82rem; color: var(--texto-2); line-height: 1.5; }
.ponto-motivo { font-size: .78rem; color: var(--texto-2); font-style: italic; margin: 6px 0 2px; }
.devolver-bloco { margin-top: 12px; border-color: var(--alerta-borda); }
.devolver-bloco > summary { color: var(--alerta-fg); }
.devolver-bloco .check-form { padding: 0 12px 12px; }
.devolver-itens { display: grid; gap: 6px; margin: 6px 0 10px; }
.devolver-item { display: flex; gap: 8px; align-items: flex-start; font-size: .84rem; color: var(--texto); width: auto; }
.liberar-acao { margin-top: 14px; }
/* Confirmacao de leitura das observacoes quando a IA nao rodou (13/08). */
.liberar-aviso { margin-bottom: 12px; }
.liberar-obs { margin: 8px 0 0; padding-left: 18px; }
.liberar-obs li { margin-bottom: 4px; }
.liberar-obs b { font-variant-numeric: tabular-nums; margin-right: 4px; }
.liberar-confirma { display: flex; align-items: flex-start; gap: 8px; margin-bottom: 12px;
  font-size: .86rem; color: var(--texto); cursor: pointer; }
.liberar-confirma input { margin-top: 2px; flex: none; }
/* Fase 15 — quadro das PROPOSTAS dentro do certame. Herda .kanban/.card-rfp;
   o quadro nao ocupa a tela toda (convive com o resto do drill), entao a
   altura das colunas nao e travada aqui. */
/* O quadro saiu do `.painel-bloco` na validacao da 15: aninhado, ele somava o
   padding do bloco e ficava mais estreito que o conteudo do Painel. Agora ele
   e o conteudo da tela, na mesma largura util. O h2 perde o estilo que vinha
   de `.painel-bloco h2` e ganha o seu. */
.quadro-propostas { margin-bottom: var(--sp-4); }
.quadro-propostas > h2 { margin: 0 0 var(--sp-3); font-size: 1.02rem; letter-spacing: -.01em; }
.quadro-propostas > h2 small { font-weight: 500; color: var(--cinza); font-size: .8rem; margin-left: 8px; }
.quadro-propostas .kanban { background: var(--board-bg); }
.quadro-propostas .kanban-col { max-height: none; }
/* A bolinha da coluna vem do :nth-child generico (1..6), pensado para os
   quadros de 6 colunas. Este quadro tem 5 e herdava a cor por POSICAO — o
   valor calhava de bater, mas qualquer reordenacao (15.7) trocaria as cores
   em silencio. Aqui a cor fica presa ao SIGNIFICADO da coluna. */
.kanban-propostas .kanban-col:nth-child(1) .kanban-col-titulo::before { background: var(--faint); }   /* em preenchimento */
/* ESCOLHA (Design System): `--alerta` e `--laranja` eram dois tons (âmbar e
   laranja) e no sistema os dois são o `org`; para a 2ª e a 4ª coluna não
   ficarem iguais, a 2ª usa o `org-texto` (laranja escuro). */
.kanban-propostas .kanban-col:nth-child(2) .kanban-col-titulo::before { background: var(--org-texto); }  /* recebidas: a bola esta com a Alcance */
.kanban-propostas .kanban-col:nth-child(3) .kanban-col-titulo::before { background: var(--azul); }    /* analise tecnica */
.kanban-propostas .kanban-col:nth-child(4) .kanban-col-titulo::before { background: var(--laranja); } /* comercial */
.kanban-propostas .kanban-col:nth-child(5) .kanban-col-titulo::before { background: var(--ok); }      /* decidida */
/* Quadro GERAL (validacao da 15): 4 colunas, cor presa ao SIGNIFICADO pelo
   mesmo motivo do quadro das propostas. A 4a posicao herdaria `--laranja` da
   regra generica, que e a cor de menor contraste da paleta no tema claro
   (2,57) -- e "Encerrada" e desfecho, entao verde diz mais que laranja. */
.kanban-certames .kanban-col:nth-child(1) .kanban-col-titulo::before { background: var(--faint); }  /* rascunho */
.kanban-certames .kanban-col:nth-child(2) .kanban-col-titulo::before { background: var(--org-texto); } /* recebendo propostas */
.kanban-certames .kanban-col:nth-child(3) .kanban-col-titulo::before { background: var(--azul); }   /* em analise */
.kanban-certames .kanban-col:nth-child(4) .kanban-col-titulo::before { background: var(--ok); }     /* encerrada */
.card-certame { cursor: pointer; }
/* O card INTEIRO abre a proposta (queixa do PO: "ao clicar no card nao abre").
   Nao da para envolver tudo num <a>, porque o botao da etapa e outro <a> --
   HTML invalido e o botao perderia o clique. Entao o link do titulo se ESTICA
   sobre o card por ::after, e a acao sobe por z-index. */
/* Tipografia do card (apontamento do PO: "meio sem graça"). Os tres KPIs
   dividiam a largura em partes iguais e o total quebrava em duas linhas
   ("R$ 48,10 / mi"), o que sozinho ja estragava o card. Agora:
   - a grade da a cada KPI o espaco do seu conteudo, e o numero NAO quebra;
   - hierarquia de verdade: rotulo pequeno e cinza, numero grande e escuro,
     em fonte tabular (colunas de digitos alinhadas entre cards);
   - o total, que e o que se compara, pesa mais que os outros dois. */
.card-proposta .kpi-linha { display: grid; grid-template-columns: auto auto auto;
  justify-content: start; gap: 4px 18px; margin-top: 2px; }
.card-proposta .kpi { display: block; }
.card-proposta .kpi span { display: block; font-size: .64rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: .05em; color: var(--cinza); }
.card-proposta .kpi b { display: block; margin-top: 1px; font-size: .92rem;
  font-weight: 700; color: var(--navy); font-variant-numeric: tabular-nums;
  white-space: nowrap; }
.card-proposta .kpi:first-child b { font-size: 1.02rem; letter-spacing: -.01em; }
.card-proposta .card-rfp-kpis { border-top: 1px solid var(--line2); padding-top: 9px; margin-top: 9px; }
.card-proposta .card-rfp-titulo { font-size: .95rem; letter-spacing: -.01em; }
.card-proposta { position: relative; cursor: pointer; }
.card-proposta:hover { border-color: var(--azul); }
.cardp-abrir { text-decoration: none; }
.cardp-abrir::after { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: var(--raio-cartao); }
.cardp-acoes { position: relative; z-index: 2; }
.cardp-acao { padding: 5px 14px; font-size: .78rem; }
.cardp-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0; }
/* Sinal comercial no card (PO, 18/08): resposta da outra parte deixa de morar
   so no historico. Dois tons, porque o mesmo fato interessa a lados diferentes
   em momentos diferentes: `alerta` quando a bola esta com quem olha, `neutro`
   quando e so situacao. Reusa os tokens de erro e de info, ja medidos nos dois
   temas. */
.cardp-comercial { display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 9px; border-radius: var(--raio-pilula); font-size: .72rem; font-weight: 700;
  white-space: nowrap; }
.cardp-comercial.alerta { background: var(--alerta-bg); color: var(--alerta-fg); border: 1px solid var(--alerta-borda); }
.cardp-comercial.neutro { background: var(--info-bg); color: var(--azul-escuro); border: 1px solid var(--info-borda); }
.cardp-quest { background: var(--info-bg); color: var(--info-fg); border: 1px solid var(--info-borda); border-radius: var(--raio-pilula); padding: 1px 8px; font-size: .68rem; font-weight: 700; }
.cardp-acoes { display: flex; flex-wrap: wrap; gap: 4px 12px; margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--borda); }
/* TRAVA de contraste (15.8): era `--azul-sup`, que da 2,78 sobre o card no tema
   ESCURO — reprova AA para texto. `--azul-sup` e token de FUNDO (botao,
   cabecalho de tabela, avatar, bolha do chat), sempre com texto branco por
   cima; como cor de TEXTO ele nunca foi pensado. `--azul` e o de primeiro
   plano: identico no tema claro (7,04 — nada muda ali) e claro o bastante no
   escuro (6,00). */
.cardp-acoes a { font-size: .76rem; font-weight: 600; color: var(--azul); text-decoration: none; }
.cardp-acoes a:hover { text-decoration: underline; }
/* Confirmacoes pos-acao (mensagens do Django) — pares de estado vetados */
.mensagens { margin-bottom: 14px; display: grid; gap: 8px; }
/* O DESTAQUE do sistema (ver `.aviso-card`): barra lateral na cor da
   variante, rótulo mono em caixa alta nas duas do sistema (Nota e Atenção). */
.msg { padding: 10px 14px; font-size: .88rem; border-radius: var(--raio-cartao); border: var(--traco-cabelo) solid; border-left: var(--traco-destaque) solid; }
.msg-success { background: var(--ok-bg); color: var(--ok-fg); border-color: var(--ok-borda); border-left-color: var(--ok-fg); }
.msg-warning { background: var(--alerta-bg); color: var(--alerta-fg); border-color: var(--alerta-borda); border-left-color: var(--org); }
.msg-error { background: var(--erro-bg); color: var(--erro-fg); border-color: var(--erro-borda); border-left-color: var(--erro-fg); }
.msg-info { background: var(--info-bg); color: var(--info-fg); border-color: var(--fio); border-left-color: var(--blu); }
.msg-warning::before, .msg-info::before { display: block; margin-bottom: 3px; font-family: var(--font-mono); font-size: var(--t-rotulo);
  font-weight: 600; letter-spacing: 2.4px; text-transform: uppercase; }
.msg-warning::before { content: "Atenção"; }
.msg-info::before { content: "Nota"; }
.check-form { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.check-form label { display: block; width: 100%; font-size: .8rem; color: var(--texto-2); }
.check-form textarea { width: 100%; margin-top: 4px; }
/* Campo em bloco, botao a direita (pedido do PO): o textarea estreito ao lado
   do texto explicativo ficava apertado e desalinhado. */
.check-form-linha { display: flex; gap: 10px; align-items: flex-end; width: 100%; }
.check-form-linha textarea { flex: 1; }
.check-form-linha .btn { flex: none; }
@media (max-width: 700px) { .check-form-linha { flex-direction: column; align-items: stretch; } }
/* Decisao do desvio (Fase 14): radios lado a lado, quebra no estreito */
.check-decisao { display: flex; gap: 14px; flex-wrap: wrap; font-size: .84rem; }
.check-decisao label { display: flex; gap: 6px; align-items: center; width: auto; color: var(--texto); }
/* A recusa inteira na tela: requisito + resposta do fornecedor */
.recusa { margin-top: 12px; border: 1px solid var(--borda); border-radius: var(--raio-cartao); padding: 12px 14px; background: var(--superficie); }
.recusa-cab { color: var(--navy); font-size: .88rem; line-height: 1.45; }
.recusa-cab b { margin-right: 6px; }
.recusa-grade { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--sp-3); margin: 10px 0; }
/* Par descricao x requisito nas telas de CARTAO. Grade propria, com duas
   colunas FIXAS de largura igual: no `.recusa-grade` (auto-fit) uma terceira
   celula subiria para a mesma fileira e o par deixaria de ser par. Reempilha no
   mesmo corte de 900px da tabela — um so ponto de quebra no portal. */
.recusa-escopo { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); margin: 10px 0; }
@media (max-width: 900px) { .recusa-escopo { grid-template-columns: 1fr; } }
.recusa-grade span, .recusa-escopo span { display: block; font-size: .68rem; color: var(--cinza); text-transform: uppercase; letter-spacing: .04em; }
.recusa-grade p, .recusa-escopo p { margin: 4px 0 0; font-size: .84rem; color: var(--texto-2); line-height: 1.5; }
.recusa-na { color: var(--erro-fg); font-weight: 700; }
/* Fase 14: inabilitada por descumprimento tecnico + chips do desvio. Os chips
   usam o PAR erro-bg/erro-fg (vetado nos 2 temas) — nunca branco sobre cor
   forte, que ja reprovou em contraste duas vezes nesta base. */
.aviso-erro { background: var(--erro-bg); border: var(--traco-cabelo) solid var(--erro-borda); border-left: var(--traco-destaque) solid var(--erro-fg); }
.aviso-erro .aviso-txt strong { color: var(--erro-fg); }
/* OS AVISOS DO BM, que as telas do BM usam SOZINHOS (sem `.aviso-card`), em
   `<p>` e `<div>`: a mesma caixa do Destaque, com o respiro que o
   `.aviso-card` daria. `aviso-ambar` (a Atenção do sistema) e `recados-do-bm`
   NÃO EXISTIAM no `portal.css` (levantamento de 09/10): as telas do BM os
   usavam sem estilo nenhum. ⚠️ `span.aviso-ambar` é recado DENTRO de linha
   (uma célula, a mensagem do envio que o JS preenche): ali ele é só a cor de
   atenção, sem caixa — caixa numa célula cobraria largura de todas as linhas
   (regra 20) e o `<span>` vazio desenharia uma caixa vazia. */
p.aviso-erro, div.aviso-erro:not(.aviso-card), p.aviso-ok, div.aviso-ok:not(.aviso-card), p.aviso-ambar, div.aviso-ambar {
  padding: 10px 14px; margin: 0 0 12px; color: var(--texto); border-radius: var(--raio-cartao); }
.aviso-ambar { background: var(--alerta-bg); border: var(--traco-cabelo) solid var(--alerta-borda); border-left: var(--traco-destaque) solid var(--org); }
span.aviso-ambar { background: none; border: 0; padding: 0; color: var(--alerta-fg); font-weight: 600; }
p.aviso-ambar::before, div.aviso-ambar::before { content: "Atenção"; display: block; margin-bottom: 4px; font-family: var(--font-mono);
  font-size: var(--t-rotulo); font-weight: 600; letter-spacing: 2.4px; text-transform: uppercase; color: var(--alerta-fg); }
.recados-do-bm { display: grid; gap: 8px; margin-bottom: 14px; }
.recados-do-bm > p { margin: 0; }
.recusa-inabilitada { border-color: var(--erro-borda); }
.recusa-essencial, .recusa-nao-essencial, .recusa-veredito, .recusa-veredito-ok { display: inline-block; margin-left: 8px; padding: 1px 8px; border-radius: var(--raio-pilula); font-size: .68rem; font-weight: 700; vertical-align: 2px; text-transform: uppercase; letter-spacing: .03em; }
.recusa-essencial { background: var(--erro-bg); color: var(--erro-fg); border: 1px solid var(--erro-borda); }
/* O NAO essencial e o oposto de um alerta: ele DIMINUI a gravidade do ponto
   ("um NA aqui nao vira red flag"). Por isso e neutro e discreto — pintado de
   vermelho passaria a mensagem contraria. A classe `.recusa-essencial` fica: o
   selo vermelho volta se o PO decidir marcar os dois lados. */
.recusa-nao-essencial { background: var(--superficie-2); color: var(--texto-2); border: 1px solid var(--borda); }
.recusa-veredito { background: var(--erro-bg); color: var(--erro-fg); border: 2px solid var(--erro-fg); }
.recusa-veredito-ok { background: var(--ok-bg); color: var(--ok-fg); border: 2px solid var(--ok-fg); }
.recusa-aceita { border-color: var(--ok-borda); }
/* Parecer na linha do item (vista integral): aceito herda o tom OK; nao
   aceito o par de erro; sem decisao (legado) fica neutro — sempre por token. */
.obs-box.parecer-aceito { border-color: var(--ok-borda); }
.obs-box.parecer-aceito .cab { color: var(--ok-fg); }
.obs-box.parecer-nao-aceito { border-color: var(--erro-borda); }
.obs-box.parecer-nao-aceito .cab { color: var(--erro-fg); }
/* Situacao em uma palavra, no cabecalho */
.rot-situacao { letter-spacing: .03em; }
.check-acao { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.check-nota { color: var(--texto-2); font-size: .82rem; }
.check-quem { display: block; color: var(--cinza); font-size: .72rem; margin-top: 4px; }
/* Explicacao de cada condicao: o rotulo curto sozinho nao se entendia */
/* SEM teto de largura: o teto de 78ch cortava frase de uma linha no meio e
   deixava palavra orfa embaixo. Medida de leitura serve a paragrafo longo,
   nao a micro-copy de duas frases dentro de um cartao. */
.check-explica { color: var(--texto-2); font-size: .82rem; line-height: 1.55; margin-top: 6px; }
.check-estado { font-weight: 600; color: var(--navy); }
.check-consequencia { color: var(--texto-2); font-size: .8rem; font-style: italic; margin-top: 4px; }
/* Sequencia dos estagios: a tela diz onde esta e para onde vai */
.fluxo { list-style: none; display: flex; gap: 10px; flex-wrap: wrap; margin: 0 0 var(--sp-3); padding: 0; }
.fluxo-etapa { flex: 1 1 150px; border: 1px solid var(--borda); border-radius: var(--raio-cartao); padding: 10px 12px; background: var(--superficie); }
.fluxo-etapa b { display: block; color: var(--texto-2); font-size: .86rem; }
.fluxo-etapa small { color: var(--cinza); font-size: .7rem; text-transform: uppercase; letter-spacing: .04em; }
.fluxo-fase { display: block; font-size: .66rem; color: var(--cinza); text-transform: uppercase; letter-spacing: .06em; font-weight: 700; }
.fluxo-etapa.concluida { background: var(--ok-bg); border-color: var(--ok-borda); }
.fluxo-etapa.concluida b { color: var(--navy); }
.fluxo-etapa.atual { background: var(--info-bg); border-color: var(--azul); }
.fluxo-etapa.atual b { color: var(--navy); font-weight: 700; }
.fluxo-etapa.na { opacity: .72; }
/* Ambar sobre fundo verde/azul deu 3,96 no claro (medido). Inconsistencia de
   dado e alerta de verdade: tom de erro, que tambem contrasta. */
.fluxo-alerta { margin-top: 6px; font-size: .72rem; line-height: 1.4; color: var(--erro-fg); border-top: 1px solid var(--erro-borda); padding-top: 6px; }
.fluxo-nota { color: var(--texto-2); font-size: .84rem; line-height: 1.55; margin: 0; }

/* Fase 13.5 — telas da negociacao */
/* Refeita depois do apontamento do PO: os campos ficavam desalinhados e os
   rotulos de ajuda cortados. Grade com colunas de largura minima, rotulo em
   cima e ajuda embaixo -- nada compete pelo mesmo espaco. */
.neg-form { display: flex; flex-direction: column; gap: var(--sp-4); }
.neg-grade { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: var(--sp-3); }
/* SEIS por linha (PO, 14/08). Com `auto-fit, minmax(280px,1fr)` o numero de
   colunas saia da largura da janela: numa tela larga davam 7 na primeira linha
   e 5 na segunda, e a grade ficava torta com os 12 blocos tipicos. Fixando em
   6, os 12 caem em duas linhas cheias.

   O rotulo do bloco e longo e passou a quebrar em duas linhas; `align-items:
   end` mantem os CAMPOS alinhados entre si mesmo quando um rotulo ocupa uma
   linha a mais que o vizinho — sem isso a fileira de campos fica serrilhada,
   que e o mesmo defeito de outra forma. */
.neg-grade-blocos { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--sp-3); margin-top: var(--sp-3); align-items: end; }
@media (max-width: 1500px) { .neg-grade-blocos { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 1100px) { .neg-grade-blocos { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 760px)  { .neg-grade-blocos { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.neg-campo { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
/* CESTA do desconto por item (PO, 14/08): escolhe bloco -> item, empilha e
   envia tudo junto. O valor fica em CADA linha, porque cada item tem o seu. */
.neg-itens { margin-top: var(--sp-3); }
.neg-item-escolha { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr) auto; gap: var(--sp-3); align-items: end; }
@media (max-width: 900px) { .neg-item-escolha { grid-template-columns: 1fr; } }
.neg-item-lista { display: flex; flex-direction: column; gap: 8px; margin-top: var(--sp-3); }
/* 4 colunas desde 17/08: a UNIDADE entrou antes do valor, porque o tipo passou
   a ser por item (PO: "posso querer uns itens colocar valor e outros %").
   Ela vem antes do numero, que e a ordem em que se le — "R$ 1.500,00", "7,5%". */
.neg-item-linha { display: grid; grid-template-columns: minmax(0, 1fr) 76px 140px auto; gap: 10px; align-items: center;
  background: var(--superficie-2); border: 1px solid var(--borda); border-radius: var(--raio-cartao); padding: 8px 10px; }
@media (max-width: 760px) { .neg-item-linha { grid-template-columns: minmax(0, 1fr) 76px 110px auto; } }
.neg-item-rot { font-size: .84rem; color: var(--texto); min-width: 0; overflow-wrap: break-word; }
/* O valor do item embaixo da descricao (PO, 17/08): "ajuda no entendimento
   do desconto a ser solicitado". Em bloco proprio para nao competir com a
   descricao, e menor porque e referencia e nao o dado que se edita. */
.neg-item-desc { display: block; }
.neg-item-base { display: block; font-size: .76rem; font-weight: 600; color: var(--texto-2); margin-top: 2px; }
.neg-item-base:empty { display: none; }
.neg-item-linha input, .neg-item-unid { width: 100%; max-width: none; box-sizing: border-box; }
/* Fonte um ponto acima do resto do controle: "R$" e "%" sao dois caracteres e
   precisam ser lidos de relance, ao lado de um numero comprido. */
.neg-item-unid { font-weight: 600; text-align: center; }
/* o × que tira o item da cesta: ação em linha da lista, TEXTO/LINK
   (`botao botao-texto neg-item-tirar`), alvo de 30 px */
.botao.neg-item-tirar { justify-content: center; width: 30px; height: 30px; padding: 0; font-size: 1.05rem; line-height: 1; }
.neg-item-vazio { color: var(--texto-2); font-size: .84rem; margin: var(--sp-3) 0 0; }
/* Marcador da unidade DENTRO do campo do desconto (PO, 17/08: "quero que
   apareça o campo formatado ou pelo menos uma indicacao antes do campo,
   similar ao que e feito no valor unitario da RFP. E tem que ser mutavel
   conforme seleciono o tipo").

   Mesmo principio do `.vu-moeda`: ELEMENTO irmao, nunca pseudo. A diferenca e
   que aqui o embrulho tem EXATAMENTE a caixa do input, entao `top: 0; bottom: 0`
   com flex centra o rotulo sozinho — sem repetir padding e metrica de fonte a
   mao, que foi o que deu "aparece o R$ mas esta desalinhado" da outra vez.

   R$ vai a ESQUERDA e % a DIREITA porque e assim que se le cada um; o padding
   do input abre so do lado ocupado. */
.neg-unid { position: relative; display: block; }
.neg-unid-marca { position: absolute; top: 0; bottom: 0; display: flex; align-items: center;
  font-size: .84rem; font-weight: 600; color: var(--texto-2); pointer-events: none; }
.neg-unid[data-unid="valor"] .neg-unid-marca { left: 11px; }
.neg-unid[data-unid="percentual"] .neg-unid-marca { right: 12px; }
.neg-unid[data-unid="valor"] input { padding-left: 36px; }
.neg-unid[data-unid="percentual"] input { padding-right: 30px; }
.neg-rot { font-size: .76rem; font-weight: 600; color: var(--navy); }
.neg-ajuda { font-size: .72rem; color: var(--cinza); line-height: 1.4; }
.neg-campo select, .neg-campo input { width: 100%; }
.neg-blocos > summary { cursor: pointer; font-size: .86rem; font-weight: 600; color: var(--azul); }
.neg-blocos > summary small { font-weight: 400; color: var(--cinza); margin-left: 6px; }
.neg-acao { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
/* Botao presente mas bloqueado: mantem o padrao da tela e o cursor avisa */
/* (o `.bloqueado` é o DESABILITADO da D-VIS-03, sem opacidade: na regra dos
   botões, no topo do arquivo) */
/* O form comercial usa .neg-* (refeito na Fase 13.5); as .comercial-form/
   -linha/-grade/-blocos ficaram para tras e sairam na faxina da Fase 15. */
/* Decisao do fornecedor em PAR (apontamento do PO na validacao da Fase 15).
   Antes: Aceitar era um botao cheio e Recusar um `▸` cinza do tamanho de um
   link -- o desenho empurrava para o aceite, numa tela em que ele assume um
   preco. Agora os dois tem o MESMO tamanho e peso, e cada um abre o painel do
   proprio ato, com a consequencia escrita e o botao que executa la dentro.
   Herda `.verdito` (o par Aprovar/Reprovar da analise tecnica). */
.comercial-decisao { margin-top: var(--sp-4); }
/* DECISAO COMERCIAL — tela sobreposta e CENTRADA, uma por ato (PO, 14/08).
   Antes eram blocos que se expandiam na propria pagina: mesmo exclusivos, a
   decisao disputava a leitura com o resto da tela. Sobreposta, ela fica sozinha
   — que e o que se quer de um ato que NAO SE DESFAZ.

   Mesma tecnica da tratativa do item: `position: fixed` no conteudo do
   <details>, veu no ::before. O conteudo continua DENTRO do <form>, entao o
   csrf e o campo `rodada` vao junto no POST. */
/* Cancelar a solicitacao (PO, 17/08): reusa a tela sobreposta do aceite/recusa
   porque e o mesmo tipo de ato — nao se desfaz. O `name` do <details> e outro
   (`decisao-admin`) so para nao competir com os do fornecedor, que vivem noutra
   tela. */
.neg-cancelar { margin-top: var(--sp-3); }
.neg-avisar { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin-top: var(--sp-3); font-size: .86rem; cursor: pointer; }
.neg-avisar input { width: auto; flex: none; }
.neg-avisar small { flex-basis: 100%; color: var(--texto-2); font-size: .74rem; }
.decisao-modal { margin: 0; }
.decisao-modal > summary { list-style: none; cursor: pointer; }
.decisao-modal > summary::-webkit-details-marker { display: none; }
.decisao-modal[open]::before { content: ""; position: fixed; inset: 0; z-index: 79; background: var(--veu-modal); }
.decisao-modal[open] > .modal-caixa {
  position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 80;
  width: min(560px, calc(100vw - 32px)); box-sizing: border-box;
  max-height: 86vh; overflow-y: auto;
  background: var(--superficie); border: 1px solid var(--controle-borda); border-top: var(--traco-acento) solid var(--navy);
  border-radius: var(--raio-cartao);
  padding: 0 20px 20px;
}
.modal-topo { position: sticky; top: 0; display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: var(--superficie); border-bottom: 1px solid var(--line); margin: 0 -20px 16px; padding: 16px 20px 12px; }
.modal-topo b { color: var(--navy); font-size: 1rem; }
.modal-caixa p { font-size: .88rem; line-height: 1.55; color: var(--texto-2); margin: 0 0 14px; }
.modal-caixa label { display: block; font-size: .84rem; color: var(--texto-2); margin-bottom: 14px; }
.modal-caixa textarea { width: 100%; max-width: none; box-sizing: border-box; margin-top: 6px; }
/* Os NUMEROS do aceite em destaque: e sobre eles que a decisao e tomada. */
.modal-numeros { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); margin: 0 0 16px; }
.modal-numeros > div { background: var(--superficie-2); border: 1px solid var(--borda); border-radius: var(--raio-reto); padding: 10px 12px; }
.modal-numeros span { display: block; font-size: .68rem; color: var(--cinza); text-transform: uppercase; letter-spacing: .04em; }
.modal-numeros b { font-size: 1.02rem; color: var(--navy); font-variant-numeric: tabular-nums; }
/* Confirmar e Voltar lado a lado: a saida tem de ser tao visivel quanto o ato. */
.modal-acoes { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.decisao-corpo { padding: 12px 14px 14px; }
.decisao-corpo p { margin: 0 0 12px; font-size: .86rem; line-height: 1.5; }
.decisao-corpo label { display: block; margin: 0 0 12px; font-size: .8rem; color: var(--texto-2); }
.decisao-corpo label small { font-weight: 400; }
.decisao-corpo textarea { width: 100%; max-width: 520px; margin-top: 4px; }

/* ===== Bloco de red flags: rola por dentro, não estica a página ===== */
/* Pedido do PO: com muitas flags o bloco definia a altura da página e empurrava
   o comparativo para fora da tela. Cor sempre por token. */
.bloco-flags-n { font-weight: 700; font-size: .78rem; color: var(--cinza); }
.bloco-flags > .flags {
  overflow-y: auto; overscroll-behavior: contain; padding-right: 4px;
  /* Largura cheia (tela do contratante): teto de viewport, sem vizinho para seguir */
  max-height: 70vh;
}
@media (min-width: 901px) {
  /* Lado a lado no painel: a altura vem da TABELA vizinha. O bloco vira coluna
     flex esticada e a lista ocupa o que sobra — com flex-basis 0 e min-height 0
     a lista não empurra a altura da linha do grid. */
  .grid2 > .bloco-flags { display: flex; flex-direction: column; align-self: stretch; min-height: 0; }
  .grid2 > .bloco-flags > .flags { flex: 1 1 0; max-height: none; min-height: 220px; }
}
/* Impressão: teto e rolagem cortariam flags do papel. */
@media print {
  .bloco-flags > .flags { max-height: none; overflow: visible; }
}

/* ==========================================================================
   PORTAL DE BM — a tela de preenchimento (Fase 5, etapa 5b)

   Desenho aprovado ANTES do HTML: `docs/bm/tela-de-preenchimento-do-bm.md`.
   Critérios: `docs/bm/15-criterios-fase-5.md`.

   ⚠️ Usa SÓ os tokens que já existem acima, medidos nos dois temas. Cor nova
   aqui seria cor não medida — e a armadilha 8 do CLAUDE.md diz o que acontece
   com quem mede contraste sem forçar os dois temas.
   ========================================================================== */

/* ⚠️ O BM GANHOU A CASCA COM MENU LATERAL (instrução `018` §4), e com ela o
   `.main { overflow-x: clip }` da RFP. A tabela de medição foi desenhada para
   ROLAR NA HORIZONTAL com a página, com código e descrição congelados
   (`docs/bm/tela-de-preenchimento-do-bm.md` §1.1) e o cabeçalho `sticky` no
   topo — e o `clip` cortaria as colunas da direita em vez de rolar, sem barra
   nenhuma. Nas telas do BM a rolagem horizontal volta a ser a da página, como
   era antes da casca (armadilha 5: ao mover um bloco, leve o layout junto).
   Medido pelo `qa` a 1024 (veredito `018`, adendo B): nada cortado. Com o menu
   ABERTO as congeladas não prendiam — ver o `@media` depois delas, abaixo. */
body.casa-bm .main { overflow-x: visible; }

.tabela-de-medicao {
  width: 100%;
  border-collapse: separate;   /* `collapse` quebra o sticky: a borda da célula
                                  fixa fica desenhada pela tabela, não pela
                                  célula, e ela some ao rolar. */
  border-spacing: 0;
  font-size: 14px;
}

.tabela-de-medicao thead th {
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--navy);       /* cabeçalho do sistema: branco 600 sobre navy */
  color: var(--texto-inv);
  font-weight: 600;
  border-bottom: var(--traco-fio) solid var(--navy);
  text-align: left;
  padding: 8px 10px;
  white-space: nowrap;
}

.tabela-de-medicao td {
  padding: 6px 10px;
  border-bottom: 1px solid var(--line2);
  vertical-align: top;
}

/* ⚠️ AS DUAS COLUNAS CONGELADAS — e é `position: sticky`, NÃO uma segunda
   tabela. Congelar coluna duplicando a tabela quebraria a ordem do Tab: o campo
   da linha 1 levaria ao código da linha 2 (desenho §2.5). Aqui a ordem do DOM
   permanece a ordem visual, e o Tab funciona de graça. */
.tabela-de-medicao .col-codigo,
.tabela-de-medicao .col-descricao {
  position: sticky;
  background: var(--superficie);
  z-index: 2;
}
.tabela-de-medicao .col-codigo    { left: 0;     min-width: 90px; }
.tabela-de-medicao .col-descricao { left: 90px;  min-width: 280px; }
/* ⚠️ `.tabela-de-medicao .col-codigo` (0,2,0) vence `thead th` (0,1,2) e
   pintaria as duas congeladas do cabeçalho de branco — com o texto branco
   por cima. Aqui elas voltam ao navy; o filete `org` na primeira. */
.tabela-de-medicao thead .col-codigo,
.tabela-de-medicao thead .col-descricao { z-index: 4; background: var(--navy); }
.tabela-de-medicao thead .col-codigo { box-shadow: inset var(--traco-acento) 0 0 var(--org); }

/* ⚠️⚠️ COM O MENU NO FLUXO, AS CONGELADAS PRENDEM RENTE A ELE (veredito `018`,
   adendo B, defeito 3). O `left: 0` acima prende na borda da JANELA — certo
   abaixo de 901 px, onde o menu é gaveta por cima da página. No desktop o menu
   ocupa `--side-w` à esquerda, no fluxo: a 1024 com o menu ABERTO por escolha
   a página rola 40–54 px, a célula do código começa em 258 e nunca chega ao 0
   — não congelava — e o menu, preso só no `top`, saía pela esquerda.

   O que resolve, sem trocar de rolador: o menu prende também no `left`, e as
   congeladas prendem a `--side-w` da janela, que é a largura do menu no fluxo
   (`.side { width: var(--side-w) }`, 236 aberto e 66 recolhido). A página
   continua sendo o ÚNICO rolador, nos dois eixos — então o cabeçalho continua
   preso no `top: 0` ao rolar para baixo. (Uma caixa com `overflow-x: auto` em
   volta da tabela congelaria as colunas e SOLTARIA o cabeçalho: a caixa vira o
   rolador do `top` também, e ela não rola na vertical.) É o mesmo desenho da
   barra do total do escopo, `left: var(--side-w)` só no desktop.

   O `z-index` do menu fica acima de tudo da tabela: o rodapé dos totais é
   `sticky` (z 3) sem congelar, e ao rolar na horizontal ele passaria por cima
   do menu. Escopado à casca do BM: na RFP a `.main` corta o transbordo e a
   página não rola na horizontal. */
@media (min-width: 901px) {
  body.casa-bm .side { left: 0; z-index: 5; }
  body.casa-bm .tabela-de-medicao .col-codigo    { left: var(--side-w); }
  body.casa-bm .tabela-de-medicao .col-descricao { left: calc(var(--side-w) + 90px); }
}

.tabela-de-medicao .col-descricao small {
  display: block;
  color: var(--texto-3);
}

.tabela-de-medicao .col-dinheiro,
.tabela-de-medicao .col-ja-medido,
.tabela-de-medicao .col-contagem {
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;   /* dígito de largura fixa: coluna de
                                           dinheiro que dança ao trocar de valor
                                           é onde o olho perde a linha. */
}

/* Os botões da linha do BM ("fechar (…%)", "aceitar a proposta do SM",
   "manter o meu", "ver o que foi lançado") são AÇÕES EM LINHA DE TABELA: o
   TEXTO/LINK da D-VIS-03 (`botao botao-texto`, no `_linha_do_bm.html`). Eram o
   secundário compacto, por seletor de tipo (`024`). Aqui só a letra da
   célula. */
.tabela-de-medicao .botao { font-size: 0.82rem; }

/* ⚠️ A LARGURA SAI DO MAIOR CONTEÚDO QUE O DOMÍNIO PERMITE, em algarismos
   TABULARES — a conta das colunas da RFP (veredito `018`, adendo B, defeito 2).
   Era `8ch`: 68,70 px de caixa, e com o `box-sizing: border-box` geral e o
   padding/borda do `input[type="text"]` (12 + 12 + 1 + 1) sobravam 42,70 px
   para o texto — e "0,1200" mede 44,06 em Barlow 400, 15,2 px, tabular. O
   campo cortava o último algarismo do próprio valor.

       percentual  "100,0000"   0 a 100% com as 4 casas que `pct_construtor`
                                (6 casas da fração) deixa: 7 algarismos + vírgula
                                = (7 × 527 + 264) / 1000 × 15,2 = 60,09 px
       quantidade  "99999,999"  as 3 casas de `qtd_construtor`, e 5 algarismos
                                inteiros RESERVADOS (a maior quantidade da
                                planilha de referência é 70.000); acima disso
                                o número rola dentro do campo, inteiro, como
                                o Valor unit. de bilhão da RFP (veredito `018`)
                                = (8 × 527 + 264) / 1000 × 15,2 = 68,10 px

   Caixa = texto + 24 de padding + 2 de borda + 1 de folga para o cursor,
   arredondada para cima: 88 e 96. 527 e 264 são os avanços do algarismo
   TABULAR e da vírgula na Barlow 400 (por mil); `ch` é o zero PROPORCIONAL
   (565), e por isso não serve de régua aqui.
   `test_o_campo_de_medicao_cabe_o_MAIOR_valor_que_o_dominio_permite` refaz a
   conta lendo o padding, a borda e o corpo do `input[type="text"]`. */
.tabela-de-medicao .campo-medicao {
  width: 88px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.tabela-de-medicao .campo-medicao[data-modo="quantidade"] { width: 96px; }

/* ⚠️ A LINHA EM FOCO — barra de acento de 6px, NAS DUAS PONTAS.
   Fundo colorido está nos "becos sem saída" do CLAUDE.md: o melhor tingimento
   desta paleta dá 1,27 (escuro) e 1,14 (claro), invisível. A barra dá 6,0/7,04.
   E são as duas pontas porque numa linha larga a barra da esquerda sai do campo
   de visão de quem está digitando na coluna do meio (desenho §2.4). */
.tabela-de-medicao .linha-do-bm:focus-within .col-codigo {
  box-shadow: inset 6px 0 0 var(--acento);
}
.tabela-de-medicao .linha-do-bm:focus-within .col-estado {
  box-shadow: inset -6px 0 0 var(--acento);
}

.tabela-de-medicao .linha-do-bm[data-estado="salvando"] .col-estado {
  color: var(--texto-3);
}

/* ⚠️ TRÊS CANAIS no estado de falha — cor, ícone e texto —, porque é o estado
   que não pode passar despercebido (`15` §2). E ele não some sozinho com o
   tempo: some quando o salvamento der certo. */
/* ⚠️ ESCOPADOS sob `.tabela-de-medicao` de propósito. Este arquivo é
   COMPARTILHADO com a RFP, que está em produção — e `.estado-erro` é nome
   genérico o bastante para alguém criar um igual lá amanhã. Regra de portal
   novo não pode vazar para tela em uso. */
/* ⚠️ `inline-block` e `raio-controle`, e não pílula: a etiqueta quebra em coluna
   estreita, e `inline` a fatiava em tiras, com o canto só na primeira e na última
   (`design-system-desenho-qa.md`, D-2). Bloco inteiro, canto de controle. */
.tabela-de-medicao .estado-erro,
.tabela-de-medicao .estado-conflito {
  display: inline-block;
  color: var(--erro-fg);
  background: var(--erro-bg);
  border: 1px solid var(--erro-borda);
  border-radius: var(--raio-controle);
  padding: 1px 6px;
  font-weight: 600;
  white-space: normal;
}
.tabela-de-medicao .estado-salvo { color: var(--ok); white-space: nowrap; }

.tabela-de-medicao .linha-com-erro .col-codigo {
  box-shadow: inset 6px 0 0 var(--erro);
}

.tabela-de-medicao .linha-do-recado td {
  background: var(--erro-bg);
  border-bottom: 1px solid var(--erro-borda);
}

/* ⚠️ Os totais ficam colados na base da janela: quem digita a linha 300 precisa
   ver o total sem rolar até o fim de 411 linhas. */
.tabela-de-medicao tfoot td {
  position: sticky;
  bottom: 0;
  background: var(--superficie);
  border-top: 1px solid var(--borda);
  z-index: 3;
}
.tabela-de-medicao .total-do-bm td { font-size: 15px; }
.tabela-de-medicao .composicao-do-liquido td {
  color: var(--texto-2);
  font-size: 13px;
}

/* ==========================================================================
   PORTAL DE BM — a tela do SM (Fase 6, etapa 6b)

   Desenho aprovado ANTES do HTML: `docs/bm/tela-do-sm.md`.

   ⚠️ Escopado sob `.tabela-de-medicao`, pelo mesmo motivo do bloco da Fase 5:
   este arquivo é COMPARTILHADO com a RFP, que está em produção.
   ========================================================================== */

/* ⚠️ O valor lançado pelo Construtor é TEXTO, e o CSS reforça a diferença de
   NATUREZA que o HTML já faz — não a substitui. Se um dia virar campo, quem
   pega é `test_a_tela_NAO_TEM_campo_de_percentual_do_CONSTRUTOR`, não isto. */
.tabela-de-medicao .col-lancado {
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  background: var(--fundo-suave);
}
/* ⚠️ O MESMO CHOQUE das congeladas (acima, no bloco da Fase 5): a regra da
   coluna (0,2,0) vence `thead th` (0,1,2), e o cabeçalho "O Construtor lançou"
   saía BRANCO sobre `fundo-suave` — 1,12:1, medido pelo `qa` (veredito `018`,
   adendo B, defeito 1). O fundo claro é das CÉLULAS do corpo; o cabeçalho
   volta ao navy do sistema. Sem `z-index` aqui: esta coluna não congela, e
   um 4 a faria passar POR CIMA das congeladas ao rolar na horizontal.
   `test_o_cabecalho_de_TODA_coluna_da_tabela_de_medicao_tem_o_par_do_sistema`
   cobra o par de TODO `th` das tabelas de medição, não só deste. */
.tabela-de-medicao thead .col-lancado { background: var(--navy); }
.tabela-de-medicao .col-lancado small {
  display: block;
  color: var(--texto-2);
  font-weight: 400;
}

.tabela-de-medicao .col-proposta { min-width: 220px; }
/* A proposta do SM é o MESMO domínio do "Medir agora" em percentual
   (`pct_sm`, 0 a 100% com quatro casas): a mesma largura, pela mesma conta
   (ver `.campo-medicao`, no bloco da Fase 5). Era `8ch`, com o mesmo corte. */
.tabela-de-medicao .campo-proposta {
  width: 88px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.tabela-de-medicao .campo-justificativa {
  display: block;
  width: 100%;
  margin-top: 4px;
}

/* ⚠️ O CRITÉRIO ESCRITO, e ele é informação — não é o destaque. O `16` §1:
   "«40% de salto sobre a média dos BMs anteriores» é informação; destaque
   colorido sem explicação é enfeite." Por isso o sinal é TEXTO legível, e a cor
   só o separa da descrição. */
.tabela-de-medicao .sinal-de-risco {
  display: block;
  color: var(--alerta-fg);
  font-weight: 600;
}
.tabela-de-medicao .sinal-de-risco[data-sinal="fecha_a_linha"] {
  color: var(--erro-fg);
}

.abas-da-analise strong { border-bottom: 3px solid var(--acento); }
.abas-da-analise a { margin-left: var(--sp-4); }

/* ⚠⚠ A QUEBRA DO «RESPONDIDOS» na tela de envio — entrega 1, etapa 4.

   O número sai do SERVIDOR e NÃO acrescenta bloqueio: a trava de 100% já
   existia. Ele TORNA A TRAVA LEGÍVEL — antes o botão sumia sem dizer por quê.
   Por isso a aparência é de INFORMAÇÃO e não de alerta: sem cor de erro, sem
   ícone. Quem avisa que está bloqueado é o cartão de pendências, logo abaixo. */
.quebra-respondidos .quebra-total {
  margin: 0 0 var(--sp-2, 0.5rem);
  font-size: 1.05rem;
}
.quebra-respondidos .quebra-baldes {
  list-style: none;
  margin: 0;
  padding-left: var(--sp-3, 0.75rem);
}
.quebra-respondidos .quebra-baldes li {
  display: flex;
  gap: var(--sp-2, 0.5rem);
  max-width: 22rem;
  padding: 0.15rem 0;
}
/* O ponto do desenho ("· com preço 274"), e ele é decoração: fica no CSS,
   fora do HTML, para nao virar texto que leitor de tela anuncia. */
.quebra-respondidos .quebra-baldes li::before {
  content: "·";
  color: var(--borda);
}
.quebra-respondidos .quebra-baldes span {
  flex: 1 1 auto;
}
.quebra-respondidos .quebra-baldes b {
  font-variant-numeric: tabular-nums;
}
