/* painel/estilo.css — os tokens do /guias (leitor-guias/web/estilo.css) pelo NOME e pelo
   VALOR, não "no espírito". Este arquivo já afirmou isso no comentário enquanto era
   escuro; as mesmas nove pessoas alternam entre as duas telas o dia inteiro, e duas
   paletas obrigam a reaprender qual verde quer dizer "salvo" e qual vermelho quer dizer
   "não salvou". Claro também é o que combina com o trabalho: escritório, de dia, seis
   horas de digitação — tema escuro é recomendação para app de consumo à noite, e foi
   descartada de propósito. */
:root {
  --tinta: #0f172a; --suave: #64748b; --linha: #e2e8f0; --fundo: #f1f5f9;
  --marca: #002d5f; --acento: #0ea5e9; --alerta: #b45309; --perigo: #b91c1c;
  --ok: #047857;
  /* --suave dá 4.76:1 sobre BRANCO (passa) e 4.35:1 sobre --fundo (reprova), e aqui texto
     secundário cai nos dois fundos — o cabeçalho grudado da etapa é tingido com --fundo.
     Um cinza só, mais escuro, evita a pergunta "esse cinza está sobre qual fundo?": 7.6:1
     no branco, 6.9:1 no --fundo. --suave continua valendo para o que NÃO é texto (borda de
     hover), exatamente como no /guias. */
  --suave-texto: #475569;
  --sombra: -6px 6px 24px rgba(0, 45, 95, .07);
  /* Altura do cabeçalho fixo. O cabeçalho da etapa gruda LOGO ABAIXO dele: com número
     errado aqui, ou sobra um vão ou o nome da etapa some por baixo do topo.
     ⚠️ 63px só é VERDADE enquanto o `.topo` couber em UMA linha; quebrado em duas ele mede
     113px — aí o cabeçalho da etapa gruda em 63 e fica 50px ATRÁS do topo, invisível
     justamente onde foi prometido. O que mantém a constante honesta agora é CONSTRUÇÃO, e
     não medição: acima de 720px o `.topo` é `nowrap`, e quem cede espaço são o título e o
     nome de quem está conectado (reticências), nunca a linha. Abaixo de 720px ele volta a
     quebrar — e ali o cabeçalho da etapa deixa de grudar, então não há constante a honrar.

     ⚠️ POR QUE A CONSTRUÇÃO SUBSTITUIU A MEDIÇÃO: a medição envelheceu CALADA. Este arquivo
     dizia "quebra abaixo de 570px", e aquilo foi medido quando o topo tinha DUAS abas; com a
     terceira (Células) e o nome no teto de 22ch, o mínimo de uma linha já era 702px — 17px
     de folga para os 720px, e nenhum teste reprovou. Medido em Chrome no próprio painel:
     marca 135,1 + três abas 252,6 + nome 163,6 + Sair 54,3 + 6 vãos de 10 + 36 de recheio =
     702. Qualquer botão novo no topo custava mais do que a folga inteira (o "Exportações"
     custa 113,5px sozinho, 206,7px com o selo de falha) — com `nowrap`, custa zero. */
  --altura-topo: 63px;
  /* O que o cabeçalho grudado da etapa ocupa DEBAIXO do topo, para a rolagem parar antes
     dele. 43px medidos + folga; vira 0 onde o cabeçalho não gruda. */
  --altura-resumo: 52px;
}
/* ⚠️ ISTO É O QUE SALVA O SHIFT+TAB. Tabular para FRENTE o navegador resolve sozinho; para
   TRÁS, não: quando a caixa anterior já está dentro do retângulo da janela ele decide que
   não precisa rolar nada — e ela está dentro da janela, sim, mas DEBAIXO dos 106px de topo
   + cabeçalho de etapa grudados. A pessoa digita numa caixa que não vê. Voltar para
   corrigir um campo é movimento de primeiro dia em quem preenche 44; `scroll-padding-top`
   diz ao navegador que o alto da janela começa depois da moldura fixa, e as duas direções
   passam a parar no lugar. Uma linha, sem JS. */
html { scroll-padding-top: calc(var(--altura-topo) + var(--altura-resumo)); }
* { box-sizing: border-box; }

/* ─── O plano de fundo institucional, o MESMO arquivo que o formulário do cliente usa ────
   No `html` e não no `body`, e sem pseudo-elemento: o `background-attachment: fixed` no
   `html` pinta a tela do navegador uma vez, enquanto um `::before` com `z-index: -1`
   entraria em briga de empilhamento com o fundo do próprio `body`. O `body` fica
   transparente para não cobrir isto.

   ⚠️ O VÉU BRANCO AQUI É MAIS FRACO QUE O DO FORMULÁRIO, DE PROPÓSITO, e a diferença é
   medida. No formulário do cliente ele é 62%→74%, porque lá o texto da pergunta fica
   DIRETAMENTE sobre a imagem. Aqui todo texto mora dentro de `.cartao`, que é branco
   opaco — então o véu não é o que garante o contraste, e um véu forte só apagaria a marca
   sem comprar nada.
   Medido na própria imagem (luminância média 0.879; o percentil 5 mais escuro em 0.625):
   mesmo com véu ZERO, `--suave-texto` sobre o ponto mais escuro dá 4.87:1 — já passa AA.
   Com 50%→66% dá 6.1:1 a 6.5:1, com folga para pixels mais escuros que a amostragem não
   pegou. Se um dia entrar texto fora de cartão, refaça esta conta antes.

   `prefers-contrast: more` engrossa o véu: quem pede mais contraste no sistema está
   pedindo menos decoração atrás do texto, não uma imagem mais bonita. */
html {
  background:
    linear-gradient(rgba(255, 255, 255, .50), rgba(255, 255, 255, .66)),
    url("plano-de-fundo.png?v=1") center center / cover no-repeat fixed,
    var(--fundo);
}
@media (prefers-contrast: more) {
  html { background:
    linear-gradient(rgba(255, 255, 255, .92), rgba(255, 255, 255, .96)),
    url("plano-de-fundo.png?v=1") center center / cover no-repeat fixed,
    var(--fundo); }
}
body { margin: 0; background: transparent; color: var(--tinta);
       font: 15px/1.45 system-ui, -apple-system, "Segoe UI", sans-serif; }
h1, h2 { margin: 0 0 4px; }
h2 { font-size: 19px; color: var(--marca); }
.oculto { display: none !important; }
.cresce { flex: 1; }
.meta { color: var(--suave-texto); font-size: 12.5px; }
.erro { color: var(--perigo); min-height: 18px; }
.aviso { color: var(--alerta); font-weight: 600; }
/* ⚠️ TRÊS `<p class="aviso">` EMPILHADAS na seção da massa (`#massa-aviso`, `#massa-feito`,
   `#massa-fichas`), e o normal é as três estarem vazias — mas `<p>` vazio ainda carrega a
   margem do navegador, então sobrava um vão de meia linha entre os botões e a tabela da
   conferência, que crescia e encolhia conforme as frases apareciam. Mesmo idioma do
   `.progresso:empty` mais abaixo; e `:empty` em vez de omitir a marcação porque os três `<p>`
   são os ganchos que o JS procura por id. Vale também para o quarto `.aviso` da tela, o
   `#u-aviso` da aba de usuários, que passa a vida vazio pelo mesmo motivo. O `.erro` NÃO entra
   nisto: ele tem `min-height` de propósito, para a tela não pular quando a frase de erro
   aparece e desaparece. */
.aviso:empty { display: none; }
/* ⚠️ E O RESUMO DA LISTA DE CLIENTES, pelo mesmo motivo e no mesmo idioma. Ele é escrito por
   `desenhaClientes` ("12 de 40 cliente(s)"), então vazio ele só fica quando a lista NÃO veio —
   e é justamente aí que ele deixava 25px de vão entre a caixa de filtrar e a frase de erro que
   explica o que aconteceu, empurrando a explicação para longe da pergunta. Seletor por id, e
   não `.meta:empty`: `.meta` é a classe do `#quem` do topo e dos subtítulos dos dois diálogos,
   e uma regra larga aqui esconderia um deles no dia em que passasse a nascer vazio. */
#clientes-resumo:empty { display: none; }

/* ── O AVISO DE "VOCÊ VÊ SÓ A SUA CARTEIRA" ──
   ⚠️ NÃO É `.aviso`, e a diferença é o tempo. `.aviso` é `--alerta` em negrito: cor de "olhe
   isto agora", para frase que aparece depois de uma ação e sai da tela em seguida. Esta fica
   à vista TODA sessão de quem está numa célula restrita — em `--alerta`, seis horas por dia,
   ela ensina a ignorar a cor do alerta, e é a mesma cor que a recusa da massa usa. Então ela é
   uma NOTA: fundo de papel, filete `--marca` na borda que a lê como "informação do sistema", e
   o texto no tom de leitura normal. Continua achável — o filete é o que a separa da legenda
   cinza logo abaixo —, e não compete com o vermelho de `#clientes-erro`, que fica ao lado.
   `:empty` (e não omitir a marcação) porque o `<p>` é o gancho que o `desenha()` procura por
   id, e o `<p>` vazio ainda carrega a margem do navegador. */
