  /* ---- seleção em lote ----------------------------------------------------
     A caixa mora SOBRE a miniatura, e não numa coluna própria: uma coluna só
     para ela custaria largura em toda linha por um recurso que a maioria nunca
     usa. Invisível até o hover — e sempre visível quando marcada, senão o
     usuário perde de vista o que selecionou ao mover o mouse. */
  .pj-marca { position: absolute; inset: 0; display: flex; align-items: center;
              justify-content: center; background: rgba(19,31,51,.45);
              opacity: 0; transition: opacity var(--t); cursor: pointer; }
  .pj-capa, .card-thumb { position: relative; }
  .pj-linha:hover .pj-marca, .card:hover .pj-marca,
  .pj-linha.marcado .pj-marca, .card.marcado .pj-marca { opacity: 1; }
  .pj-marca input { width: 17px; height: 17px; accent-color: var(--orange); cursor: pointer; }
  /* Marcado: anel laranja em vez de fundo colorido. A linha zebrada já usa
     fundo, e dois fundos disputando deixam a lista suja. */
  .pj-linha.marcado { box-shadow: inset 3px 0 0 var(--orange); background: #fff8f3 !important; }
  .card.marcado { border-color: var(--orange); box-shadow: 0 0 0 2px rgba(255,101,1,.22); }

  /* Barra de lote: mesma anatomia da barra de estado das outras telas —
     grudada embaixo, dentro do fluxo, e só existe quando há seleção. */
  .pj-lote { position: sticky; bottom: 12px; z-index: 20; margin-top: var(--s4);
             display: flex; align-items: center; gap: 10px;
             background: var(--navy); color: #fff; border-radius: 12px;
             padding: 10px 14px; box-shadow: 0 6px 20px rgba(19,31,51,.28); }
  .pj-lote-n { min-width: 26px; height: 26px; padding: 0 7px; border-radius: 20px;
               background: var(--orange); color: #fff; font-weight: 700; font-size: 12.5px;
               display: inline-flex; align-items: center; justify-content: center;
               font-variant-numeric: tabular-nums; }
  .pj-lote-acoes { margin-left: auto; display: flex; align-items: center; gap: 8px; }
  /* Sobre o navy, o campo claro padrão cegaria. Estes dois herdam a altura
     compacta (32px) das outras barras densas. */
  .pj-lote select { height: 32px; padding: 0 10px; border-radius: 9px; font-size: 12.5px;
                    background: rgba(255,255,255,.12); color: #fff;
                    border: 1px solid rgba(255,255,255,.22); box-shadow: none; }
  .pj-lote select option { color: var(--ink); background: var(--surface); }
  .pj-lote button { background: rgba(255,255,255,.12); color: #fff;
                    border-color: rgba(255,255,255,.22); }
  .pj-lote button:hover:not(:disabled) { background: rgba(255,255,255,.2); color: #fff; }

  /* O que falta para entregar. Âmbar de estado, nunca o laranja da marca: é
     lembrete, não ação — e nada aqui bloqueia o trabalho. */
  .pj-pend { display: flex; flex-direction: column; gap: 3px; align-items: flex-start; }
  .pj-falta { font-size: 10.5px; font-weight: 600; line-height: 1.5;
              padding: 1px 7px; border-radius: 20px; white-space: nowrap;
              background: var(--warn-bg); color: var(--warn); cursor: help; }
  /* Sem data de voo: a informação some em cinza, sem virar alarme — muito
     projeto antigo foi cadastrado antes de o campo existir. */
  .pj-datas .d1.sem-voo { color: var(--ink-3); font-style: italic; }

  /* Ações rápidas: abrir o 3D e o documento sem passar pelo cartão de preview.
     Ficam SEMPRE visíveis, a 45% — quem está aprendendo não descobre o que só
     aparece no hover. E a coluna existe mesmo vazia, senão a linha se desloca
     quando o cursor entra nela. */
  .pj-rapidas { display: flex; gap: 6px; justify-content: flex-end; }
  .pj-rapidas button {
    width: 32px; height: 32px; padding: 0; border-radius: 9px;
    display: flex; align-items: center; justify-content: center;
    border: 1px solid var(--border); background: var(--surface); color: var(--ink-2);
    /* 0.45 sumia — em toque não há hover para revelar, e o aluno não descobre
       o que não vê. Discreto, mas legível de longe. */
    opacity: .78; transition: opacity var(--t), background var(--t), color var(--t), border-color var(--t);
  }
  .pj-rapidas button svg { width: 19px; height: 19px; }
  .pj-linha:hover .pj-rapidas button { opacity: 1; border-color: var(--border); background: var(--surface); }
  .pj-rapidas button:hover { color: var(--orange); border-color: var(--orange); }
  .pj-rapidas button:disabled { opacity: .2; cursor: not-allowed; }
  .pj-linha:hover .pj-rapidas button:disabled { opacity: .28; border-color: transparent;
                                                background: none; color: var(--ink-3); }

  /* Telas estreitas: preserva identidade, situação e anomalias — o que decide
     onde olhar primeiro. Recolhe cliente e data, depois tipo e fotos. As ações
     ficam até o fim: são o motivo de a lista existir. */
  @media (max-width: 1280px) {
    .pj-lista { --pj-cols: 56px minmax(0, 2fr) 104px 118px 96px 154px 92px 76px; }
    .pj-cli, .pj-fotos { display: none; }
    .pj-cab button:nth-child(3), .pj-cab button:nth-child(6) { display: none; }
  }
  /* Abaixo de 940px o "o que falta" também recolhe: nesta largura já saíram
     tipo e anomalias, e insistir espremeria o nome do projeto, que é o que
     permite achar a linha. O aviso continua no preview e antes de gerar. */
  @media (max-width: 940px) {
    .pj-lista { --pj-cols: 56px minmax(0, 1fr) 118px 154px 76px; }
    .pj-tipo, .pj-anom, .pj-pend { display: none; }
    .pj-cab button:nth-child(2), .pj-cab button:nth-child(5) { display: none; }
  }

  /* aviso flutuante — confirma e some sozinho, sem empurrar o layout */
  /* Retorno ao usuário: um jeito só, flutuante no canto — nunca uma barra que
     empurra o conteúdo. Verde some em 3s; navy fica enquanto a tarefa corre;
     vermelho espera o OK, porque erro precisa ser lido. */
  #toast { position: fixed; right: 26px; bottom: 26px; z-index: 300; display: flex;
           align-items: center; gap: 11px; max-width: min(460px, calc(100vw - 52px));
           background: var(--navy); color: #fff; border: 1px solid rgba(255,255,255,.10);
           border-radius: 12px; padding: 12px 12px 12px 16px; font-size: 13px;
           line-height: 1.4; box-shadow: 0 14px 38px rgba(19,31,51,.38);
           opacity: 0; transform: translateY(10px); pointer-events: none;
           transition: opacity .18s, transform .18s; }
  #toast.mostra { opacity: 1; transform: none; pointer-events: auto; }
  #toast > svg { width: 18px; height: 18px; flex: none; }
  #toast > span { flex: 1; }
  #toast.ta-ok   > svg { color: var(--good-claro); }
  #toast.ta-info > svg { color: #7fb2ff; animation: giraToast 1.4s linear infinite; }
  #toast.ta-erro { background: #3b1410; border-color: rgba(255,90,69,.42); }
  #toast.ta-erro > svg { color: var(--bad-claro); }
  @keyframes giraToast { to { transform: rotate(360deg); } }
  /* Fechar discreto no verde/navy; OK explícito no erro, que pede um gesto. */
  #toast .x-faixa { width: 26px; height: 26px; padding: 0; flex: none; border: 0;
                 background: none; color: var(--tinta-esc-2); border-radius: 8px;
                 display: flex; align-items: center; justify-content: center; }
  #toast .x-faixa svg { width: 14px; height: 14px; }
  #toast .x-faixa:hover { background: rgba(255,255,255,.10); color: #fff; }
  #toast .ta-ok { height: 30px; padding: 0 14px; flex: none; font-size: 12.5px;
                  background: rgba(255,255,255,.12); border: 1px solid rgba(255,255,255,.22);
                  color: #fff; border-radius: 9px; }
  #toast .ta-ok:hover { background: rgba(255,255,255,.20); }
  /* Botão de ação do aviso — hoje só o "Desfazer" da exclusão de fotos. Mesma
     roupa do que o visualizador já usa no desfazer de anomalia e medição, para
     o gesto ser reconhecível nos dois lugares. */
  #toast .ta-acao { height: 26px; padding: 0 11px; flex: none; border-radius: 7px;
                    font-size: 12.5px; font-weight: 600;
                    background: rgba(255,255,255,.14); border: 0; color: #fff; }
  #toast .ta-acao:hover:not(:disabled) { background: rgba(255,255,255,.22); color: #fff; }
  @media (max-width: 700px) { #toast { right: 12px; left: 12px; bottom: 12px; }
  }

  /* Diálogos do produto (texto, confirmação, senha). Substituem prompt/confirm
     do navegador, que exibem o endereço do servidor e ignoram o desenho. */
  .dlg { position: fixed; inset: 0; z-index: 80; background: rgba(19,31,51,.55);
         backdrop-filter: blur(3px); display: grid; place-items: center;
         animation: dlgIn .12s ease; }
  @keyframes dlgIn { from { opacity: 0 } to { opacity: 1 } }
  .dlg-cartao { width: min(430px, 92vw); background: var(--surface);
                animation: dlgSobe .14s cubic-bezier(.2,.8,.2,1); }
  @keyframes dlgSobe { from { transform: translateY(8px) scale(.98) } to { transform: none } }

  /* Faixa de somente leitura e ocultação das ações para o papel visualizador. */
  .faixa-leitura { display: flex; align-items: center; gap: 9px; background: var(--info-bg);
                   border-bottom: 1px solid var(--info-bd); color: var(--info); font-size: 12.5px;
                   padding: 9px 26px; }
  .faixa-leitura svg { flex: none; }
  /* O BANNER DA ASSINATURA — item 379, cores do print aprovado (379-modo-leitura.html):
     amarelo na carencia (dias 0 a 3, trabalha normal), vermelho no modo leitura. Reusa a
     anatomia da .faixa-leitura porque as duas dizem a mesma coisa em registros diferentes:
     este acesso esta contido, e eis por que. */
  .faixa-leitura.assinatura-aviso { background: var(--warn-bg); border-bottom-color: var(--warn-bd);
                                    color: var(--warn); }
  .faixa-leitura.assinatura-trava { background: var(--bad-bg); border-bottom-color: var(--bad-bd);
                                    color: var(--bad); }
  .assinatura-regularizar { margin-left: auto; flex: none; }
  body.so-leitura .cta-salvarbar, body.so-leitura #salvar, body.so-leitura #excluir,
  body.so-leitura #rSalvar, body.so-leitura #rSalvarCopia, body.so-leitura .pr-conc-btn,
  body.so-leitura .pr-conc-reabrir, body.so-leitura #telaNovo, body.so-leitura #eqAdicionar,
  body.so-leitura #processar, body.so-leitura #cancelar, body.so-leitura #relPdf,
  body.so-leitura #revExcluir,
  /* 🔴 `#fichaModelo` E NAO `.esp-botoes` — item 320, 21/08/2026.
     O segmentado da ficha passou a usar `.pj-modo`, que e o componente unico; esta
     regra continuava citando a classe VELHA e, sem o conserto, o modo leitura do
     revisor voltaria a mostrar a escolha de ficha. Foi a troca de classe quebrando
     um seletor que ninguem estava olhando — e por isso o id proprio: ele nomeia
     ESTE segmentado sem prender o desenho a ele. */
  body.so-leitura #fichaModelo, body.so-leitura #baixarResultados { display: none !important; }
  body.so-leitura input, body.so-leitura select, body.so-leitura textarea { pointer-events: none;
    background: var(--inerte-bg); color: var(--ink-3); }
  .us-papel.vis { background: var(--info-bg); color: var(--info); border: 1px solid var(--info-bd); }

  /* 🔴 AQUI FICARAM DOIS CORPOS DE REGRA ÓRFÃOS POR TRÊS DIAS, e eles mataram a
     MOLDURA DE TODO DIÁLOGO DO APP — item 360, 24/08/2026.

     O item 320 tirou `.btn-verde` e `.btn-azul` do catálogo de botões e apagou a
     PRIMEIRA linha de cada regra, deixando a segunda solta:

         display: inline-flex; align-items: center; gap: 7px; }

     Declaração sem seletor e sem chave de abrir. O Chromium descarta até se
     recuperar — e o que ele engoliu foi EXATAMENTE a regra seguinte, medido: a
     `.dlg-cartao` logo abaixo, com `position: relative`, `padding`, `border-radius`,
     a sombra e o `max-height: 90vh`.

     ⚠️ **O pior não era o recheio: era o `position: relative`.** Sem ele o `.dlg-x`
     (`absolute; top:14px; right:14px`) se posiciona contra o `.dlg`, que é `fixed` —
     e o botão de FECHAR de todo diálogo ia para o alto da TELA. Medido: X em y=14
     com o cartão em y=198,7, **185px acima do próprio diálogo**.

     E o `max-height: 90vh; overflow-y: auto` morreu junto: era ele que impedia um
     diálogo mais alto que a janela de ser cortado nas DUAS pontas.

     **Apagar CSS é apagar a regra INTEIRA.** Meia regra não dá erro nenhum: ela
     envenena a vizinha, e o sintoma aparece longe da causa. */

  /* ============== MOLDURA PADRÃO DE TODO MODAL ============================
     Um modal do Sherlock tem sempre a mesma anatomia e as mesmas folgas:

       recheio do cartão .... 26px nas laterais, 22px em cima, 22px embaixo
       título ............... 17px Montserrat, navy, com folga de 40px à direita
                              para o X não encostar
       texto de apoio ....... 13px, --ink-2, 16px abaixo do título
       barra de ações ....... encostada à direita, 8px entre botões, filete acima
       fechar ............... 32px redondo, SEMPRE a 14px do topo e da direita
       largura .............. 430px (aviso), 470px (formulário), 1040px (planos)

     Antes cada diálogo tinha o seu: recheios de 24/26, 28/26, 20/22 e 16/18,
     quatro larguras, e só um dos cinco tinha botão de fechar. */
  .dlg-cartao { position: relative; padding: 22px 26px; border-radius: 12px;
                box-shadow: var(--sh-modal);
                /* TETO DE ALTURA, PARA TODO DIALOGO DO APP.
                   Sem ele, dialogo mais alto que a janela e cortado NAS DUAS PONTAS: o `.dlg`
                   centra com `place-items: center`, e o que passa some para cima e para
                   baixo — inclusive o titulo e o botao de fechar. Ninguem tinha esbarrado
                   nisso porque nenhum dialogo era alto; o Detalhes da tela Motor foi o
                   primeiro, e ele mostrou o defeito de todos. */
                max-height: 90vh; overflow-y: auto; }
  /* O dialogo LARGO: para conteudo que 430px espreme. Hoje so o Detalhes. */
  .dlg-cartao.largo { width: min(820px, 94vw); }
  /* O SELO DO SEGUNDO FATOR na Conta, item 381: verde ligado, cinza desligado. */
  .sf-selo { display: inline-flex; align-items: center; height: 22px; padding: 0 10px;
             border-radius: 11px; font-size: 12px; font-weight: 600;
             background: var(--surface-2, #eef1f5); color: #6b7280; }
  .sf-selo.ligado { background: var(--good-bg); color: var(--good); }
  /* A linha "Exigir o segundo fator de toda a equipe", item 381, embaixo da Equipe. */
  .eq-2fa { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap;
            margin-top: var(--s3); padding-top: var(--s3); border-top: 1px solid #e5e7eb; }
  /* E o MEDIO, para as tres qualidades: em 430px a descricao quebrava em quatro
     linhas e a coluna do tempo em tres. E a largura do print que ele aprovou. */
  .dlg-cartao.medio { width: min(500px, 94vw); }
  /* O DIALOGO DO PIN — item 302, aprovado por print em 21/08. O mapa dentro do
     dialogo da casa (usa o `largo`); 300px de mapa e o que o print mostrou, e cabe
     nos 738px do notebook dele com o nome e as acoes embaixo. */
  .pin-busca { display: flex; gap: 8px; margin-bottom: 10px; }
  .pin-busca input { flex: 1; }
  .pin-mapa { height: 300px; border-radius: 10px; overflow: hidden; background: #e6e9f0; }
  .pin-nota { display: block; color: var(--ink-3); font-size: 11.5px; margin-top: 4px; }
  .pin-linha { display: flex; align-items: center; gap: 12px; }
  .pin-linha .vazio { flex: 1; }
  /* A VISTA MAPA de Projetos — item 306. A altura é a janela menos o topo da tela:
     nos 738px do notebook dele sobra ~420px de mapa, e ele nao rola. */
  .pj-mapa { position: relative; height: clamp(300px, calc(100vh - 350px), 680px);
             border-radius: 12px; overflow: hidden; background: #e6e9f0; }
  .pj-mapa-sem { position: absolute; left: 12px; bottom: 12px; z-index: 900;
                 background: rgba(19,31,51,.88); color: #dfe6f2; font-size: 12px;
                 padding: 7px 12px; border-radius: 9px; }
  .pj-mapa-sem u { color: var(--warn-claro); }
  .pj-pop b { display: block; font-size: 13px; margin-top: 6px; }
  .pj-pop small { display: block; color: var(--ink-3); margin: 2px 0 8px; }
  .pj-pop .pj-pop-capa { width: 100%; height: 72px; object-fit: cover; border-radius: 8px; }
  .pj-pop button.principal { width: 100%; }

  /* ================ PLANOS: página de vendas ==============================
     Não é uma lista de opções, é uma decisão de compra. Cabeçalho navy com a
     pergunta que o cliente se faz, quatro colunas comparáveis linha a linha,
     preço grande, o recomendado elevado e com fita. */
  /* 1200 e nao 1040 desde 10/08/2026: os planos passaram de quatro para CINCO quando o
     teste de 14 dias entrou, e a quinta coluna caia sozinha numa segunda fileira. Ele
     pediu todos na mesma linha, e esta e a largura que da coluna legivel para cinco sem
     passar da tela estreita dele (1536 de viewport, ver CLAUDE.md). */
  /* 🔴 `hidden auto`, E NÃO `hidden` — item 364, 24/08/2026.
     Ele viu: *"no notebook a tela planos não aparece inteira, talvez pudesse ter um
     scroll"*. Medido a 1536x738: a caixa para em **664px** (o `max-height: 90vh` do
     `.dlg-cartao`) e o conteúdo pede **771** — **106px ficavam INALCANÇÁVEIS**, e na
     tela dele, mais baixa, é pior.
     O `overflow: hidden` estava aqui por uma razão boa: o canto arredondado não pode
     vazar sobre o hero navy. Mas ele cancela o `overflow-y: auto` que o `.dlg-cartao`
     declara, e aí o teto de altura vira uma tesoura em vez de uma rolagem.
     ⚠️ `hidden auto` resolve os dois: recorta o que passa dos lados, e rola o que passa
     embaixo. Recortar em UM eixo não obriga a recortar no outro — foi essa a confusão. */
  .pl-dlg { width: min(1200px, 96vw); padding: 0 !important; overflow: hidden auto; }
  .pl-dlg::before { display: none; }          /* o hero navy já é o topo */
  .pl-hero { position: relative; background: linear-gradient(135deg, var(--navy-3) 0%, var(--navy-4) 100%);
             color: #fff; padding: 30px 34px 28px; text-align: center; }
  .pl-hero::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0;
                    height: 3px; background: var(--orange); }
  .pl-dlg .pl-hero h3 { color: #fff; font-size: 24px; margin: 0 0 10px; padding: 0;
                        letter-spacing: -.02em; line-height: 1.2; }
  /* margin-left/right auto centram o BLOCO; text-align centra o texto dentro
     dele. Sem os dois, um parágrafo estreito fica colado à esquerda mesmo com
     o texto "centralizado" — foi o que aconteceu aqui. */
  /* 66ch quebrava o texto em três linhas dentro de um hero de 1040px — sobrava
     largura de sobra dos dois lados. 88ch usa o espaço e fecha em duas. */
  .pl-dlg .pl-hero p { color: #a9bad2; font-size: 13px; line-height: 1.6;
                       margin-left: auto; margin-right: auto; margin-bottom: 0;
                       max-width: 88ch; text-align: center; }
  /* Mesmo 14/14 dos demais: a distância do canto é a mesma em todo modal. */

  /* QUANTAS COLUNAS = QUANTOS PLANOS, e o numero vem do JS em `--pl-n`.
     Estava cravado em 4, e o dia em que o teste de 14 dias entrou a grade passou a mostrar
     4 + 1 numa fileira solta embaixo — sem ninguem mexer nesta linha. Numero de coluna
     escrito a mao e uma afirmacao sobre os DADOS feita no CSS; ela envelhece no primeiro
     plano novo, e envelhece em silencio. `minmax(0, 1fr)` e obrigatorio junto: com `1fr`
     puro a coluna nao encolhe abaixo do conteudo e a grade estoura para fora do modal. */
  .pl-grade { display: grid; grid-template-columns: repeat(var(--pl-n, 4), minmax(0, 1fr));
              gap: 14px; padding: 30px 26px 22px; align-items: start; }
  .pl-col { position: relative; border: 1px solid var(--border); border-radius: 12px;
            padding: 22px 18px 18px; background: var(--surface);
            transition: border-color var(--t), box-shadow var(--t), transform var(--t); }
  .pl-col:hover { border-color: var(--border-hover); box-shadow: var(--sh-2); }
  /* O recomendado sobe e ganha contorno: destaque de verdade, não uma etiqueta. */
  .pl-col.destaque { border-color: var(--orange); box-shadow: 0 0 0 2px var(--orange),
                     0 10px 30px rgba(255,101,1,.16); transform: translateY(-8px);
                     padding-bottom: 26px; }
  .pl-col.atual { background: var(--surface-2); border-color: var(--navy-2); }
  .pl-fita { position: absolute; top: -11px; left: 50%; transform: translateX(-50%);
             background: var(--orange); color: #fff; font-size: 10px; font-weight: 700;
             letter-spacing: .07em; text-transform: uppercase; padding: 4px 12px;
             border-radius: 20px; white-space: nowrap; box-shadow: 0 3px 10px rgba(255,101,1,.34); }
  .pl-fita.atual { background: var(--navy); box-shadow: none; }
  .pl-cab { min-height: 62px; margin-bottom: 14px; }
  .pl-col h4 { font-family: var(--brand); font-weight: 700; font-size: 16px;
               color: var(--navy); margin: 0 0 5px; }
  .pl-cab p { font-size: 11.5px; color: var(--ink-3); line-height: 1.45; margin: 0; }
  /* 52px é a altura natural de "R$ 489 / por mês". "Sob consulta" é 20px em vez
     de 30 e media 42 — os 10px de diferença empurravam o botão da última coluna
     para cima, e quatro ações que deveriam estar na mesma linha saíam em três
     alturas. Fixar aqui alinha sem tocar em nenhuma coluna específica. */
  .pl-preco { margin-bottom: 16px; min-height: 52px; }
  .pl-preco b { display: block; font-family: var(--brand); font-weight: 800; font-size: 30px;
                color: var(--navy); line-height: 1; font-variant-numeric: tabular-nums;
                letter-spacing: -.02em; }
  .pl-preco span { display: block; font-size: 11px; color: var(--ink-3); margin-top: 5px; }
  /* "Grátis" fica do TAMANHO DO PREÇO (30px), e não do "Sob consulta" (20px): é a mesma
     informação que "R$ 149" — o que custa —, e encolhê-la faria a única coluna sem
     barreira de entrada parecer a menos importante da fileira. Verde porque é a boa
     notícia da tela, e é o mesmo verde dos "✓" do rodapé. */
  .pl-gratis { color: var(--good) !important; }
  /* Só a largura: altura, raio, fonte e preenchimento vêm da regra base de
     botão, que agora também vale para `a.btn`. */
  .pl-btn { width: 100%; justify-content: center; }
  .pl-atual-sel { display: block; text-align: center; height: 38px; line-height: 36px;
                  font-size: 12.5px; font-weight: 600; color: var(--ink-3);
                  background: var(--surface); border: 1px dashed var(--border);
                  border-radius: 9px; }
  .pl-linhas { margin-top: 18px; padding-top: 4px; border-top: 1px solid var(--hair); }
  .pl-linhas > div { display: flex; justify-content: space-between; align-items: baseline;
                     gap: 8px; padding: 7px 0; border-bottom: 1px solid var(--hair); }
  .pl-linhas > div:last-child { border-bottom: 0; }
  .pl-linhas span { font-size: 11.5px; color: var(--ink-3); }
  .pl-linhas i { font-style: normal; font-size: 12px; color: var(--ink-2);
                 font-variant-numeric: tabular-nums; white-space: nowrap; }
  .pl-linhas i b { font-size: 13px; color: var(--ink); font-weight: 700; }

  .pl-rodape { border-top: 1px solid var(--border); background: var(--surface-2);
               padding: 16px 26px 20px; }
  .pl-rodape p { margin: 0; font-size: 11.5px; color: var(--ink-3); line-height: 1.5;
                 text-align: center; }
  .pl-dlg .dlg-erro { margin: 0 26px 12px; }
  /* Abaixo de 1240 nao cabe cinco: as quebras usam numero fixo de proposito, porque aqui a
     conta e de ESPACO e nao de quantos planos existem. O `!important` nao e preguica — o
     `--pl-n` vem do elemento (atributo `style`), e sem ele a media query perderia. */
  @media (max-width: 1240px) { .pl-grade { grid-template-columns: repeat(3, minmax(0, 1fr)) !important; }
  }
  @media (max-width: 940px) { .pl-grade { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
                              .pl-col.destaque { transform: none; }
  }
  @media (max-width: 560px) { .pl-grade { grid-template-columns: 1fr !important; }
  }

  /* ================ FECHAR: UM SÓ, PARA TODO MODAL ========================
     Havia três desenhos convivendo: um "✕" de texto em caixa quadrada, um
     círculo escuro translúcido sobre a capa, e um quadrado claro nos diálogos.
     Passa a existir um só, em duas peles:

       .x-fecha          claro  — sobre fundo branco (a maioria dos diálogos)
       .x-fecha.sobre-foto escuro — sobre imagem, onde o claro sumiria

     32×32, redondo, ✕ de 15px centrado no traço. Novo modal usa esta classe;
     não desenhe outro.

     ## O CATÁLOGO INTEIRO DO GESTO "FECHAR" — item 324, 21/08/2026

     São DUAS classes, e não cinco. Contei cinco de cabeça no fecho do item 320 e o
     inventário me desmentiu — que é a regra desta casa, e a razão de ela existir:

       .x-fecha        32px, redondo. O botão de fechar de MODAL e de painel.
                       Peles: (padrão, claro) e `.sobre-foto` (escuro sobre imagem).
       .x-faixa        26px, quadrado arredondado. O X dentro de uma FAIXA que já é
                       colorida — o `#toast` e o `#mensagem`. A cor vem do contexto,
                       porque a faixa muda de cor conforme o recado.

     E DUAS que NÃO são vestes, apesar do nome parecido:

       .dlg-x          só POSIÇÃO (`absolute; top:14px; right:14px`). Modificador que se
                       põe em cima do `.x-fecha`, como os pesos do `btn-p` — prefixá-lo de
                       outro jeito faria parecer que é outro botão.
       .pv-x           era só GANCHO de JS, para o `querySelector` achar o X do preview.
                       **Morreu**: naquele overlay há um X só, e o canônico já o identifica.
                       Classe que existe para ser encontrada engorda o catálogo sem
                       desenhar nada.

     ⚠️ **Por que `.x-faixa` não virou uma pele do `.x-fecha`:** o tamanho é outro (26 contra
     32) e a cor é HERDADA da faixa, não declarada. Uma pele que muda tamanho e abre mão da
     cor não é a mesma peça com outra roupa — é outra peça, e fingir o contrário faria a
     próxima pessoa achar que pode usar 32px dentro do toast. */
  .x-fecha { width: 32px; height: 32px; flex: none; padding: 0; border-radius: 50%;
             display: inline-flex; align-items: center; justify-content: center;
             border: 1px solid var(--border); background: var(--surface);
             color: var(--ink-3); cursor: pointer;
             transition: background var(--t), color var(--t), border-color var(--t), transform var(--t); }
  .x-fecha svg { width: 15px; height: 15px; display: block; }
  .x-fecha:hover { background: var(--surface-2); color: var(--ink);
                   border-color: var(--border-hover); transform: scale(1.06); }
  .x-fecha:active { transform: none; }
  .x-fecha.sobre-foto { border-color: transparent; background: rgba(10,18,32,.5);
                        color: #fff; backdrop-filter: blur(4px); }
  .x-fecha.sobre-foto:hover { background: rgba(10,18,32,.78); color: #fff;
                              border-color: transparent; }

  /* ============ TODO MODAL: fechar no canto, e mais presença ==============
     O fechar fica SEMPRE no canto superior direito do cartão, montado pelo
     _dlgBase — antes, de cinco modais só um tinha X, e cada um em um lugar.
     O cartão ganhou barra laranja no topo e um título mais forte: estavam
     todos brancos e sem hierarquia. */
  .dlg-cartao::before { content: ""; position: absolute; top: 0; left: 0; right: 0;
                        height: 3px; background: var(--orange);
                        border-radius: 12px 12px 0 0; }
  .dlg-x { position: absolute; top: 14px; right: 14px; z-index: 2; }
  .dlg-cartao h3 { font-family: var(--brand); font-weight: 700; font-size: 16px;
                   color: var(--navy); margin: 0 0 6px; padding-right: 40px;
                   letter-spacing: -.01em; }
  .dlg-cartao > p { color: var(--ink-2); font-size: 13px; line-height: 1.55;
                    margin: 0 0 var(--s4); }
  .dlg-acoes { display: flex; justify-content: flex-end; gap: var(--s2);
               margin-top: var(--s5); padding-top: var(--s4);
               border-top: 1px solid var(--hair); }
  /* O de usuário tem cabeçalho navy próprio: lá o X vai em cima dele, claro. */
  .dlg-usuario { padding-top: 0; }
  /* Fechar no padrão claro: o topo agora é claro. */

  /* Convite por e-mail no diálogo de usuário. Fica desligado e explicado
     enquanto o SMTP não estiver configurado — melhor do que sumir e deixar o
     dono procurando onde ativa. */
  /* Entrega do convite: os dois caminhos que NÃO exigem configuração vêm
     primeiro, lado a lado. O envio automático fica embaixo, como opção. Exigir
     servidor SMTP para mandar dois convites é trabalho desproporcional. */
  /* Texto longo para copiar: fonte de largura fixa, para o alinhamento das
     linhas do convite não desandar. */
  .copiavel { width: 100%; font: 12.5px/1.6 ui-monospace, Consolas, monospace;
              resize: vertical; min-height: 150px; }

  .du-entrega { margin-top: var(--s4); }
  .du-entrega > label { display: block; font-size: 11px; font-weight: 600;
                        letter-spacing: .04em; text-transform: uppercase;
                        color: var(--ink-3); margin-bottom: 7px; }
  .du-opcoes { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
  .du-op { height: auto; flex-direction: column; align-items: flex-start; gap: 1px;
           padding: 9px 12px; text-align: left; background: var(--surface-2); }
  .du-op:hover:not(:disabled) { border-color: var(--orange); background: var(--sel-bg); }
  .du-op svg { width: 16px; height: 16px; color: var(--orange); margin-bottom: 2px; }
  .du-op b { font-size: 12.5px; color: var(--ink); font-weight: 600; }
  .du-op small { font-size: 10.5px; color: var(--ink-3); line-height: 1.35; font-weight: 400; }

  /* ============ BLOCO DOS DADOS EXIGIDOS PELA NORMA =======================
     Muitos campos em grupos curtos, com subtítulo por assunto: a edificação,
     a inspeção, a documentação, o voo e o que NÃO foi inspecionado. A fração
     no título responde "quanto falta" sem precisar gerar o PDF. */
  .norma-sub { font-family: var(--brand); font-weight: 700; font-size: 11px;
               letter-spacing: .07em; text-transform: uppercase; color: var(--ink-2);
               margin: var(--s5) 0 var(--s3); padding-bottom: 5px;
               border-bottom: 1px solid var(--hair); display: flex;
               align-items: baseline; gap: 9px; flex-wrap: wrap; }
  .norma-sub:first-of-type { margin-top: 0; }
  .norma-sub small { font-family: var(--ui); font-weight: 400; font-size: 11px;
                     letter-spacing: 0; text-transform: none; color: var(--ink-3); }
  /* GSD medido do modelo, logo abaixo do campo. Verde de ESTADO (não o laranja
     da ação): é uma constatação — "isto foi medido" —, não um botão que pede
     clique. O botão dentro dela é o compacto padrão. */
  .gsd-medido { display: flex; align-items: center; gap: 9px; margin-top: -4px;
                background: var(--good-bg); border-radius: 9px; padding: 8px 12px;
                font-size: 12px; color: var(--ink-2); }
  .gsd-medido b { color: var(--good); font-variant-numeric: tabular-nums; }
  .gsd-medido small { display: block; color: var(--ink-3); font-size: 11px;
                      font-variant-numeric: tabular-nums; }
  .gsd-medido em { margin-left: auto; font-style: normal; color: var(--good);
                   font-size: 11.5px; font-weight: 600; }
  .gsd-medido button { margin-left: auto; flex: none; }
  .gsd-ponto { width: 8px; height: 8px; border-radius: 50%; background: var(--good);
               flex: none; }

  /* O campo do "não inspecionado" é o que mais protege o profissional: ganha
     destaque de aviso, não de campo comum. */
  .norma-aviso { margin: var(--s3) 0 0 !important; font-size: 11.5px !important;
                 background: var(--warn-bg); border-left: 3px solid var(--warn);
                 border-radius: 0 8px 8px 0; padding: 10px 13px; line-height: 1.5; }