.nota-carteira { margin: 8px 0 4px; padding: 8px 12px; border-left: 3px solid var(--marca);
                 background: var(--fundo); border-radius: 0 6px 6px 0;
                 font-size: 13.5px; color: var(--tinta); }
.nota-carteira:empty { display: none; }

/* Grudado no topo como no /guias: em card comprido, saber em qual ferramenta e em qual
   aba se está não pode depender de rolar de volta. */
.topo { display: flex; align-items: center; gap: 10px; padding: 11px 18px;
        background: #fff; border-bottom: 1px solid var(--linha);
        position: sticky; top: 0; z-index: 5; flex-wrap: nowrap; }
/* ⚠️ ENCOLHÍVEL COM RETICÊNCIAS, como o `#quem` ao lado — só que aqui é o `nowrap` que
   cobra: o mínimo automático de um item de flex é o CONTEÚDO, então sem `min-width: 0` e
   `overflow: hidden` o topo passaria a ESTOURAR para fora da janela em vez de encolher, e a
   página inteira ganharia rolagem lateral. "Painel de cli…" ainda responde em que ferramenta
   a pessoa está; barra de rolagem horizontal no painel, não. */
.marca { font-size: 16px; color: var(--marca); min-width: 0; overflow: hidden;
         text-overflow: ellipsis; white-space: nowrap; }
/* ⚠️ OS BOTÕES DO TOPO NÃO ENCOLHEM. Sem isto, a falta de espaço seria descontada deles
   também — "Exportaçõ…", "Sai…" — e botão cortado não diz o que faz. Quem cede são o título
   e o nome, que continuam respondendo o que respondiam depois das reticências. */
.topo button { flex: none; }
/* O nome de quem está conectado (`#quem`) é o único texto de largura imprevisível no topo,
   e é ele que decide quando o topo quebra em duas linhas: com "Célia Nunes (admin)" o topo
   quebra abaixo de 570px; com um nome de 44 letras, abaixo de 780px — ou seja, o
   `--altura-topo: 63px` estaria errado num notebook de 1024px, e não só no celular.
   ⚠️ `max-width` E NÃO só `min-width: 0`: item de flex com `flex-wrap` QUEBRA a linha antes
   de encolher, então deixá-lo encolhível não adianta — é preciso limitar o tamanho que ele
   pede. Com o teto, qualquer nome contribui no máximo o mesmo que um de 22 letras, o ponto
   de quebra volta a ser o de sempre (570px) e a constante volta a ser verdade em toda
   largura em que o cabeçalho da etapa gruda. Nome cortado por reticências ainda responde
   "quem está conectado"; a alternativa era medir a altura do topo em JS. */
.topo .meta { max-width: 22ch; overflow: hidden; text-overflow: ellipsis;
              white-space: nowrap; }
.aba { background: transparent; color: var(--suave-texto); border: 1px solid transparent;
       font-weight: 600; padding: 8px 12px; border-radius: 8px; cursor: pointer; }
.aba.ativa { color: var(--marca); border-color: var(--linha); background: var(--fundo); }
/* ── O botão da fila, no canto do topo ───────────────────────────────────────────────────
   `inline-flex` porque ele tem DUAS partes, o rótulo e o selo, e é o `gap` que as separa:
   com espaço em branco na marcação o vão dependeria de como o HTML foi indentado.
   ⚠️ O SELO É O AVISO DE FALHA (ver o comentário dele no index.html), e o `:empty` é o que o
   faz desaparecer quando não há falha nenhuma — mesmo idioma do `.aviso:empty` e do
   `.progresso:empty`, e `:empty` em vez de omitir a marcação porque o `<span>` é o gancho que
   o `atualizaSinalDaFila` procura por id. */
#abre-fila { display: inline-flex; align-items: center; gap: 7px; }
#fila-sinal:empty { display: none; }
/* ⚠️ A COR VEM JUNTO DO TEXTO, NUNCA SOZINHA: o selo já diz "2 falharam" por escrito, e
   `--perigo` no botão é o que faz o aviso ser notado por quem não estava lendo o topo. Cor
   sozinha não chega a quem não distingue vermelho — a mesma regra que a legenda do traço de
   progresso enuncia (o que separa os estados é o preenchimento, não só a cor). */

.painel { padding: 20px 18px 60px; display: grid; gap: 18px; }
/* ⚠️ `min-width: 0` porque item de grade NÃO encolhe abaixo do próprio conteúdo. A tabela
   de clientes tem células `nowrap`; sem esta linha ela empurrava o cartão inteiro para
   fora da janela e quem abria o painel em 768px rolava a PÁGINA para o lado — em vez de
   rolar a tabela dentro do `.rolavel`, que é o que o `.rolavel` existe para fazer. */
.painel > * { min-width: 0; }
.cartao { background: #fff; border: 1px solid var(--linha); border-radius: 14px;
          padding: 26px; box-shadow: var(--sombra); }
/* largo: a tabela de clientes tem muita coluna, e card estreito obrigava rolagem
   lateral — reclamação real na tela de usuários do /guias. */
.cartao.largo { max-width: 1500px; width: 100%; margin: 0 auto; }
.cartao:not(.largo) { max-width: 420px; margin: 8vh auto; }

input, select, button { font: inherit; }
input, select { background: #fff; color: var(--tinta); border: 1px solid var(--linha);
                border-radius: 8px; padding: 9px 11px; width: 100%; margin: 6px 0; }
/* Trabalho de digitação se faz TABULANDO, não clicando: quem preenche 44 campos precisa
   enxergar onde está o cursor sem procurar. Foco visível em tudo que recebe foco, e o
   `:focus` das caixas (e não só `:focus-visible`) porque ali o anel é informação, não
   enfeite. */
/* ⚠️ O ANEL É `--marca`, E NO /guias ELE É `--acento` — divergência de propósito, não
   deriva. `--acento` (#0ea5e9) dá 2.77:1 sobre o branco da caixa e 2.53:1 sobre `--fundo`:
   reprova o mínimo de 3:1 que se pede a um indicador não textual, e num formulário de 44
   campos o anel É a informação de onde o cursor está. `--marca` (#002d5f) dá 13.63:1 e
   continua sendo token do /guias — o vocabulário compartilhado fica inteiro, só a
   atribuição muda. Quem for "alinhar com o /guias" depois: isto foi decidido, não
   esquecido. */
/* ⚠️ A ÚNICA DIVERGÊNCIA DELIBERADA DO /guias NESTE ARQUIVO, e ela é medida. Lá o anel de
   foco é `--acento` (#0ea5e9), que sobre branco dá **2,77:1** — abaixo do mínimo de 3:1 para
   elemento de interface. `--marca` (#002d5f) dá **13,63:1**. Quem preenche 44 campos tabulando
   precisa VER onde está; copiar o anel do /guias por fidelidade seria copiar um defeito para
   dentro da tela que mais depende dele. Se um dia o /guias corrigir o anel dele, os dois
   voltam a coincidir — a divergência é do valor, não da ideia. */
input:focus, select:focus { outline: 2px solid var(--marca); outline-offset: -1px; }
a:focus-visible, button:focus-visible, summary:focus-visible,
input:focus-visible, select:focus-visible {
  outline: 2px solid var(--marca); outline-offset: 2px; }
summary:focus-visible { outline-offset: -2px; }
button { border: 1px solid var(--linha); background: #fff; color: inherit;
         border-radius: 8px; padding: 8px 13px; cursor: pointer; }
button:hover { border-color: var(--suave); }
button.primario { background: var(--marca); border-color: var(--marca); color: #fff; }
button.primario:hover { filter: brightness(1.15); }
button.mini { padding: 3px 9px; font-size: 12px; }
/* O logo. `width`/`height` estão no HTML também, e não é redundância: sem eles o navegador
   não reserva o espaço antes de a imagem chegar, e o cabeçalho PULA quando ela carrega.

   ⚠️ `logo-conecta.png` E `logo-simbolo.png` NÃO SÃO TRANSPARENTES — têm fundo BRANCO, e isso
   é uma decisão medida, não descuido. O arquivo de origem é um mockup (letras em 3D
   fotografadas numa parede) e recortar a parede com alfa deixava franja creme em volta do
   símbolo e borda rasgada sob "CONECTA": a sombra das letras é AZULADA, então nenhum teste de
   neutralidade a separa do logo. Achatar a parede para branco puro (correção de campo plano)
   sai limpo — mas só funciona sobre BRANCO.
   Por isso os dois lugares que os usam são brancos de propósito: `.topo` e `.cartao` têm
   `background:#fff`. Trocar o fundo de qualquer um dos dois por cor faz aparecer um retângulo
   branco em volta do logo. Se um dia isso for preciso, o caminho é o VETOR original, não um
   recorte melhor. Há prova em `backend/tests/test_painel_web.py`. */
.marca-simbolo { height: 36px; width: auto; margin-right: 9px; display: block; }
/* O conjunto no cartão de login. `max-width:100%` porque o cartão encolhe no celular e a
   imagem tem largura fixa em px — sem isto ela estoura a moldura. */
.marca-login { margin: 2px 0 18px; text-align: center; }
.marca-login img { max-width: 100%; height: auto; }
/* Ação secundária escrita como texto, sem moldura. Existe para "Esqueci minha senha" não
   competir com "Entrar": dois botões desenhados iguais no mesmo cartão fazem a pessoa
   escolher entre eles, quando um é o caminho e o outro é o desvio. Sublinhado e não só cor,
   porque cor sozinha não distingue nada para quem não a vê. */
button.botao-texto { border: 0; background: none; color: var(--marca); padding: 6px 0;
                     text-decoration: underline; font-size: 13px; }
button.botao-texto:hover { color: var(--acento); }
/* O "Excluir" ARMADO — o clique seguinte apaga uma conta e não tem desfazer. `--perigo` no
   texto e na borda porque é o único botão desta tela em que a cor precisa dizer "pare": a
   frase que explica o que vai acontecer mora no `#u-aviso`, acima da tabela, e quem já
   rolou até a vigésima linha pode não estar olhando para lá. Fundo claro e não sólido —
   #b91c1c em texto sobre #fef2f2 dá 6,2:1, e um botão vermelho cheio no meio de uma linha
   de botões brancos parece o botão principal da tela, que é o oposto do que ele é. */
button.mini.armado { color: var(--perigo); border-color: #fecaca; background: #fef2f2;
                     font-weight: 600; }
/* `not-allowed`, como no /guias: o cursor é a única pista de que o botão apagado está
   apagado de propósito, e não quebrado. */
button[disabled] { opacity: .45; cursor: not-allowed; }
.linha-form { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.linha-form input, .linha-form select { width: auto; flex: 1; min-width: 160px; }
/* Existe para NÃO haver `style="…"` embutido no app.js: `esc()` não neutraliza folha de
   estilo, então `prova_escape_painel.js` reprova o atributo `style` inteiro — inclusive
   literal. Estilo mora aqui; marcação gerada só carrega classe. */
.linha-form.espaco-acima { margin-top: 14px; }

/* Os botões de status abrem a etapa, então precisam de respiro ANTES dos campos, e de uma
   separação visível: sem a linha, eles pareciam o primeiro campo do formulário. */
.linha-form.status-da-etapa {
  margin-bottom: 14px; padding-bottom: 12px; border-bottom: 1px solid var(--linha);
}
/* Linha de pares rótulo+caixa (o formulário de criar usuário): os rótulos moram acima das
   suas caixas, e a linha alinha por BAIXO para o botão "Criar" ficar na altura das caixas
   e não na dos rótulos. */
.linha-form.pares { align-items: flex-end; }
.par { display: flex; flex-direction: column; gap: 3px; flex: 1 1 200px; }
.par .rotulo { margin-top: 0; }
.par input, .par select { width: 100%; margin: 0; }
.linha-checkbox { display: flex; gap: 8px; align-items: center; }
.linha-checkbox input { width: auto; margin: 0; }
/* Rótulo de verdade acima da caixa. Placeholder some quando se digita, e some da leitura
   de tela quase sempre — quem volta a um formulário meio preenchido fica sem saber o que
   aquele campo era. */
.rotulo { display: block; font-size: 12.5px; color: var(--suave-texto);
          margin-top: 10px; font-weight: 600; }

.rolavel { overflow-x: auto; }
/* `tabular-nums` vem do /guias (lá está no valor grande do cartão de contato e na coluna
   numérica da tabela de usuários): sem ele os dígitos têm larguras diferentes, e uma coluna
   de números — tentativas da fila, contagens de etapa — fica com as casas desalinhadas de
   linha para linha. Numa tabela que se lê de cima para baixo, isso atrapalha de verdade. */
table { width: 100%; border-collapse: collapse; background: #fff; font-size: 14px;
        font-variant-numeric: tabular-nums; }
th, td { text-align: left; padding: 9px 10px; border-bottom: 1px solid var(--linha);
         white-space: nowrap; }
th { color: var(--suave-texto); font-weight: 700; font-size: 11px;
     text-transform: uppercase; letter-spacing: .04em; }
tr:last-child td { border-bottom: 0; }
tr.clicavel { cursor: pointer; }
tr.clicavel:hover td { background: #f8fafc; }

/* O traço de progresso: 9 quadradinhos, um por etapa, na ordem da ficha.
   ⚠️ A COR NÃO PODE SER O ÚNICO SINAL — quem não separa verde de âmbar via só quadradinhos
   iguais. Cada estado tem um PREENCHIMENTO diferente (vazio, metade, cheio), que sobrevive
   em tons de cinza e em impressão, e a contagem "3/9" sai escrita ao lado. A legenda do
   que cada um significa está no index.html, em cima da tabela. */
.trilha { display: inline-flex; gap: 3px; align-items: center; }
.trilha i { width: 12px; height: 12px; border-radius: 3px; display: inline-block;
            border: 1px solid var(--suave); background: #fff; }
.trilha i.andamento { border-color: var(--alerta);
  background: linear-gradient(135deg, var(--alerta) 0 50%, #fff 50% 100%); }
.trilha i.concluida { border-color: var(--ok); background: var(--ok); }
.trilha .conta { margin-left: 6px; font-size: 12px; color: var(--suave-texto);
                 font-variant-numeric: tabular-nums; }
.legenda { display: flex; gap: 16px; flex-wrap: wrap; align-items: center;
           margin: 0 0 10px; }
.legenda .trilha { gap: 5px; }

.vinculos { display: flex; gap: 14px; flex-wrap: wrap; margin: 12px 0 18px; }
.vinculo { border: 1px solid var(--linha); border-radius: 12px; padding: 14px;
           flex: 1 1 260px; min-width: 260px; }
.vinculo .rotulo { color: var(--suave-texto); font-size: 11px; text-transform: uppercase;
                   letter-spacing: .06em; font-weight: 700; margin: 0 0 4px; }
.lido-de-outra { border-style: dashed; }
/* ── O RESPONSÁVEL, no card ──
   ⚠️ "SEM RESPONSÁVEL" É ESCRITO E TINGIDO, e não deixado em branco. Um `<div>` vazio sob o
   rótulo "Responsável" é indistinguível de dado que não carregou — e este é o caso que mais
   importa ler: cliente sem responsável NÃO APARECE para nenhuma célula que veja só a própria
   carteira, e é o único lugar de onde isso se resolve. `--alerta` (o mesmo do `.aviso`) porque
   é um estado que pede ação de quem está olhando; itálico para não parecer um e-mail curto. */
.sem-responsavel { color: var(--alerta); font-weight: 600; font-style: italic; }
/* A troca fica na MESMA caixa do valor. O `.vinculo` tem 260px e o `.par` de fábrica pede
   `flex: 1 1 200px`: com o botão "Trocar" ao lado, os dois não cabem na mesma linha e o botão
   cai para a de baixo — o que está certo, mas só porque o `.linha-form` tem `flex-wrap: wrap`.
   O `flex-basis` menor deixa os dois lado a lado quando o cartão tem espaço, e o `min-width: 0`
   é o que permite ao `.par` encolher (sem ele o flex respeita o `min-width: 160px` do
   `<select>` e a caixa estoura para fora do cartão). O ajuste é no `.par`, e não no `<select>`:
   ele é filho de um flex de COLUNA, onde `flex-basis` seria altura. */
.troca-responsavel { margin-top: 10px; align-items: flex-end; }
.troca-responsavel .par { flex: 1 1 140px; min-width: 0; }

.etapa { border: 1px solid var(--linha); border-radius: 12px; margin: 10px 0;
         background: #fff; }
/* ⚠️ CABEÇALHO GRUDADO, e o `top` é o do cabeçalho da página. Precificação tem 44 campos:
   depois de rolar meia tela a pessoa não sabe mais em qual etapa está digitando, e as três
   respostas ("qual etapa", "quanto falta", "em que estado ela está") são exatamente as que
   moram aqui. Fica grudado só enquanto a própria etapa está na tela — sticky não empilha
   com as irmãs. */
.etapa > summary { position: sticky; top: var(--altura-topo); z-index: 2;
                   padding: 10px 14px; cursor: pointer; display: flex; gap: 10px;
                   align-items: center; flex-wrap: wrap; background: var(--fundo);
                   border-radius: 11px; }
.etapa[open] > summary { border-bottom: 1px solid var(--linha);
                         border-radius: 11px 11px 0 0; }
/* ⚠️ ABAIXO DE 720px O CABEÇALHO DA ETAPA NÃO GRUDA, e é decisão, não desistência. Nessa
   faixa o `.topo` quebra em duas linhas (113px) e o próprio cabeçalho quebra em três
   (~99px): grudar os dois reservaria 212px dos 800px da tela do celular só para moldura, e
   `--altura-topo` estaria errado justamente ali. 720px é o mesmo ponto em que a grade cai
   para uma coluna — não é número novo. Sem grudar, `--altura-resumo` vira 0 e a rolagem do
   Shift+Tab volta a precisar só do topo. */
@media (max-width: 719px) {
  /* E aqui o topo VOLTA A QUEBRAR: abaixo desta faixa não há constante a honrar (o cabeçalho
     da etapa não gruda), e encolher título e nome até caberem numa linha de 320px deixaria os
     dois em reticências para não ganhar nada. */
  .topo { flex-wrap: wrap; }
  /* Aqui `--altura-topo` só alimenta o `scroll-padding-top`, e o valor é o PIOR CASO
     medido (162px em 320px de largura; 113px de 375px para cima), não o típico: errar para
     mais custa um vão em branco acima da caixa, errar para menos põe a caixa debaixo do
     topo — que é o defeito que este arquivo acabou de consertar. */
  :root { --altura-topo: 162px; --altura-resumo: 0px; }
  .etapa > summary { position: static; }
}
/* A seta é desenhada aqui, e não escrita na marcação: `display:flex` no summary já apaga o
   marcador padrão do navegador, e sem nenhum sinal de "isto abre" a etapa fechada parece
   um título morto. Sem emoji e sem imagem — duas bordas giradas. */
.etapa > summary::before { content: ""; width: 7px; height: 7px; flex: none;
  border-right: 2px solid var(--suave-texto); border-bottom: 2px solid var(--suave-texto);
  transform: rotate(-45deg); margin: 0 2px 0 0; transition: transform .12s ease; }
.etapa[open] > summary::before { transform: rotate(45deg); }
.etapa .corpo { padding: 12px 14px 14px; }
/* `inline-block` + `vertical-align: middle` vêm do /guias: sem eles o selo desalinha da
   linha de base do texto ao lado, e num cabeçalho de etapa isso aparece. */
.selo { display: inline-block; vertical-align: middle;
        font-size: 11px; padding: 2px 8px; border-radius: 999px; font-weight: 700;
        border: 1px solid var(--linha); background: var(--fundo);
        color: var(--suave-texto); white-space: nowrap; }
.selo.concluida { background: #ecfdf5; color: var(--ok); border-color: #a7f3d0; }
.selo.andamento { background: #fffbeb; color: var(--alerta); border-color: #fde68a; }
/* "12 de 44 preenchidos". Número tabular para o contador não dançar a cada campo salvo. */
.progresso { font-size: 12.5px; color: var(--suave-texto);
             font-variant-numeric: tabular-nums; }
.progresso.completo { color: var(--ok); font-weight: 700; }
/* Etapa sem campo no catálogo não tem "12 de 44" para mostrar, e etapa nunca alterada não tem
   "Alterada em": os dois `span` saem vazios e, como o `summary` é flex com `gap: 10px`, vazio
   ainda ocupa um vão — sobra um buraco no meio do cabeçalho e outro na ponta direita.
   ⚠️ Precisa ser SELETOR ESPECÍFICO e nunca `summary > span:empty`: o `.cresce` também é um
   `span` vazio, e ele é o espaçador que empurra o "Alterada em" para a direita — escondê-lo
   colaria tudo à esquerda. `:empty` (e não omitir a marcação) porque o `span` de progresso
   é o gancho que o salvamento procura para atualizar o contador. */
.progresso:empty, .etapa > summary > .meta:empty { display: none; }

/* Os campos que a ficha NÃO edita aqui (o que o formulário público gravou). `dd` quebra
   linha — o `white-space: nowrap` das células da tabela não vale aqui: descrição de CNAE e
   lista de CNAEs secundários são compridas, e cortar no meio esconde justamente o fim. */
.etapa dl { display: grid; grid-template-columns: minmax(140px, 220px) 1fr;
            gap: 4px 14px; margin: 6px 0 14px; }
.etapa dt { color: var(--suave-texto); font-size: 12.5px; }
.etapa dd { margin: 0; overflow-wrap: anywhere; }

/* Empresa arquivada ou que existe só para receber fatura: o card ABRE (é assim que se
   inspeciona o histórico de quem foi inutilizado), então precisa dizer o que é. */
.marca-estado { display: inline-block; margin-left: 8px; background: #fef2f2;
                color: var(--perigo); border-color: #fecaca; }

/* ⚠️ AS COLUNAS DOS CAMPOS SÃO O CORAÇÃO DESTA TELA. Precificação tem 44 campos; em coluna
   única são 44 linhas de rolagem e nenhuma noção de quanto falta. Três colunas no monitor
   da mesa, duas no notebook e no tablet, uma no celular. Números fixos e não `auto-fill`:
   o cartão vai a 1500px, e `auto-fill` com caixa de 220px daria SEIS colunas de rótulo
   espremido — a grade tem de servir à leitura, não preencher a largura. */
.campos { display: grid; gap: 12px 20px; margin: 4px 0 14px;
          grid-template-columns: 1fr; }
@media (min-width: 720px) { .campos { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1180px) { .campos { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
/* A ordem de tabulação é a da marcação, que aqui é a mesma da leitura: a grade preenche
   linha a linha, então tabular anda da esquerda para a direita e desce — igual ao olho. */
.campo { display: flex; flex-direction: column; gap: 3px; }
/* `overflow-wrap: anywhere` pelo mesmo motivo do `.etapa dd`, e aqui o risco é maior: item
   de grade não encolhe abaixo do próprio conteúdo, então UM rótulo com uma palavra
   comprida sem espaço (um e-mail, uma URL, um código colado) alarga a coluna, alarga o
   cartão e devolve a rolagem lateral da PÁGINA que o `.painel > * { min-width: 0 }` existe
   para matar. Nenhum rótulo da ficha faz isso hoje — mas rótulo é editável à mão no
   catálogo depois da primeira carga, então é alcançável por uso normal, não por ataque. */
.campo .meta { line-height: 1.25; overflow-wrap: anywhere; }
/* `margin: 0` desfaz o `margin: 6px 0` da regra geral de `input, select`: aqui quem dá o
   respiro é o `gap` da grade, e as duas somadas descolavam o rótulo da sua caixa. Altura
   de toque de celular (44px) custaria ~10px por campo — em precificação, 440px de rolagem
   a mais em quem trabalha com mouse e teclado. Por isso a caixa é compacta AQUI e cresce
   só onde o dedo é o ponteiro (regra `pointer: coarse` no fim do arquivo). */
.campo input.valor, .campo select.valor { width: 100%; margin: 0; padding: 6px 9px;
          border: 1px solid var(--linha); border-radius: 8px; font: inherit; }
/* Confirmação discreta: a pessoa preenche vários campos seguidos e precisa saber quais já
   foram, sem um aviso pulando a cada tabulação. O tema claro trouxe de volta o par de
   fundos do /guias (#ecfdf5 / #fef2f2) — o comentário antigo dizia que eles ficavam
   ilegíveis, e ficavam mesmo: o painel era escuro. */
.campo .valor.salvo { border-color: var(--ok); background: #ecfdf5; }
.campo .valor.nao-salvou { border-color: var(--perigo); background: #fef2f2; }

/* Dedo em vez de ponteiro: aí a área de toque vale mais que a linha economizada. */
@media (pointer: coarse) {
  .campo input.valor, .campo select.valor { padding: 10px 11px; }
  button.mini { padding: 8px 12px; }
}
/* ⚠️ AGORA TEM ANIMAÇÃO DE VERDADE, e é por ela que este bloco deixou de ser precaução: a
   CHAVE da aba de Células desliza (`transform` do botão, 180ms) e a cor da trilha vai de
   cinza a verde. Quem pede menos movimento no sistema recebe a mesma troca SEM transição — o
   estado final é idêntico, e ele é o que informa. O `!important` é o que garante isso mesmo
   com as regras da chave escritas mais abaixo neste arquivo. Continua valendo para o resto (a
   seta do `summary`, o hover do botão), que anima pouco. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: .01ms !important;
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    scroll-behavior: auto !important; }
}

/* A coluna de marcar. Largura fixa para a caixa não empurrar a razão social a cada
   redesenho — a tabela é relida a cada filtro digitado. */
#tabela-clientes th.marca-col, #tabela-clientes td.marca-col { width: 2.2rem; }
/* `margin: 0` desfaz o `margin: 6px 0` da regra geral de `input`: com ela, cada linha da
   tabela ganhava 12px de altura e uma lista de 40 empresas rolava uma tela a mais. */
#tabela-clientes input[type="checkbox"] { width: 1rem; height: 1rem; margin: 0;
                                          vertical-align: middle; }

/* A RECUSA DO TETO NÃO PODE SER TEXTO CINZA DE 12px. Ela é a única coisa entre "marquei o
   filtro errado" e um clique recusado depois do fato, e `.meta` é o estilo do que se lê de
   passagem. Com `--perigo` (#b91c1c, 6,47:1 no branco) e peso 700 ela se lê como recusa. */
.meta.excedeu { color: var(--perigo); font-weight: 700; font-size: 13.5px; }

/* Os três grupos da conferência. A COR NÃO É O ÚNICO SINAL: cada grupo entra com o nome
   escrito na primeira coluna ("já tinha outro valor", "estava vazia"), porque quem não
   separa âmbar de cinza precisa ler a mesma informação. */
tr.grupo-diferentes td { background: #fff7ed; }
tr.grupo-vazias td { background: #f8fafc; }
tr.grupo-iguais td, tr.grupo-sem-etapa td { color: #64748b; }

/* O selo de estado da tarefa, no mesmo desenho dos selos de etapa. */
/* mensagem de erro do Composio: pode ser longa, e quebrar é melhor que esticar a tabela */
td.motivo { max-width: 28rem; word-break: break-word; font-size: 0.86em;
            white-space: normal; }

/* ─── O cabeçalho do card e o botão "Exportar" ───────────────────────────────────────
   O botão fica na PONTA DIREITA da primeira linha do card, na altura da razão social. Antes
   ele morava no fim do card, depois das nove etapas — em precificação são 44 campos, e a
   ação mais pedida da tela ficava a uma tela e meia de rolagem do nome da empresa que ela
   exporta. `align-items: flex-start` para o botão alinhar com a PRIMEIRA linha do bloco de
   identidade (razão social) e não com o meio dele, que fica na altura do CNPJ. */
.cabeca-card { display: flex; gap: 12px; align-items: flex-start; }
/* `min-width: 0` pelo mesmo motivo do `.painel > *`: item de flex não encolhe abaixo do
   próprio conteúdo, e razão social é texto de largura imprevisível — sem isto ela empurraria
   o botão para fora do cartão em vez de quebrar linha. */
.cabeca-card .identidade { min-width: 0; }
/* O botão não encolhe nem quebra: "Exportar" cortado ao meio não é rótulo. */
.cabeca-card button { flex: none; white-space: nowrap; }

/* ─── O modal ──────────────────────────────────────────────────────────────────────────
   Saiu em 27/08/2026 com os diálogos de exportação e VOLTOU no mesmo dia com o aviso de
   carteira — restaurado do git, como o comentário de então mandava.

   ⚠️ `z-index: 10` fica acima do `.topo` (5) e do cabeçalho grudado da etapa (2). Modal que
   passa por baixo de cabeçalho fixo é modal que não bloqueia nada.

   ⚠️ O DESFOQUE É `backdrop-filter` NO VÉU, não `filter:blur()` no conteúdo de baixo — a
   mesma decisão (e o mesmo motivo) do player de vídeo do /cliente: `filter` num ancestral cria
   contexto de empilhamento e quebra `position:fixed`/`sticky` dos descendentes, e aqui isso
   levaria o `.topo` junto. O `@supports not` dá véu OPACO a quem não tem a propriedade, senão
   o texto do diálogo fica sobre um painel legível e perde contraste. */
.fundo-modal { position: fixed; inset: 0; z-index: 10;
               display: grid; place-items: center; padding: 20px;
               background: rgba(10, 30, 55, .42);
               -webkit-backdrop-filter: blur(14px) saturate(120%);
               backdrop-filter: blur(14px) saturate(120%); }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .fundo-modal { background: rgba(10, 30, 55, .86); }
}
/* Mesmo raio, sombra e borda do `.cartao`: o modal é um cartão que veio para a frente. */
.modal { background: #fff; border: 1px solid var(--linha); border-radius: 14px;
         padding: 20px 22px; width: min(560px, 100%); max-height: 86dvh; overflow-y: auto;
         box-shadow: 0 24px 60px rgba(10, 40, 80, .28); }
.modal:focus-visible { outline: 2px solid var(--marca); outline-offset: 2px; }
.cabeca-modal { display: flex; gap: 12px; align-items: flex-start; margin-bottom: 2px; }
.cabeca-modal h2 { min-width: 0; overflow-wrap: anywhere; }
.modal .linha-form { margin: 12px 0 0; }
.modal p { margin: 10px 0; }
.modal code { background: var(--fundo-suave, #f1f5f9); padding: 1px 5px; border-radius: 4px;
              font-size: 12.5px; }
/* Lista que não tem nada: a frase precisa dizer isso, e não deixar um vão vazio onde a
   pessoa fica procurando o que não existe. Nasceu no modal (empresa sem ficha nenhuma) e
   vale para os dois outros lugares em que a mesma pergunta aparece: o card de quem não tem
   etapa liberada pela célula, e a tabela de células vazia. Um seletor só porque é a mesma
   frase de mesmo tipo — três cópias divergiriam na primeira vez que alguém mexesse numa. */
.vazio { color: var(--suave-texto); font-size: 12.5px; margin: 12px 0; }

/* ─── A aba de CÉLULAS (no código, `setor`) ───────────────────────────────────────────
   O quadro de permissão, como o coordenador pediu: uma LISTA COM MARCADORES dos nove grupos
   da ficha, cada item com uma CHAVE deslizante (o "toggle do iPhone") e uma SANFONA que abre
   os campos daquele grupo.

   ⚠️ COLUNA ÚNICA, e isto é a reversão deliberada da grade de 2/3 colunas que estava aqui.
   Com sanfona, expandir um item de uma coluna empurra os vizinhos DELA e desalinha as outras
   — a pessoa perde o lugar no meio de uma decisão de acesso. Em coluna única, expandir
   empurra para baixo e nada mais se move. O que a grade comprava (comparar o que está ligado
   sem rolar) a chave devolve de outro jeito: a POSIÇÃO do botão é visível de longe, muito
   mais que um quadradinho de 16px.
   ⚠️ E É `<ul>`/`<li>` DE VERDADE: os marcadores são o pedido, e a lista semântica é o que
   faz o leitor de tela anunciar "item 3 de 9". */
.lista-etapas { list-style: disc; margin: 12px 0 4px; padding-left: 22px; }
.lista-etapas > li { margin: 6px 0; }
.lista-etapas > li::marker { color: var(--suave); }
/* ⚠️ AGORA SÃO DUAS FILEIRAS EMPILHADAS, e a `.linha-chave` é a MOLDURA das duas: em cima o
   acesso e o nome do grupo; embaixo, quando o acesso está ligado, o nível. O pedido foi "o
   toggle de leitura edição, deixe mais próximo do toggle de liga e desliga, no caso pode ficar
   abaixo do toggle de liga e desliga" — e o que ele corrige é real: com o nível empurrado para
   a borda direita do cartão largo (1500px), as duas chaves da MESMA permissão ficavam a meia
   tela de distância, e a segunda caía debaixo do olho de quem estava lendo o nome do grupo.
   Empilhadas, as duas ficam a 26px uma da outra e leem-se como o que são: dois passos do mesmo
   controle.
   ⚠️ O `flex` MORA NUM `<div>`, NUNCA NO `<li>`. Flex (ou grid) no `<li>` APAGA o marcador da
   lista, e o marcador é pedido do coordenador ("uma lista com marcadores") — é por isso que
   este `div` existe desde o começo, e é por isso que empilhar as chaves NÃO virou
   `flex-direction: column` no `<li>`. Medido na `prova_celulas_painel.js`. */
.linha-chave { display: flex; align-items: flex-start; gap: 8px;
               border: 1px solid var(--linha); border-radius: 10px; padding: 2px 8px; }
.linha-chave:hover { border-color: var(--suave); }
/* A PRIMEIRA fileira: a chave de acesso e o texto que expande, IRMÃOS na mesma linha — é isso
   que faz o clique na chave não abrir a sanfona (ver o comentário do `itemDaEtapa` no app.js).
   `flex-start` porque o texto do grupo pode quebrar em duas linhas e a chave tem de continuar
   no alto, ao lado da primeira. */

/* ── A CHAVE: `<input type="checkbox">` NATIVO, desenhado até parecer a chave do iPhone ──
   ⚠️ NÃO TROQUE POR `<div>` COM `onclick`. É decisão de quem construiu a tela, está escrita
   no index.html e o motivo é este painel ser usado seis horas por dia por gente que tabula:
   na caixa nativa o teclado (Tab chega, Espaço alterna), o foco, o `<label for>` e o estado
   que o leitor de tela anuncia ("caixa de seleção, marcada") vêm DE GRAÇA. Uma chave de
   `div` é bonita e inacessível, e este painel já perdeu o foco do teclado duas vezes.
   `appearance: none` desliga o desenho do sistema e mantém TUDO isso — e é por isso que a
   caixa não é escondida com `display: none`, que a tiraria da ordem de tabulação.
   O `label` é o alvo grande: 44px de altura contando o vão, que é o mínimo para o dedo. */
.lista-etapas .chave,
.linha-carteira .chave { display: flex; align-items: center; min-height: 44px;
                       padding: 0 2px; cursor: pointer; flex: none; }
/* ⚠️ A TERCEIRA CHAVE ENTRA NAS MESMAS REGRAS, e não numa cópia delas. É a decisão que o
   bloco do NÍVEL, mais abaixo, já documenta ("ela é A MESMA CHAVE, e as regras foram
   AGRUPADAS em vez de copiadas"): três chaves no mesmo painel com desenhos que divergem — uma
   verde e uma azul, uma que desliza e uma que só muda de cor — seriam lidas como três
   controles diferentes, e a pessoa procuraria a diferença de comportamento que não existe. O
   seletor dela não é prefixado por `.lista-etapas` porque ela mora no CABEÇALHO do painel, e
   não na lista dos nove grupos — que é justamente a distinção que ela precisa comunicar. */
.lista-etapas input.etapa-da-celula,
.lista-etapas input.nivel-da-celula,
input.chave-de-carteira {
  appearance: none; -webkit-appearance: none;
  width: 46px; height: 26px; flex: none; margin: 0; padding: 0; position: relative;
  border: 1px solid var(--linha); border-radius: 999px; background: var(--linha);
  cursor: pointer;
  /* 180ms: dentro da faixa de 150–300ms que o desenho pede. Menos que isso não se lê como
     movimento (a chave "pisca"), mais que isso atrasa nove decisões seguidas. Quem pediu
     menos movimento no sistema recebe a troca sem transição — ver o bloco
     `prefers-reduced-motion` mais acima, que zera a duração de tudo, inclusive daqui. */
  transition: background-color .18s ease, border-color .18s ease;
}
/* ⚠️ O BOTÃO É `::before` DO PRÓPRIO INPUT, e não um `<span>` na marcação: um `span` de
   enfeite obrigaria `aria-hidden` (atributo novo na prova de escape) e daria ao app.js mais
   marcação para escrever à mão. Pseudo-elemento em `input` com `appearance: none` é suportado
   nos três motores. */
.lista-etapas input.etapa-da-celula::before,
.lista-etapas input.nivel-da-celula::before,
input.chave-de-carteira::before {
  content: ""; position: absolute; top: 2px; left: 2px; width: 20px; height: 20px;
  border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(15, 45, 95, .35);
  transition: transform .18s ease;
}
/* Ligada: VERDE `--ok`, o mesmo verde que já quer dizer "salvo" no resto do sistema — e o
   botão vai para a DIREITA. ⚠️ A cor não é o único sinal, e aqui isso sai de graça: a posição
   do botão informa por si, então quem não distingue o verde do cinza lê a chave igual. */
.lista-etapas input.etapa-da-celula:checked,
.lista-etapas input.nivel-da-celula:checked,
input.chave-de-carteira:checked { background: var(--ok); border-color: var(--ok); }
.lista-etapas input.etapa-da-celula:checked::before,
.lista-etapas input.nivel-da-celula:checked::before,
input.chave-de-carteira:checked::before { transform: translateX(20px); }
/* ⚠️ O ANEL É `--marca`, NUNCA `--acento` — ver a medição no alto deste arquivo (`--acento`
   dá 2,77:1 sobre branco, abaixo do mínimo de 3:1; `--marca` dá 13,63:1). `offset` positivo
   porque a chave é uma pílula: o anel colado nela se confunde com a borda dela. */
.lista-etapas input.etapa-da-celula:focus,
.lista-etapas input.nivel-da-celula:focus,
input.chave-de-carteira:focus { outline: 2px solid var(--marca);
                                           outline-offset: 2px; }

/* ── A FILEIRA DA TERCEIRA CHAVE, no cabeçalho do painel da célula ──
   Mesma altura de alvo das outras (44px, herdada da regra `.chave` no alto deste bloco) e o
   rótulo GRUDADO nela: ao contrário das nove, esta chave não tem uma sanfona ao lado para
   dizer do que ela trata, então a palavra é a única coisa que a nomeia — e ela é um
   `<label for>`, então clicar no texto alterna a chave. Peso 600 porque a linha compete com o
   `<h2>` e os dois botões logo acima. */
.linha-carteira { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.rotulo-carteira { font-weight: 600; cursor: pointer; }

/* ── A SEGUNDA CHAVE: O NÍVEL, ENTRE LEITURA E EDIÇÃO ──
   ⚠️ ELA É A MESMA CHAVE, e as regras acima foram AGRUPADAS em vez de copiadas: duas chaves na
   mesma linha com desenhos que divergem (um verde e um azul, um que desliza e um que só muda
   de cor) leriam-se como dois controles de naturezas diferentes, quando são o mesmo gesto
   sobre a mesma permissão. Agrupar também é o que garante que o `appearance: none`, o anel
   `--marca`, os 180ms e o `prefers-reduced-motion` valham para as duas para sempre — uma
   cópia divergiria no primeiro ajuste, e a metade esquecida seria a nova.

   ⚠️ E ELA FICA ABAIXO DA DE ACESSO, na segunda fileira da `.linha-chave` — não mais empurrada
   para a borda direita com `margin-left: auto`. Foi o pedido ("deixe mais próximo do toggle de
   liga e desliga, no caso pode ficar abaixo"), e o que ele corrige: num cartão de 1500px, o
   `margin-left: auto` jogava a segunda chave a meia tela da primeira, e quem acabava de ligar o
   acesso não tinha por que olhar para lá. Empilhadas, o gesto seguinte cai 26px abaixo do dedo.
   O que a distância comprava (não confundir "liguei o acesso" com "liberei a edição") passa a
   ser comprado pelas PALAVRAS e pela COR da trilha, que agora divergem: a de acesso é cinza ou
   verde, a de nível é branca ou verde, e a de nível tem as duas palavras ao lado. `padding-left`
   de 2px alinha a fileira com a borda da chave de cima (o `.chave` tem `padding: 0 2px`). */
.nivel { display: flex; align-items: center; gap: 6px; flex: none;
         margin-left: auto; padding-left: 10px; }
/* ⚠️ AS DUAS PALAVRAS SÃO O CONTROLE, e não legenda. Uma chave entre dois estados sem nome só
   sabe dizer "ligado", e "ligado" não responde se o ligado é Leitura ou Edição — foi a dúvida
   literal do usuário ("como eu ajusto quem edita? não sei"). Então as duas ficam escritas, uma
   de cada lado, e a que vale agora é grifada em PESO e em COR: quem não distingue os tons lê o
   negrito, e a posição do botão da chave é o terceiro sinal. Nenhum deles sozinho. */
.palavra-nivel { font-size: 12.5px; color: var(--suave-texto); white-space: nowrap; }
.palavra-nivel.agora { color: var(--marca); font-weight: 700; }

/* ── A COR DA CHAVE DE NÍVEL: LEITURA = BRANCO, EDIÇÃO = VERDE ──
   Foi o pedido ("altere a cor para leitura branco e edição verde"), e ele separa as duas chaves
   agora que elas ficaram empilhadas: a de acesso é CINZA (`--linha`) quando desligada, a de
   nível é BRANCA quando em Leitura. Sem essa divergência, duas pílulas quase idênticas uma
   embaixo da outra pediriam para ser lidas como a mesma coisa duas vezes.

   ⚠️ E TRILHA BRANCA SOBRE CARTÃO BRANCO PRECISA DE CONTORNO, senão ela não fica feia — fica
   AMBÍGUA: quem olha não sabe se está em Leitura ou se a chave nem existe naquela linha. O
   contorno é `--suave` (#64748b), que dá 4,76:1 contra o branco do `.cartao` — acima do mínimo
   de 3:1 para elemento de interface (não é texto). `--linha` (#e2e8f0) NÃO serve aqui: dá
   1,23:1, que é o mesmo que não ter contorno. As duas contas estão medidas na
   `prova_celulas_painel.js`, e é ela que reprova a troca.

   ⚠️ E O BOTÃO TROCA DE COR COM A TRILHA, pelo mesmo motivo: branco sobre branco apagaria o
   botão, e com ele a POSIÇÃO — que é o sinal que existe justamente para não depender da cor.
   Em Leitura o botão é `--suave` sobre trilha branca (4,76:1); em Edição volta a ser branco
   sobre o verde `--ok` (5,55:1). Nos dois estados dá para ver de que lado ele está. */
.lista-etapas input.nivel-da-celula { background: #fff; border-color: var(--suave); }
.lista-etapas input.nivel-da-celula::before { background: var(--suave); }
.lista-etapas input.nivel-da-celula:checked::before { background: #fff; }

/* ── A SANFONA: os campos que compõem o grupo ──
   `<details>`/`<summary>` nativo, o mesmo idioma das nove etapas do card (`.etapa`), e sem
   `position: sticky`: aqui a sanfona é curta e o cabeçalho grudado só brigaria com o do
   card. 44px de altura no `summary` pelo mesmo motivo do `label`. */
.sanfona { flex: 1; min-width: 0; }
.sanfona > summary { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
                     min-height: 44px; padding: 4px 2px; cursor: pointer;
                     list-style: none; }
.sanfona > summary::-webkit-details-marker { display: none; }
/* A seta é desenhada aqui, e não escrita na marcação — mesma regra do `.etapa > summary`. */
.sanfona > summary::before { content: ""; width: 7px; height: 7px; flex: none;
  border-right: 2px solid var(--suave-texto); border-bottom: 2px solid var(--suave-texto);
  transform: rotate(-45deg); transition: transform .18s ease; }
.sanfona[open] > summary::before { transform: rotate(45deg); }
/* A contagem ("44 campos"): com grupos de 4 e de 44, saber o tamanho ANTES de expandir é o
   que evita a rolagem surpresa. Cinza e menor — é dado de apoio, não o nome do grupo. */
.sanfona .conta-campos { color: var(--suave-texto); font-size: 12.5px; }
/* Os campos, em colunas de largura fixa: 44 rótulos em coluna única são 44 linhas de
   rolagem, e aqui ninguém compara nada — só confere o que tem dentro. `column-width` (e não
   número fixo de colunas) porque o cartão vai de 320px a 1500px. */
.campos-do-grupo { list-style: disc; margin: 0 0 10px; padding-left: 26px;
                   column-width: 230px; column-gap: 22px; font-size: 13px; }
.campos-do-grupo li { margin: 2px 0; break-inside: avoid; }
.sanfona > p.meta { margin: 0 0 10px; }

/* A célula escolhida na tabela: o quadro de permissão abaixo é DELA, e sem marca na lista
   fica fácil configurar a errada depois de rolar a tela. Barra à esquerda além do fundo —
   cor sozinha não chega a quem não a distingue, mesmo idioma do traço de progresso. */
#tabela-celulas tr.selecionada td { background: #eff6ff; }
#tabela-celulas tr.selecionada td:first-child { box-shadow: inset 3px 0 0 var(--marca); }
/* Lista vazia (nenhuma célula cadastrada): a frase ocupa a linha, sem `nowrap` de célula de
   tabela e sem parecer um dado. */
td.vazio { color: var(--suave-texto); font-size: 12.5px; white-space: normal; }

/* ─── O NÍVEL CHEGANDO AO CARD: A ETAPA SOMENTE-LEITURA ──────────────────────────────
   ⚠️ SOMENTE-LEITURA NÃO É `disabled`, E ESTE BLOCO É ONDE ISSO SE VÊ. Uma caixa de texto
   cinza e travada é o desenho universal de "quebrado, ou falta preencher algo antes": quem a
   encontra procura o que destravar e acaba pedindo suporte. O valor escrito como TEXTO é lido
   como informação, que é o que ele é — a Célula tem acesso de leitura ali, e leitura é um
   estado completo, não uma edição impedida. Por isso não há `input` nenhum aqui: nem
   `readonly`, nem `disabled`.
   A altura acompanha a das caixas de edição (`.valor`) de propósito: numa ficha em que algumas
   etapas editam e outras só leem, linhas de alturas diferentes fariam a grade de três colunas
   dançar entre uma etapa e a seguinte. */
.valor-lido { margin: 0; padding: 7px 0; font-size: 14px; color: var(--tinta);
              min-height: 20px; overflow-wrap: anywhere; }
/* O vazio é ESCRITO, e em tom secundário: campo somente-leitura em branco é indistinguível de
   campo que não carregou, e daqui ninguém pode conferir a diferença (não há caixa para
   clicar). */
.valor-lido.vazio { color: var(--suave-texto); font-style: italic; }
/* A frase que ocupa o lugar dos três botões de status. Fundo e barra à esquerda em `--marca`,
   e NÃO em `--perigo`: não é erro nem aviso, é o estado normal de quem tem leitura. Ela é a
   única coisa na etapa capaz de explicar por que não há controle nenhum — sem ela, uma etapa
   sem botões e sem caixas parece uma etapa que não carregou. */
.somente-leitura { margin: 0 0 10px; padding: 8px 10px; font-size: 12.5px;
                   color: var(--marca); background: #eff6ff; border-radius: 8px;
                   box-shadow: inset 3px 0 0 var(--marca); }

/* ─── 403 NÃO É VERMELHO ──────────────────────────────────────────────────────────────
   `.erro` é `--perigo` porque quer dizer "algo deu errado". Falta de permissão é o sistema
   funcionando e dizendo não — mesma caixa, outro significado, e com a mesma cor a pessoa trata
   os dois como defeito e chama o TI. Fica em `--alerta` sobre fundo âmbar, com a barra à
   esquerda: distinto do vermelho E distinto do texto comum, para quem não separa os dois tons.
   A frase do `mensagemDoErro` já diz por escrito que não é falha — o CSS é o reforço, nunca o
   único sinal (caixa de erro copiada para um chamado viaja sem folha de estilo). */
.erro.sem-permissao { color: var(--alerta); background: #fffbeb; border-radius: 8px;
                      padding: 8px 10px; box-shadow: inset 3px 0 0 var(--alerta); }

/* ── A aba de Auditoria ──────────────────────────────────────────────────────────────
   As duas origens ganham uma marca DISCRETA na lateral, e não cores de fundo diferentes:
   a tabela é lida de cima a baixo procurando UMA linha, e fundo alternado por categoria
   compete com essa leitura. A marca responde "isto é ato administrativo ou mudança de
   cliente?" quando a pergunta aparece, sem gritar antes disso. */
.origem-cliente td:first-child { border-left: 3px solid var(--acento); }
.origem-admin   td:first-child { border-left: 3px solid var(--suave); }

/* A trilha guarda valores longos (endereço, razão social, observação). Sem isto, uma linha
   estica a tabela e empurra as colunas que importam para fora da tela. */
#tabela-auditoria td { vertical-align: top; max-width: 22rem; word-break: break-word; }

/* ══ A TELA DE ENTRADA: duas colunas ═══════════════════════════════════════════════════
   Vale para os TRÊS cartões que dividem esta tela (login, "esqueci minha senha" e "defina
   sua senha"). Deixar um com moldura nova e dois com a antiga seria pior que não mexer: os
   três aparecem no mesmo fluxo, e a pessoa que erra a senha sai de um para o outro. */
.entrada { display: grid; grid-template-columns: 40% 1fr; min-height: 100vh;
           /* `100dvh` depois do `100vh`: no Safari do iPhone a barra de endereço entra na
              conta do `vh`, e o rodapé ficava escondido atrás dela. Navegador que não
              conhece `dvh` ignora a linha e fica com o `vh` de cima. */
           min-height: 100dvh; }

/* ── A coluna da marca ── */
/* ⚠️ O NAVY É `#05265B`, AMOSTRADO DO MOCKUP, e não `var(--marca)` (#002d5f). Os dois são
   quase iguais e a diferença some ao lado um do outro — mas `--marca` é o token de TEXTO e
   de botão do painel inteiro, medido para contraste sobre BRANCO (13,63:1, ver o anel de
   foco). Este é um plano de fundo de meia tela. Amarrar os dois faria um ajuste de
   legibilidade no token repintar esta parede, e um ajuste de parede mexer no contraste de
   44 campos. São propósitos diferentes, então são valores diferentes. */
/* ⚠️ CENTRALIZADO NOS DOIS EIXOS, e o `align-items: center` faz metade do trabalho: ele
   centra cada filho horizontalmente. A outra metade é os dois filhos compartilharem a MESMA
   largura (o `max-width: 460px` de baixo) — sem isso, o logo e a frase seriam centrados
   INDEPENDENTEMENTE, cada um com a sua largura, e a frase deixaria de começar onde o logo
   começa. É esse alinhamento entre os dois que o mockup tem.
   Padding SIMÉTRICO (6% dos dois lados): a versão anterior tinha 8% à esquerda e 6% à
   direita, o que já empurrava o bloco para a esquerda antes de qualquer centralização. */
.entrada-marca { background: #05265B; color: #fff;
                 display: flex; flex-direction: column;
                 justify-content: center; align-items: center;
                 padding: 6vh 6%; gap: 18px; }
/* A marca, sobre o navy. `69%` sai da proporção do mockup (o logo ocupa ~69% da largura da
   coluna), e o `max-width` é o que impede o arquivo de 899px de crescer além do desenhado
   numa janela larga. `height: auto` com `width`/`height` na marcação: os atributos reservam
   o espaço antes de a imagem chegar, o CSS decide o tamanho final. */
.entrada-logo { display: block; width: 100%; max-width: 460px; height: auto; }
/* A MESMA largura máxima do logo — é o que faz a frase começar exatamente onde o "b"
   começa, em vez de os dois serem centrados cada um por si. */
/* ⚠️ O TETO É 24px, E ELE FOI MEDIDO CONTRA O MOCKUP — não escolhido por gosto. Com o teto
   anterior (18px) a frase saía com 17px de tinta contra os 23px do mockup: **25% menor**. E o
   efeito disso não é "a fonte está pequena", é outro: uma frase miúda ao lado de um logo de
   460px se DESCOLA dele — os dois deixam de ler como um bloco só, e o olho reporta isso como
   desalinhamento, que foi exatamente a queixa. O vão entre os dois (24px contra os 22px do
   mockup) já estava certo; o que faltava era peso.

   ⚠️ E O TETO É 22px, NÃO 24px, POR UMA RAZÃO MEDIDA: a 24px a frase pede 471px e a caixa
   tem 460 — ela QUEBRAVA em duas linhas, e no mockup é uma linha só. Alargar a caixa
   consertaria a quebra e estragaria o alinhamento (o logo e a frase dividem a mesma largura
   máxima; é isso que faz as duas começarem no mesmo x). A 22px a frase pede 432px: cabe com
   28px de folga, que é a margem para a pilha de fontes do sistema variar entre um Mac e um
   Windows — e este painel roda nos dois. A tinta sai com ~21px contra os 23px do mockup.
   `vw` e não px fixo porque a coluna é 40% da janela: a frase precisa encolher junto com ela. */
.entrada-frase { margin: 0; width: 100%; max-width: 460px;
                 font-size: clamp(15px, 1.35vw, 22px); color: #E8EEF7; }

/* ── A coluna do cartão ── */
/* `#F9F8F6` também sai do mockup: é um branco QUENTE, e a diferença para o branco puro é o
   que faz o cartão ter borda visível sem precisar de sombra pesada. */
.entrada-conteudo { background: #F9F8F6; display: flex; flex-direction: column;
                    align-items: center; justify-content: center; gap: 14px;
                    padding: 5vh 24px; }
/* ⚠️ ANULA O `margin: 8vh auto` do `.cartao:not(.largo)`. Dentro de um flex centralizado,
   aquela margem empurrava o cartão para baixo do centro — o desalinhamento que parece "quase
   certo" e que ninguém sabe explicar. O `max-width` continua vindo de lá. */
/* ⚠️ E ALARGA PARA 480px, contra os 420px do `.cartao:not(.largo)`. O motivo é MEDIDO, não
   estético: o rótulo do checkbox aqui é "Seguir conectado NESTA MÁQUINA por 30 dias" — mais
   longo que o do mockup, de propósito (ver o comentário dele no index.html) —, e em 420px ele
   não cabe na mesma linha do "Esqueci minha senha": o desvio quebrava para baixo e para a
   ESQUERDA, parecendo desalinhado. Alargar o cartão é o que deixa a frase inteira E o
   alinhamento do mockup coexistirem. Vale só dentro da entrada; o resto do painel continua
   com 420px. Os 520px também são a largura do mockup: lá o cartão ocupa 37% da tela, que
   em 1440px de janela dá 533px. */
.entrada-conteudo .cartao { margin: 0; width: 100%; max-width: 520px; }
.entrada-rodape { margin: 0; color: var(--suave); font-size: 12.5px; }

/* O par de títulos do cartão de login. `<p>` e não `<h2>`: o `<h1>` do cartão é o logo (com
   o nome no `alt`), e um `<h2>` aqui criaria um segundo nível de título para uma frase de
   boas-vindas — ruído na navegação por cabeçalhos de quem usa leitor de tela. */
.entrada-titulo { margin: 0; text-align: center; font-size: 21px; font-weight: 700;
                  color: var(--marca); }
.entrada-sub { margin: 2px 0 16px; text-align: center; color: var(--suave-texto);
               font-size: 13.5px; }

/* ── Campo com ícone, e o olho da senha ── */
.campo-com-icone { position: relative; display: flex; align-items: center; }
/* O `padding-left` abre o vão do ícone; o `padding-right` só existe onde há o olho, e quem
   decide isso é a presença do botão — daí a regra irmã logo abaixo. */
.campo-com-icone input { padding-left: 40px; }
.campo-com-icone:has(.ver-senha) input { padding-right: 44px; }
.icone-campo { position: absolute; left: 12px; width: 18px; height: 18px;
               pointer-events: none; fill: none; stroke: var(--suave);
               stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
/* ⚠️ O ÍCONE ACOMPANHA O FOCO. Sem isto ele fica cinza claro dentro de uma caixa com anel
   `--marca` em volta, e lê-se como campo desabilitado — o oposto do que o foco significa. */
.campo-com-icone:focus-within .icone-campo { stroke: var(--marca); }
.ver-senha { position: absolute; right: 6px; border: 0; background: none; padding: 6px;
             line-height: 0; border-radius: 6px; color: var(--suave); }
.ver-senha svg { width: 19px; height: 19px; fill: none; stroke: currentColor;
                 stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.ver-senha:hover { color: var(--marca); border-color: transparent; }
/* Ligado = a senha está À VISTA, que é o estado que pede atenção numa máquina compartilhada.
   A cor acompanha o `aria-pressed`, então o estado é UM só — não há um booleano em JS e uma
   classe de CSS para divergirem. */
.ver-senha[aria-pressed="true"] { color: var(--marca); }

/* ── A linha do checkbox com o desvio ── */
.linha-opcoes { display: flex; align-items: center; justify-content: space-between;
                gap: 12px; flex-wrap: wrap; margin: 10px 0 2px; }
.linha-opcoes .linha-checkbox { font-size: 13px; }
/* ⚠️ `margin-left: auto` E NÃO SÓ O `space-between`. Quando os dois não couberem na mesma
   linha (rótulo mais longo, fonte maior do sistema, zoom em 150%), o `space-between` sozinho
   joga o desvio para a ESQUERDA da segunda linha, encostado no checkbox — lê-se como erro de
   alinhamento. Com a margem automática ele fica à direita nos DOIS casos, e a quebra passa a
   parecer intencional, que é o que ela é. */
.linha-opcoes .botao-texto { padding: 0; white-space: nowrap; margin-left: auto; }

/* ⚠️ ABAIXO DE 900px A COLUNA DA MARCA SOME, e não vira uma faixa no topo. Numa tela de
   celular ela seria uma parede azul de 200px empurrando o formulário para baixo da dobra —
   e o que a pessoa precisa ver ao abrir é o campo de e-mail, não o logo. O nome do sistema
   continua na tela: ele está no logo DENTRO do cartão. */
@media (max-width: 900px) {
  .entrada { grid-template-columns: 1fr; }
  .entrada-marca { display: none; }
}

/* ⚠️ O BOTÃO PRINCIPAL DA ENTRADA OCUPA A LARGURA DO CARTÃO, e é assim no mockup. Não é só
   estética: nos três cartões desta tela existe UMA ação principal ("Entrar", "Enviar senha
   provisória", "Salvar"), e ela é o fim do caminho — largura cheia é o que a separa dos
   desvios ("Esqueci minha senha", "Voltar ao login"), que são texto sublinhado. No celular
   ela também vira um alvo de toque que ocupa a tela inteira, em vez de um retângulo de 90px
   encostado na margem esquerda.
   Escopo em `.entrada-conteudo` de propósito: no painel de trabalho os botões primários
   convivem em linha com outros (a barra da massa, o card do cliente), e largura cheia lá
   empilharia tudo. */
.entrada-conteudo .cartao button.primario { width: 100%; padding: 11px 13px;
                                            font-weight: 600; margin-top: 4px; }
/* O desvio do cartão de recuperação passa a ficar ABAIXO do botão, centralizado — antes ele
   dividia a linha com ele. Com o principal ocupando a largura, dividir a linha não é opção. */
.entrada-conteudo .cartao button.botao-texto { display: block; margin: 10px auto 0; }
/* ...menos o "Esqueci minha senha", que mora na linha do checkbox e continua à direita. */
.entrada-conteudo .linha-opcoes button.botao-texto { display: inline; margin: 0 0 0 auto; }

/* ── Acessibilidade da tela de entrada: alvos de toque e contraste ────────────────────
   ⚠️ MEDIDO, NÃO ESTIMADO (28/08/2026). Os três controles secundários do cartão nasciam
   ABAIXO do mínimo de 44×44 do Apple HIG (48×48 do Material): o olho da senha em 31×31, o
   "Esqueci minha senha" em 127×19 e o rótulo do checkbox em 292×19. Numa tela que roda em
   tablet no RH — e que é a PRIMEIRA de todas — errar o alvo é errar a entrada no sistema.

   O padrão aqui é ESTENDER a área de toque sem crescer o desenho: `min-height` mais padding
   nos dois de texto, e altura/largura fixas no olho com o ícone mantido em 19px. O que a
   pessoa vê continua igual ao mockup; o que o dedo acerta é que muda. */
.entrada-conteudo .ver-senha { width: 44px; height: 44px; display: flex;
                               align-items: center; justify-content: center; right: 2px; }
.entrada-conteudo .linha-opcoes .botao-texto { min-height: 44px; display: inline-flex;
                                               align-items: center; }
.entrada-conteudo .linha-opcoes .linha-checkbox { min-height: 44px; }
/* A caixa nativa em si continua com o tamanho do sistema — o alvo é o `<label>` inteiro,
   que embrulha o texto. Ampliá-la deixaria um quadrado azul desproporcional ao lado de uma
   frase de 13px. */

/* ⚠️ O RODAPÉ SAI DE `--suave` PARA `--suave-texto`, e é uma reprova de contraste MEDIDA:
   `--suave` (#64748b) sobre o fundo quente `#F9F8F6` dá **4,48:1** — abaixo do mínimo de
   4,5:1 do WCAG AA, por um triz. Sobre branco puro ele passaria (4,76:1), e é por isso que o
   defeito só existe AQUI: a coluna da entrada é a única superfície do painel que não é
   branca. `--suave-texto` (#475569) dá 7,2:1 no mesmo fundo. */
.entrada-rodape { color: var(--suave-texto); }

/* ── Os grupos de célula na aba de Usuários ───────────────────────────────────────────
   `<details>` nativo, o mesmo idioma da sanfona da aba de Células e das nove etapas do card
   — teclado, semântica e estado de aberto/fechado vêm de graça. */
.grupo-celula { border: 1px solid var(--linha); border-radius: 10px; margin-bottom: 10px;
                background: #fff; }
/* O cabeçalho é a superfície de clique inteira, e por isso o padding mora AQUI e não num
   filho: um `<summary>` com padding só no texto deixa faixas mortas nas laterais, onde o
   clique não abre nada e a pessoa conclui que a sanfona travou. */
.grupo-celula > summary { padding: 11px 14px; cursor: pointer; border-radius: 10px;
                          /* ⚠️ 44px de altura mínima — a mesma regra dos alvos da tela de
                             entrada, e aqui vale para quem administra em tablet. */
                          min-height: 44px; display: flex; align-items: center; gap: 6px; }
.grupo-celula > summary:hover { background: var(--fundo); }
.grupo-celula[open] > summary { border-bottom: 1px solid var(--linha);
                                border-radius: 10px 10px 0 0; }
.grupo-celula > summary:focus-visible { outline: 2px solid var(--marca); outline-offset: -2px; }
.grupo-celula > table { width: 100%; }
.grupo-celula > p { padding: 0 14px; }
/* A frase que explica o grupo ("sem célula, um operador não vê etapa nenhuma"). Fica ACIMA da
   tabela e dentro do `<details>`: ela responde "por que isto importa?", e essa pergunta só
   aparece depois de a pessoa abrir o grupo. */
.nota-do-grupo { margin: 10px 14px 2px; }
