/* components.css - botoes, cards, forms, tabela, selectbusca, modal, loading, flash. */

/* ============ [hidden] vence QUALQUER display (regra global) ============
   O atributo [hidden] e display:none do NAVEGADOR, e uma folha de usuario perde
   para qualquer display declarado numa classe: .vz e flex, .pg-loading e flex,
   .campo e flex, .bx-valores e grid. Sem esta regra, marcar hidden nao tira nada
   da tela - o elemento continua visivel e o codigo parece funcionar, porque a
   PROPRIEDADE .hidden do DOM esta correta e so o pixel mente.

   Nasceu global em 2026-08-12, depois de a listagem paginada aparecer com a
   tabela cheia E os dois estados vazios E o spinner empilhados na mesma tela
   (relato do Ricardo, com print). O projeto ja vinha remendando classe a classe
   (.campo, .bx-opt, .itens-grid, .badge-doc, .imp-resultado): remendo por classe
   so adia o proximo esquecimento, entao a regra passou a valer para todas. */
[hidden] { display: none !important; }

/* ============ Botoes ============ */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  min-height: 38px; padding: 8px 14px; border-radius: var(--raio-sm);
  border: 1px solid var(--borda-forte); background: var(--branco); color: var(--texto);
  font-size: 13px; font-weight: 600; cursor: pointer; transition: all var(--transicao);
  white-space: nowrap; text-decoration: none;
}
.btn:hover { background: var(--fundo); text-decoration: none; }
.btn:disabled { opacity: .55; cursor: not-allowed; }
.btn i { font-size: 16px; }
.btn-primario { background: var(--cor-primaria); border-color: var(--cor-primaria); color: var(--texto-sobre-primaria); }
.btn-primario:hover { background: var(--cor-primaria-escura); color: var(--texto-sobre-primaria); }
.btn-perigo { background: var(--erro); border-color: var(--erro); color: var(--branco); }
.btn-perigo:hover { filter: brightness(.94); color: var(--branco); }
.btn-fantasma { background: transparent; border-color: transparent; color: var(--texto-secundario); }
.btn-fantasma:hover { background: var(--fundo); color: var(--texto); }
.btn-sm { min-height: 32px; padding: 6px 10px; font-size: 12px; }
.btn-icone {
  width: 25px; height: 25px; min-height: 0; padding: 0; border-radius: var(--raio-sm);
  display: inline-grid; place-items: center; background: var(--branco); border: 1px solid var(--borda);
  color: var(--texto-secundario); cursor: pointer;
}
/* Tamanho do icone declarado aqui, e nao herdado: <a class="btn-icone"> pega o
   font-size da pagina (14px) e <button class="btn-icone"> pega o do navegador
   (13.3px), entao a mesma fileira de acoes saia com o primeiro icone maior que
   os outros. line-height: 1 tira o espaco extra da linha, que desloca o glifo
   dentro da caixa mesmo com a caixa centralizada. */
/* O <i> ocupa o botao inteiro e centraliza o glifo por flex. Assim o centro nao
   depende das metricas da fonte (ascent/descent), que e o que deixa o desenho
   meio pixel fora quando se confia so no place-items do botao. */
.btn-icone i {
  font-size: 16px; line-height: 1;
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
}
.btn-icone:hover { border-color: var(--cor-primaria); color: var(--cor-primaria); }
.btn-icone.perigo:hover { border-color: var(--erro); color: var(--erro); }

/* ============ Card / caixa ============ */
.card {
  background: var(--branco); border: 1px solid var(--borda); border-radius: var(--raio);
  box-shadow: var(--sombra);
}
.card-cab { padding: 16px 20px; border-bottom: 1px solid var(--borda); display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.card-cab h2, .card-cab h3 { font-size: 15px; }
.card-corpo { padding: 20px; }
.grid-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 16px; }

/* ============ Formularios ============ */
.campo { display: flex; flex-direction: column; gap: 5px; margin-bottom: 14px; }
.campo > label, .sf-usuario-titulo {
  font-size: 11px; font-weight: 700; color: var(--texto-secundario);
  text-transform: uppercase; letter-spacing: .04em;
}
.input, .textarea {
  width: 100%; height: 40px; padding: 9px 12px; border: 1px solid var(--borda-forte);
  border-radius: var(--raio-sm); background: var(--branco); color: var(--texto);
  transition: border-color var(--transicao), box-shadow var(--transicao);
}
.textarea { height: auto; min-height: 90px; resize: vertical; }
.input:focus, .textarea:focus { outline: none; border-color: var(--cor-primaria); box-shadow: 0 0 0 3px var(--cor-primaria-suave); }
.input::placeholder { color: var(--texto-fraco); }

/* 16px no celular, e so nele. O iOS Safari da ZOOM na pagina quando o campo que
   recebe o foco tem fonte MENOR que 16px, e depois do zoom o usuario fica com a
   tela deslocada, sem como voltar sozinho. Nao e escolha estetica: e o que impede
   o campo de empurrar a pagina. No desktop o controle segue nos 13px do resto da
   interface, junto com o label e o .btn.
   Vai no elemento e nao em `.input` porque a maioria dos campos do projeto nao
   carrega essa classe. `button` fica de fora de proposito: nao recebe digitacao,
   entao nao provoca zoom, e mudar ali mexeria em todo botao do sistema.
   Regra Responsividade_Sempre da matriz, no breakpoint 720 que o projeto ja usa. */
@media (max-width: 720px) {
  input, select, textarea { font-size: 16px; }
}
.linha-campos { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.dica { font-size: 12px; color: var(--texto-suave); }
/* Dica em bloco (paragrafo explicativo dentro do modal) e dica presa a uma celula. */
.dica-bloco { display: block; line-height: 1.5; margin: 0 0 14px; }
.dica-inline { display: block; font-size: 12px; color: var(--texto-suave); margin-top: 2px; }
/* Registro desativado na listagem: presente no historico, fora da projecao. */
.te-tab tbody tr.linha-inativa td { color: var(--texto-suave); background: var(--fundo-2); }

/* Barra de formulario/filtros (Padrao_Formulario): tudo 40px, botao alinhado pela base */
.ra-bar {
  display: flex; gap: 14px; align-items: flex-end; flex-wrap: wrap;
  background: var(--branco); border: 1px solid var(--borda); border-radius: var(--raio);
  padding: 14px 18px; margin-bottom: 16px;
}
.ra-bar .campo { margin-bottom: 0; }
.ra-bar .input, .ra-bar .selectbusca, .ra-bar .selectbusca .sb-display, .ra-bar > .btn {
  height: 40px; box-sizing: border-box;
}
.ra-bar .input { min-width: 220px; }
.ra-bar .selectbusca { min-width: 180px; }

/* ============ SelectBusca (Sem_Select_Nativo) ============ */
.selectbusca { position: relative; min-width: 200px; }
.selectbusca .sb-display {
  height: 40px; padding: 9px 12px; background: var(--branco); border: 1px solid var(--borda-forte);
  border-radius: var(--raio-sm); cursor: pointer; display: flex; justify-content: space-between;
  align-items: center; gap: 8px; color: var(--texto);
}
.selectbusca .sb-display:hover { border-color: var(--borda-forte); }
.selectbusca.open .sb-display { border-color: var(--cor-primaria); box-shadow: 0 0 0 3px var(--cor-primaria-suave); }
.selectbusca .sb-label.vazio { color: var(--texto-fraco); }
.selectbusca .sb-panel {
  position: absolute; top: 100%; left: 0; right: 0; z-index: var(--z-lista); background: var(--branco);
  border: 1px solid var(--borda); border-radius: var(--raio-sm); margin-top: 4px;
  box-shadow: var(--sombra-md); max-height: 280px; overflow-y: auto; display: none; /* aberto, e fixed pelo selectbusca.js (decisao 133), que le este max-height */
}
.selectbusca.open .sb-panel { display: block; }
.selectbusca .sb-search { width: 100%; padding: 10px 12px; background: var(--branco); border: none; border-bottom: 1px solid var(--borda); color: var(--texto); outline: none; }
.selectbusca .sb-opt { padding: 9px 12px; cursor: pointer; font-size: 13.5px; }
.selectbusca .sb-opt:hover, .selectbusca .sb-opt.destacado { background: var(--cor-primaria-suave); color: var(--cor-primaria-escura); }
.selectbusca .sb-opt.selecionado { font-weight: 600; }
.selectbusca .sb-vazio { padding: 12px; color: var(--texto-fraco); font-size: 13px; text-align: center; display: none; }

/* ============ Tabela + ferramentas (Tabela_Sempre_com_Ferramentas) ============ */
/* O card da tabela NAO recorta o proprio conteudo, de proposito. O overflow:
   hidden que vivia aqui existia so para o border-radius aparar os cantos da
   tabela, e desde que o menu sanduiche passou a morar DENTRO do card (no
   .tabela-topo) ele cortava o popup do menu: com a tabela curta, a lista de
   Colunas ou o botao Aplicar do Ordenar ficavam fora da area visivel e sem
   clique. Quem recorta agora e a area de ROLAGEM, que ja tem overflow proprio,
   e por isso o arredondamento das pontas desceu para ela. Regra e incidente:
   Padrao_Cabecalho_da_Tabela, secao "A armadilha do overflow", na vault. */
.tabela-wrap { background: var(--branco); border: 1px solid var(--borda); border-radius: var(--raio); box-shadow: var(--sombra); }
.tabela-topo { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-bottom: 1px solid var(--borda); border-top-left-radius: var(--raio); border-top-right-radius: var(--raio); }
.tabela-topo .busca { flex: 1; max-width: 340px; }
.tabela-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* [CABECALHO FIXO] Card e cabecalho da tabela no modelo de rolagem invertida
   (motivo e condicao em layout.css, "Listagem de cabecalho fixo"). O seletor
   longo E a condicao: .tabela-wrap filho direto de main.pagina sem o opt-out
   .pagina-rola e SEM conteudo em fluxo depois dele. Os irmaos que podem vir
   depois sem desligar o encolhimento sao os que nao ocupam a coluna: o rodape
   de paginacao (.pg-rodape, que fica no pe e e parte da listagem), modais e
   dialogs (fora do fluxo), scripts, templates, o estado vazio irmao (.vz) e o
   que esta hidden. Qualquer outro bloco depois do card (outro card, outra
   tabela, um aviso) desliga o encolhimento DESSE card: senao ele seria
   espremido pelo bloco de baixo ate sumir (a tela de aging perdeu a tabela de
   detalhe para 7px assim, na primeira medicao) e a tela segue rolando o
   documento como antes. Nao ha classe de ativacao porque a ativacao e
   automatica; quem quiser desligar numa tela declara o bloco pagina_classe.

   O card vira coluna flex com min-height:0 para poder encolher abaixo do
   conteudo; dentro dele, a faixa de busca (.tabela-topo), o rodape (.tabela-info)
   e os estados vazios ficam com a altura propria, e a .tabela-scroll (a UNICA
   com min-height:0) e quem cede e rola. O overflow continua na area de rolagem,
   nunca no card: o popup do menu sanduiche mora no .tabela-topo e o card com
   overflow o cortaria (Padrao_Cabecalho_da_Tabela, "A armadilha do overflow").

   O sticky vai no <thead> inteiro, nao nos <th>: a linha de filtros por coluna
   (.ta-filtro-row) e uma SEGUNDA linha do cabecalho e grudaria por cima da
   primeira se cada <th> tivesse o proprio top:0. z-index 3: acima das linhas e
   ABAIXO do popup do menu (60) e do painel do SelectBusca (50), que precisam
   passar por cima do cabecalho. A borda de baixo do <th> vira box-shadow porque
   com border-collapse a borda nao acompanha o sticky e some ao rolar.

   Piso de altura por NUMERO DE LINHAS, sempre abaixo da altura natural (linha de
   ~37px mais o cabecalho): um min-height unico abriria espaco vazio dentro do
   card de duas linhas, e sem piso nenhum o caso degenerado (o que esta acima do
   card nao coube na janela, a barra de filtros de cinco campos no celular)
   espremeria a tabela ate zero. Com o piso, sobra uma janela util de linhas e o
   documento volta a rolar como antes nesse caso. Seis linhas ou mais: 240px. */
.pagina:has(> .tabela-wrap):not(.pagina-rola) > .tabela-wrap:not(:has(~ :not(.pg-rodape, .modal-bg, .vz, dialog, script, template, [hidden]))) {
  display: flex; flex-direction: column; flex: 0 1 auto; min-height: 0;
}
.pagina:has(> .tabela-wrap):not(.pagina-rola) > .tabela-wrap:not(:has(~ :not(.pg-rodape, .modal-bg, .vz, dialog, script, template, [hidden]))) > .tabela-scroll {
  flex: 0 1 auto; min-height: 0; overflow-y: auto;
}
.pagina:has(> .tabela-wrap):not(.pagina-rola) > .tabela-wrap:not(:has(~ :not(.pg-rodape, .modal-bg, .vz, dialog, script, template, [hidden]))) > .tabela-scroll:has(> table > tbody > tr:nth-child(1)) { min-height: 60px; }
.pagina:has(> .tabela-wrap):not(.pagina-rola) > .tabela-wrap:not(:has(~ :not(.pg-rodape, .modal-bg, .vz, dialog, script, template, [hidden]))) > .tabela-scroll:has(> table > tbody > tr:nth-child(2)) { min-height: 95px; }
.pagina:has(> .tabela-wrap):not(.pagina-rola) > .tabela-wrap:not(:has(~ :not(.pg-rodape, .modal-bg, .vz, dialog, script, template, [hidden]))) > .tabela-scroll:has(> table > tbody > tr:nth-child(3)) { min-height: 130px; }
.pagina:has(> .tabela-wrap):not(.pagina-rola) > .tabela-wrap:not(:has(~ :not(.pg-rodape, .modal-bg, .vz, dialog, script, template, [hidden]))) > .tabela-scroll:has(> table > tbody > tr:nth-child(4)) { min-height: 165px; }
.pagina:has(> .tabela-wrap):not(.pagina-rola) > .tabela-wrap:not(:has(~ :not(.pg-rodape, .modal-bg, .vz, dialog, script, template, [hidden]))) > .tabela-scroll:has(> table > tbody > tr:nth-child(5)) { min-height: 200px; }
.pagina:has(> .tabela-wrap):not(.pagina-rola) > .tabela-wrap:not(:has(~ :not(.pg-rodape, .modal-bg, .vz, dialog, script, template, [hidden]))) > .tabela-scroll:has(> table > tbody > tr:nth-child(6)) { min-height: 240px; }
.pagina:has(> .tabela-wrap):not(.pagina-rola) > .tabela-wrap:not(:has(~ :not(.pg-rodape, .modal-bg, .vz, dialog, script, template, [hidden]))) > .tabela-scroll > table > thead {
  position: sticky; top: 0; z-index: 3;
}
.pagina:has(> .tabela-wrap):not(.pagina-rola) > .tabela-wrap:not(:has(~ :not(.pg-rodape, .modal-bg, .vz, dialog, script, template, [hidden]))) > .tabela-scroll > table > thead th {
  box-shadow: inset 0 -1px 0 var(--borda);
}
/* Pontas de CIMA: no card sem faixa de titulo (a grade do orcamento), quem
   encosta na borda superior e a propria rolagem, e o <thead> tem fundo. */
.tabela-wrap > .tabela-scroll:first-child {
  border-top-left-radius: var(--raio); border-top-right-radius: var(--raio);
}
/* Pontas de BAIXO: so quando a rolagem e o ultimo bloco RENDERIZADO do card.
   Em longhand para compor com a regra de cima, nunca sobrescrever.
   A primeira regra pega o caso simples; a segunda pega o card paginado, onde
   .vz e .pg-loading vem depois no HTML mas nascem hidden (display none), o que
   deixa a rolagem visualmente por ultimo sem ser :last-child. Sao duas regras
   separadas de proposito: lista com seletor invalido cai inteira, e navegador
   sem :has() perderia tambem o caso simples. */
.tabela-wrap > .tabela-scroll:last-child {
  border-bottom-left-radius: var(--raio); border-bottom-right-radius: var(--raio);
}
.tabela-wrap:not(:has(> .tabela-info)) > .tabela-scroll {
  border-bottom-left-radius: var(--raio); border-bottom-right-radius: var(--raio);
}

/* [BARRA DE CIMA] Segunda barra de rolagem horizontal, colada por BAIXO do
   <thead> (pedido do Ricardo, 2026-09-07). Numa grade larga (o orcamento tem 14
   colunas) a unica barra fica no PE do quadro, longe do cabecalho com que a
   pessoa esta se guiando. Esta e a MESMA rolagem, espelhada: quem rola continua
   sendo a .tabela-scroll.

   Quem monta a linha e o main.js ([data-hbar] na .tabela-scroll), nao o
   template: e um espelho da rolagem, nao um dado da tela, e assim ela nasce
   dentro do <thead> - que ja e o bloco que fica parado (sticky) quando o
   cabecalho fixo da listagem esta valendo.

   A celula ocupa a largura inteira da TABELA; quem fica parado na vista e o
   .hbar dentro dela, com position:sticky e left:0 - o mesmo recurso que ja
   segura a coluna Categoria da grade. As duas larguras (a da janela, no .hbar,
   e a do conteudo, no trilho) sao medidas em pixel pelo JS: em CSS a celula so
   sabe a largura da tabela, que e justamente o que nao serve aqui.

   A barra e desenhada a mao (::-webkit-scrollbar): a nativa do sistema pode ser
   de sobreposicao, e barra que so aparece enquanto se rola nao e atalho nenhum
   para quem esta procurando onde arrastar. */
.te-tab td.hbar-cel {
  padding: 0; border-bottom: none; background: var(--fundo);
  box-shadow: inset 0 -1px 0 var(--borda);
}
/* A altura e EXPLICITA e igual a da barra: com height:auto a caixa fica do
   tamanho do conteudo (1px do trilho) e a barra de rolagem, que e desenhada
   DENTRO da caixa, nao ganha espaco nenhum - a faixa media 1px de altura e nao
   havia o que arrastar. */
/* A borda de cima e a margem negativa TAPAM UMA COSTURA de 1px: as duas linhas
   do <thead> caem em altura fracionaria (27,8 + 12,5), e na juncao delas o
   navegador deixava escapar uma tira do corpo rolando por baixo - texto cortado
   aparecendo entre os titulos das colunas e a barra. A borda pinta essa tira com
   a cor do cabecalho e a margem devolve o 1px, para a faixa nao mudar de altura
   nem empurrar a barra. A altura e 13 e nao 12 porque a caixa e border-box: o
   1px da borda sairia do espaco da barra e a deixaria cortada. */
.hbar {
  position: sticky; left: 0; height: 13px; overflow-x: auto; overflow-y: hidden;
  border-top: 1px solid var(--fundo); margin-top: -1px;
}
.hbar-trilho { height: 1px; }
.hbar::-webkit-scrollbar { height: 12px; }
.hbar::-webkit-scrollbar-track { background: transparent; }
.hbar::-webkit-scrollbar-thumb {
  background: var(--borda-forte); border-radius: 6px;
  border: 3px solid var(--fundo); background-clip: padding-box;
}
.hbar::-webkit-scrollbar-thumb:hover { background: var(--texto-fraco); background-clip: padding-box; }

.te-tab { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.te-tab th, .te-tab td { padding: 8px 14px; text-align: left; border-bottom: 1px solid var(--borda); white-space: nowrap; }
.te-tab thead th {
  background: var(--fundo); color: var(--texto-secundario); font-weight: 700; font-size: 11.5px;
  text-transform: uppercase; letter-spacing: .03em; cursor: pointer; user-select: none; position: relative;
}
.te-tab thead th.no-sort { cursor: default; }
.te-tab tbody tr:hover { background: var(--fundo); }
.te-tab tbody tr:last-child td { border-bottom: none; }
.te-tab .sort-ind { margin-left: 6px; color: var(--cor-primaria); font-size: 11px; }
.te-tab .col-filtro { display: block; width: 100%; margin-top: 6px; height: 28px; padding: 3px 6px; font-size: 12px; border: 1px solid var(--borda); border-radius: 4px; font-weight: 400; text-transform: none; letter-spacing: 0; }
/* flex-shrink: 0 em cada slot: sem isto os botoes ENCOLHEM quando a coluna
   Acoes fica estreita, e encolhem em medidas diferentes - o que vive dentro de
   um <form> (o toggle) resiste mais que os outros e a fileira fica desalinhada.
   O tamanho do botao e do botao, nao do espaco que sobrou. */
.te-tab .acoes-cel { display: flex; gap: 6px; align-items: center; }
.te-tab .acoes-cel > *, .te-tab .acoes-cel form { flex: 0 0 auto; display: inline-flex; }
.tabela-vazia { padding: 40px 20px; text-align: center; color: var(--texto-fraco); }

/* Larguras fixas SO na listagem de Clientes e Fornecedores. Sem isto o
   navegador reparte a tabela pelo conteudo, e a coluna Nome (a de texto mais
   longo) come o espaco das outras, empurrando Cidade para fora da tela.
   Escopado por data-ta de proposito: ligar table-layout:fixed no .te-tab
   generico mudaria TODAS as listagens de uma vez, cada uma com colunas
   diferentes. A coluna Nome tem largura fixa como as demais; o texto que nao
   couber e cortado com reticencias, e o nome inteiro fica no title da celula. */
.te-tab[data-ta="cad_clientes_fornecedores"] { table-layout: fixed; }
.te-tab[data-ta="cad_clientes_fornecedores"] th,
.te-tab[data-ta="cad_clientes_fornecedores"] td {
  padding: 11px 10px; overflow: hidden; text-overflow: ellipsis;
}
.te-tab[data-ta="cad_clientes_fornecedores"] th[data-col="codigo"] { width: 55px; }
.te-tab[data-ta="cad_clientes_fornecedores"] th[data-col="nome"] { width: 222px; }
.te-tab[data-ta="cad_clientes_fornecedores"] th[data-col="documento"] { width: 142px; }
.te-tab[data-ta="cad_clientes_fornecedores"] th[data-col="tipo"] { width: 86px; }
.te-tab[data-ta="cad_clientes_fornecedores"] th[data-col="telefone"] { width: 118px; }
.te-tab[data-ta="cad_clientes_fornecedores"] th[data-col="email"] { width: 125px; }
.te-tab[data-ta="cad_clientes_fornecedores"] th[data-col="cidade"] { width: 132px; }
.te-tab[data-ta="cad_clientes_fornecedores"] th[data-col="status"] { width: 78px; }
.te-tab[data-ta="cad_clientes_fornecedores"] th.no-sort { width: 174px; } /* celular: fim do arquivo */

/* Mesma ideia na listagem de Produtos: a Descricao (texto mais longo) comia o
   espaco das outras e empurrava as ultimas para fora da tela. Acoes com 3
   botoes (editar, ativar/desativar, excluir) = 3x34 + 2x6 + padding; no celular, o fim do arquivo. */
.te-tab[data-ta="cad_produtos"] { table-layout: fixed; }
.te-tab[data-ta="cad_produtos"] th,
.te-tab[data-ta="cad_produtos"] td {
  padding: 11px 10px; overflow: hidden; text-overflow: ellipsis;
}
.te-tab[data-ta="cad_produtos"] th[data-col="codigo"] { width: 92px; }
.te-tab[data-ta="cad_produtos"] th[data-col="descricao"] { width: 410px; }
.te-tab[data-ta="cad_produtos"] th[data-col="grupo"] { width: 112px; }
.te-tab[data-ta="cad_produtos"] th[data-col="unidade"] { width: 78px; }
.te-tab[data-ta="cad_produtos"] th[data-col="valor"] { width: 108px; }
.te-tab[data-ta="cad_produtos"] th[data-col="ncm"] { width: 108px; }
.te-tab[data-ta="cad_produtos"] th[data-col="status"] { width: 78px; }
.te-tab[data-ta="cad_produtos"] th.no-sort { width: 140px; }

/* A listagem de Clientes do painel do dono (decisao 128) tinha o defeito das duas
   acima: com o slot de Acesso por IP, a razao social empurrava as Acoes para fora
   da vista em 1280 (medido com a coluna Acesso, que por isso saiu: tabela de 1281px
   numa area de 972). A receita aqui e outra, porque so UMA coluna e texto livre: as
   demais (codigo, area, situacao, os badges dos modulos, os seis slots) ficam com a
   largura do proprio conteudo, e a Empresa, com width 100% e max-width 0, leva o que
   sobra. O nome cresce com a janela e so corta (reticencias, nome inteiro no title)
   quando nao cabe. O max-width 0 tira o nome da conta da largura minima da coluna,
   senao ele a alargaria de volta; quem segura o piso dela e o cabecalho. Largura fixa
   nas outras, como acima, teria de adivinhar o texto numa fonte que o projeto nao
   embarca (o Inter do token nao vem junto: no Windows sai a Segoe UI, no Mac a do
   sistema) somado a seta da ordenacao, e errava por pouco: com a seta, Situacao pedia
   102,2px na Segoe UI e 106,5 na Arial, e os badges de Vendas e Financeiro 194,8 e
   202,2. O min-width e o piso na janela estreita, onde a tabela volta a rolar de
   lado, como ja rolava. */
.te-tab[data-ta="pf_clientes"] { min-width: 904px; }
.te-tab[data-ta="pf_clientes"] th,
.te-tab[data-ta="pf_clientes"] td { padding-left: 10px; padding-right: 10px; }
.te-tab[data-ta="pf_clientes"] th[data-col="empresa"] { width: 100%; }
.te-tab[data-ta="pf_clientes"] td.pf-empresa {
  max-width: 0; overflow: hidden; text-overflow: ellipsis;
}

.ta-menu-wrapper { position: relative; }
.ta-menu-btn { width: 36px; height: 36px; display: grid; place-items: center; border: 1px solid var(--borda-forte); border-radius: var(--raio-sm); background: var(--branco); cursor: pointer; color: var(--texto-secundario); }
.ta-menu-btn:hover { border-color: var(--cor-primaria); color: var(--cor-primaria); }
.ta-menu-btn i { font-size: 18px; }
.ta-menu, .ta-popup {
  position: absolute; top: 100%; right: 0; margin-top: 6px; background: var(--branco);
  border: 1px solid var(--borda); border-radius: var(--raio); box-shadow: var(--sombra-md);
  display: none; z-index: var(--z-menu-tabela);
}
.ta-menu { min-width: 210px; } .ta-popup { min-width: 300px; }
.ta-menu.aberto, .ta-popup.aberto { display: block; }
.ta-menu-item { display: flex; align-items: center; gap: 10px; padding: 10px 14px; font-size: 13px; cursor: pointer; color: var(--texto); }
.ta-menu-item:hover { background: var(--fundo); color: var(--cor-primaria); }
.ta-menu-item i { font-size: 16px; color: var(--texto-secundario); }
.ta-menu-item:hover i { color: var(--cor-primaria); }
.ta-menu-divider { height: 1px; background: var(--borda); margin: 4px 0; }
.ta-popup-cab { padding: 12px 14px; border-bottom: 1px solid var(--borda); font-weight: 700; font-size: 13px; }
.ta-popup-corpo { padding: 10px 14px; max-height: 300px; overflow-y: auto; }
.ta-popup-corpo label { display: flex; align-items: center; gap: 8px; padding: 6px 2px; font-size: 13px; cursor: pointer; }
.ta-popup-rodape { padding: 10px 14px; border-top: 1px solid var(--borda); display: flex; gap: 8px; justify-content: flex-end; }
.ta-popup-rodape button { padding: 7px 14px; border-radius: var(--raio-sm); border: 1px solid var(--borda); background: var(--branco); cursor: pointer; font-size: 12.5px; font-weight: 600; color: var(--texto); }
.ta-popup-rodape button:hover { background: var(--fundo); }
.ta-popup-rodape .ta-aplicar { background: var(--cor-primaria); color: var(--texto-sobre-primaria); border-color: var(--cor-primaria); }
.ta-popup-rodape .ta-aplicar:hover { background: var(--cor-primaria-escura); }

/* Item do menu aceso enquanto a ferramenta dele esta ligada (Padrao_Filtro_por_Coluna) */
.ta-menu-item.ativo { color: var(--cor-primaria); background: var(--cor-primaria-suave); }
.ta-menu-item.ativo i { color: var(--cor-primaria); }

/* Contagem "N de M registros" ao lado do menu, so com filtro de coluna ativo */
.ta-contagem { font-size: 12.5px; color: var(--texto-suave); margin-right: 10px; white-space: nowrap; align-self: center; }
.ta-menu-wrapper { display: inline-flex; align-items: center; }

/* Popup Ordenar: regras numeradas + colunas para adicionar (tudo botao, sem select nativo) */
.ta-ord-regra { display: flex; align-items: center; gap: 6px; padding: 5px 0; }
.ta-ord-num { width: 18px; height: 18px; border-radius: 50%; background: var(--cor-primaria-suave); color: var(--cor-primaria-escura); font-size: 11px; font-weight: 700; display: grid; place-items: center; flex-shrink: 0; }
.ta-ord-rotulo { flex: 1; font-size: 13px; color: var(--texto); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ta-ord-btn { width: 26px; height: 26px; display: grid; place-items: center; border: 1px solid var(--borda); border-radius: var(--raio-sm); background: var(--branco); cursor: pointer; color: var(--texto-secundario); flex-shrink: 0; }
.ta-ord-btn:hover:not(:disabled) { border-color: var(--cor-primaria); color: var(--cor-primaria); }
.ta-ord-btn.perigo:hover:not(:disabled) { border-color: var(--erro); color: var(--erro); }
.ta-ord-btn:disabled { opacity: .3; cursor: not-allowed; }
.ta-ord-btn i { font-size: 13px; }
.ta-ord-sub { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--texto-secundario); padding: 8px 0 4px; }
.ta-ord-add { display: flex; align-items: center; gap: 8px; width: 100%; padding: 6px 8px; border: none; background: none; border-radius: var(--raio-sm); cursor: pointer; font-size: 13px; color: var(--texto); text-align: left; }
.ta-ord-add:hover { background: var(--fundo); color: var(--cor-primaria); }
.ta-ord-add i { font-size: 13px; color: var(--texto-secundario); }
.ta-ord-add:hover i { color: var(--cor-primaria); }

/* Popup Linhas por pagina: lista fechada 10/50/100/500 */
.ta-tam-lista { display: flex; flex-direction: column; gap: 2px; }
.ta-tam-item { display: flex; align-items: center; padding: 8px 10px; border: none; background: none; border-radius: var(--raio-sm); cursor: pointer; font-size: 13px; color: var(--texto); text-align: left; }
.ta-tam-item:hover { background: var(--fundo); color: var(--cor-primaria); }
.ta-tam-item.on { background: var(--cor-primaria-suave); color: var(--cor-primaria-escura); font-weight: 700; }

/* ============ Listagem paginada no servidor (Padrao_Paginacao_Servidor) ============ */
/* O wrap vira referencia do overlay de loading */
.pag-wrap { position: relative; }

/* Rodape (Padrao_Cabecalho_da_Tabela): contagem a esquerda, controles no centro,
   GRID de 3 colunas (1fr auto 1fr) - nunca position:absolute, que passa por cima
   dos botoes em janela estreita. */
.pg-rodape { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 10px; margin-top: 10px; }
.pg-info { font-size: 12.5px; color: var(--texto-suave); }
.pg-nav { display: inline-flex; align-items: center; gap: 4px; }
.pg-btn { width: 30px; height: 30px; display: grid; place-items: center; border: 1px solid var(--borda); border-radius: var(--raio-sm); background: var(--branco); cursor: pointer; color: var(--texto-secundario); }
.pg-btn:hover:not(:disabled) { border-color: var(--cor-primaria); color: var(--cor-primaria); }
.pg-btn:disabled { opacity: .35; cursor: not-allowed; }
.pg-pos { font-size: 12.5px; color: var(--texto-secundario); padding: 0 8px; white-space: nowrap; }

/* Loading do fetch de pagina (Padrao_Loading_Estado: a variante inline SUBSTITUI o
   conteudo do container, nao passa por cima dele). O container aqui e o CORPO da
   tabela, nao a tabela inteira: sai o <tbody>, entra o bloco, e o CABECALHO FICA.

   O cabecalho tem de ficar porque e nele que moram os campos de filtro por coluna,
   e o usuario esta digitando dentro deles. Esconder o cabecalho durante a consulta
   da em display:none no elemento focado, e o navegador devolve o foco ao body: o
   cursor pula fora do campo no meio da palavra a cada 400ms. E o mesmo efeito que
   o Padrao_Filtro_por_Coluna proibe ("PROIBIDO reconstruir o <thead> a cada
   digitada: o input perde o foco no meio da palavra. Atualize so o corpo"). */
.pg-loading { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; padding: 48px 20px; background: var(--branco); }
.pag-wrap.carregando tbody[data-pag-corpo],
.pag-wrap.carregando .vz-pag { display: none; }

/* Estado vazio (Padrao_Estado_Vazio): bloco centrado na area da tabela; o topo
   com busca e menu fica visivel (e o controle que desfaz o filtro). */
.vz { flex: 1; min-height: 300px; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 32px 20px; }
.vz .vz-icone { font-size: 40px; color: var(--texto-fraco); line-height: 1; margin-bottom: 16px; }
.vz-titulo { margin: 0; font-family: var(--fonte-titulo); font-size: 17px; font-weight: 700; letter-spacing: -.02em; color: var(--texto); }
.vz-sub { margin: 7px 0 0; font-size: 13.5px; color: var(--texto-suave); line-height: 1.5; max-width: 400px; }

/* ============ Badges / chips ============ */
.badge { display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px; border-radius: 999px; font-size: 11.5px; font-weight: 600; }
.badge-ok { background: var(--ok-suave); color: var(--ok); }
.badge-erro { background: var(--erro-suave); color: var(--erro); }
.badge-neutro { background: var(--fundo-2); color: var(--texto-secundario); }
.badge-info { background: var(--info-suave); color: var(--info); }

/* ============ Modal (Padrao_Modal / Sem_Popup_Nativo) ============ */
.modal-bg {
  position: fixed; inset: 0; background: var(--veu-modal); z-index: var(--z-janela); display: none;
  align-items: center; justify-content: center; padding: 20px; backdrop-filter: blur(2px);
}
.modal-bg.visivel { display: flex; }
.modal-caixa { background: var(--branco); border-radius: var(--raio-lg); width: 100%; max-width: 700px; max-height: 90vh; max-height: 90dvh; overflow-y: auto; box-shadow: var(--sombra-lg); animation: modalSobe .2s ease; }
.modal-caixa.modal-largo { max-width: 1000px; }
.modal-caixa.modal-confirm { max-width: 440px; text-align: center; }
@keyframes modalSobe { from { opacity: 0; transform: translateY(-12px); } to { opacity: 1; transform: translateY(0); } }
.modal-cab { padding: 16px 20px; border-bottom: 1px solid var(--borda); display: flex; align-items: center; justify-content: space-between; }
.modal-cab h3 { font-size: 16px; }
.modal-x { background: none; border: none; cursor: pointer; font-size: 22px; color: var(--texto-fraco); display: grid; place-items: center; }
.modal-x:hover { color: var(--texto); }
.modal-corpo { padding: 20px; }
.modal-rodape { padding: 14px 20px; border-top: 1px solid var(--borda); display: flex; gap: 10px; justify-content: flex-end; }
/* Aviso do 2o ESC: aparece DENTRO do modal, logo acima do rodape, quando ha alteracao
   nao salva (o main.js injeta e esconde). Nunca vira modal em cima de modal. */
/* Mora DENTRO do .modal-rodape, a esquerda: margin-right auto empurra os botoes para a
   ponta e o aviso fica encostado no Cancelar que ele manda usar. Bloco separado somava
   altura a uma caixa ja no teto de 90vh e expulsava o rodape da vista. */
.modal-esc-aviso { display: flex; align-items: center; gap: 8px; margin-right: auto;
  padding: 8px 12px; border: 1px solid var(--alerta); border-radius: var(--raio-sm);
  background: var(--alerta-suave); color: var(--texto); font-size: 13px; }
/* Tela estreita: o aviso desce em vez de espremer os botoes. */
.modal-rodape { flex-wrap: wrap; }
.modal-esc-aviso i { color: var(--alerta); font-size: 16px; flex: none; }
/* display de classe vence [hidden]: sem isto o aviso nasceria visivel (armadilha ja
   registrada na memoria do projeto). */
.modal-esc-aviso[hidden] { display: none; }
/* Aviso da cascata (plano de contas): quantas filhas a edicao do pai arrasta. Fica
   colado ao campo Codigo, DENTRO do corpo do modal - uma linha so, num modal curto,
   que rola junto com o resto e nao empurra o rodape para fora da vista. */
.cascata-aviso { display: flex; align-items: flex-start; gap: 8px; margin: 12px 0;
  padding: 8px 12px; border: 1px solid var(--alerta); border-radius: var(--raio-sm);
  background: var(--alerta-suave); color: var(--texto); font-size: 13px; line-height: 1.45; }
.cascata-aviso i { color: var(--alerta); font-size: 16px; flex: none; margin-top: 1px; }
/* display de classe vence [hidden]: sem isto o aviso nasceria visivel. */
.cascata-aviso[hidden] { display: none; }
.confirm-corpo { padding: 30px 26px 10px; }
.confirm-corpo h3 { font-size: 18px; margin-bottom: 8px; }
.confirm-corpo p { color: var(--texto-suave); font-size: 14px; }
.confirm-icone { width: 64px; height: 64px; border-radius: 50%; display: grid; place-items: center; margin: 0 auto 16px; }
.confirm-icone i { font-size: 34px; }
.confirm-icone.perigo { background: var(--erro-suave); color: var(--erro); }
.confirm-icone.aviso { background: var(--alerta-suave); color: var(--alerta); }
.modal-confirm .modal-rodape { justify-content: center; }

/* ============ Loading (Sempre_Mostrar_Loading) ============ */
.loading-inline { padding: 70px 20px; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 14px; }
.spinner-circle { width: 44px; height: 44px; border: 4px solid var(--borda); border-top-color: var(--cor-primaria); border-radius: 50%; animation: spinner-rotate .8s linear infinite; }
.loading-text { font-size: 14px; font-weight: 600; color: var(--texto); }
@keyframes spinner-rotate { to { transform: rotate(360deg); } }
.loading-overlay { position: fixed; inset: 0; background: var(--veu-carregando); backdrop-filter: blur(2px); z-index: var(--z-carregando); display: none; align-items: center; justify-content: center; }
.loading-overlay.aberto { display: flex; }
.loading-spinner { background: var(--branco); border-radius: var(--raio); padding: 26px 40px; box-shadow: var(--sombra-lg); display: flex; flex-direction: column; align-items: center; gap: 14px; animation: modalSobe .2s ease; }

/* ============ Flash ============ */
.flash-area { position: fixed; top: 16px; right: 16px; z-index: var(--z-aviso); display: flex; flex-direction: column; gap: 10px; max-width: 380px; }
.flash { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-radius: var(--raio-sm); background: var(--branco); border: 1px solid var(--borda); box-shadow: var(--sombra-md); font-size: 13.5px; font-weight: 500; animation: modalSobe .2s ease; }
.flash i { font-size: 18px; flex-shrink: 0; }
.flash.ok { border-left: 3px solid var(--ok); } .flash.ok i { color: var(--ok); }
.flash.erro { border-left: 3px solid var(--erro); } .flash.erro i { color: var(--erro); }
.flash.info { border-left: 3px solid var(--info); } .flash.info i { color: var(--info); }
.flash-x { margin-left: auto; background: none; border: none; cursor: pointer; color: var(--texto-fraco); font-size: 16px; }
@media (max-width: 720px) { .flash-area { left: 16px; right: 16px; max-width: none; } }

/* ============ Login ============ */
.login-tela { min-height: 100vh; min-height: 100dvh; display: grid; place-items: center; padding: 20px; background: var(--fundo); }
.login-caixa { width: 100%; max-width: 400px; background: var(--branco); border: 1px solid var(--borda); border-radius: var(--raio-lg); box-shadow: var(--sombra-md); padding: 32px 30px; }
.login-marca { display: flex; flex-direction: column; align-items: center; gap: 12px; margin-bottom: 22px; text-align: center; }
.login-marca .logo-quadro { width: 54px; height: 54px; }
.login-marca .logo-quadro i { font-size: 28px; }
.login-marca h1 { font-size: 19px; }
.login-marca .sub { color: var(--texto-suave); font-size: 13px; }
.login-caixa .btn-primario { width: 100%; margin-top: 6px; }
.login-rodape { margin-top: 18px; text-align: center; font-size: 12px; color: var(--texto-fraco); }
.input-senha { position: relative; } .input-senha .input { padding-right: 42px; }
.input-senha .ver-senha { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); background: none; border: none; cursor: pointer; color: var(--texto-fraco); padding: 6px; font-size: 18px; display: grid; place-items: center; }

/* ============ Login v2 (telas dedicadas) ============
   Duas telas com identidade propria: o CLIENTE entra por uma tela dividida (marca a
   esquerda, formulario a direita) e o DONO por um cartao escuro (Painel SaaS). Usam
   namespaces .au-* e .pl-*; as classes .login-* antigas ficam INTACTAS porque as telas
   de sair e de erro, e a moldura da troca exigida (a tela e a saida), ainda dependem
   delas. base_publico NAO carrega layout.css, entao o quadro do icone e os icones de
   campo sao definidos aqui, sem depender de fora. */

/* -- Campo com icone a esquerda (+ olho opcional), compartilhado pelas duas telas -- */
.campo-box { position: relative; display: flex; align-items: center; }
.campo-box > .ci-esq { position: absolute; left: 13px; font-size: 17px; color: var(--texto-fraco); pointer-events: none; }
.campo-box .input { padding-left: 40px; }
.campo-box.tem-olho .input { padding-right: 42px; }
.campo-box .ver-senha { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); background: none; border: none; cursor: pointer; color: var(--texto-fraco); padding: 6px; display: grid; place-items: center; }

/* ===== Cliente: tela dividida ===== */
.au-tela { min-height: 100vh; min-height: 100dvh; display: grid; place-items: center; padding: 24px; background: var(--fundo); }
/* Porta COMPARTILHADA do saas: antes do login nao ha sala, entao a tela veste a
   marca da plataforma e nunca a cor injetada de uma empresa. O hex mora so no
   tokens.css (--cor-plataforma); aqui a classe apenas reaponta a familia. */
.au-tela.au-plataforma {
  --cor-primaria: var(--cor-plataforma);
  --cor-primaria-escura: var(--cor-plataforma-escura); --cor-primaria-suave: var(--cor-plataforma-suave);
}
.au-cartao {
  width: 100%; max-width: 940px; display: grid; grid-template-columns: 1.05fr 1fr;
  background: var(--branco); border: 1px solid var(--borda); border-radius: var(--raio-lg);
  box-shadow: var(--sombra-lg); overflow: hidden;
}
.au-lado {
  position: relative; overflow: hidden; padding: 42px 40px; color: var(--texto-sobre-primaria);
  display: flex; flex-direction: column; gap: 24px;
  background: linear-gradient(155deg, var(--cor-primaria), var(--cor-primaria-escura));
}
.au-marca { display: flex; align-items: center; gap: 12px; position: relative; z-index: 1; }
.au-marca-ico { width: 42px; height: 42px; border-radius: var(--raio-sm); display: grid; place-items: center; background: color-mix(in srgb, var(--branco) 16%, transparent); overflow: hidden; flex-shrink: 0; }
.au-marca-ico i { font-size: 22px; color: var(--texto-sobre-primaria); }
.au-marca-ico img { width: 100%; height: 100%; object-fit: cover; }
.au-marca-nome { font-family: var(--fonte-titulo); font-weight: 700; font-size: 15px; line-height: 1.15; }
.au-marca-sub { font-size: 11.5px; opacity: .82; }
.au-lado h2 { color: inherit; font-family: var(--fonte-titulo); font-size: 25px; line-height: 1.22; letter-spacing: -.01em; max-width: 15ch; position: relative; z-index: 1; } /* o branco do lado, e nao o var(--texto) do h2 do base.css */
.au-lado p { font-size: 13.5px; line-height: 1.55; opacity: .9; max-width: 42ch; position: relative; z-index: 1; }
.au-bullets { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; position: relative; z-index: 1; }
.au-bullets li { display: flex; align-items: center; gap: 10px; font-size: 13.5px; }
.au-bullets i { font-size: 19px; opacity: .95; flex-shrink: 0; }
.au-orb { position: absolute; border-radius: 50%; background: color-mix(in srgb, var(--branco) 10%, transparent); }
.au-orb.b1 { right: -70px; bottom: -80px; width: 230px; height: 230px; }
.au-orb.b2 { right: 70px; bottom: -150px; width: 150px; height: 150px; background: color-mix(in srgb, var(--branco) 7%, transparent); }
.au-form { padding: 46px 42px; display: flex; flex-direction: column; justify-content: center; }
.au-form h1 { font-family: var(--fonte-titulo); font-size: 23px; margin-bottom: 4px; }
.au-form .au-intro { color: var(--texto-suave); font-size: 13.5px; margin-bottom: 24px; }
.au-form .campo > label { text-transform: none; letter-spacing: 0; font-size: 13px; font-weight: 600; color: var(--texto-secundario); }
.au-form .btn-primario { width: 100%; margin-top: 6px; }
.au-alt { margin-top: 20px; text-align: center; font-size: 13px; color: var(--texto-suave); }
.au-alt a { font-weight: 600; }
@media (max-width: 820px) {
  .au-cartao { grid-template-columns: 1fr; max-width: 430px; }
  .au-lado { display: none; }
  .au-form { padding: 36px 30px; }
}

/* ===== Plataforma (dono): cartao escuro ===== */
.pl-tela {
  /* O painel do DONO tem identidade PROPRIA e fixa: nunca veste a cor de um cliente
     (nem a que sobrou no public de um banco migrado). Por isso fixa o azul da
     plataforma aqui, sobrescrevendo por heranca o --cor-primaria que o base_publico
     possa ter injetado a partir de uma empresa. A paleta escura mora no tokens.css. */
  --cor-primaria: var(--cor-plataforma); --cor-primaria-escura: var(--cor-plataforma-escura);
  --cor-primaria-suave: var(--cor-plataforma-suave);
  min-height: 100vh; min-height: 100dvh; display: grid; place-items: center; padding: 24px;
  background: radial-gradient(1100px 560px at 50% -12%, var(--pl-fundo-topo), var(--pl-fundo) 62%);
}
.pl-card {
  width: 100%; max-width: 400px; text-align: center; padding: 34px 32px;
  background: var(--pl-card); border: 1px solid var(--pl-borda);
  border-radius: var(--raio-lg); box-shadow: var(--pl-sombra);
}
.pl-logo { width: 56px; height: 56px; margin: 0 auto 16px; border-radius: 15px; display: grid; place-items: center; background: linear-gradient(160deg, var(--cor-primaria), var(--cor-primaria-escura)); box-shadow: 0 8px 22px color-mix(in srgb, var(--cor-primaria) 42%, transparent); }
.pl-logo i { font-size: 28px; color: var(--texto-sobre-primaria); }
.pl-card h1 { font-family: var(--fonte-titulo); font-size: 22px; color: var(--pl-texto); }
.pl-badge { display: inline-flex; align-items: center; gap: 6px; margin: 8px 0 26px; padding: 5px 12px; border-radius: var(--raio-full); background: color-mix(in srgb, var(--cor-primaria) 16%, transparent); color: var(--pl-destaque); font-size: 11px; font-weight: 700; letter-spacing: .05em; }
.pl-badge i { font-size: 13px; }
.pl-card form { text-align: left; }
.pl-card .campo > label { text-transform: none; letter-spacing: 0; font-size: 12.5px; font-weight: 600; color: var(--pl-muted); }
.pl-card .campo-box > .ci-esq, .pl-card .campo-box .ver-senha { color: var(--pl-muted); }
.pl-card .input { background: var(--pl-input); border-color: var(--pl-borda); color: var(--pl-texto); }
.pl-card .input::placeholder { color: var(--pl-texto-fraco); }
.pl-card .input:focus { border-color: var(--cor-primaria); box-shadow: 0 0 0 3px color-mix(in srgb, var(--cor-primaria) 28%, transparent); }
.pl-card .btn-primario { width: 100%; margin-top: 6px; }
.pl-alt { margin-top: 20px; text-align: center; font-size: 13px; color: var(--pl-muted); }
.pl-alt a { color: var(--pl-destaque); font-weight: 600; }

/* ============ Matriz de permissoes ============ */
.matriz-grupo { margin-bottom: 18px; border: 1px solid var(--borda); border-radius: var(--raio); overflow: hidden; }
.matriz-grupo-cab { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 16px; background: var(--fundo); border-bottom: 1px solid var(--borda); flex-wrap: wrap; }
.matriz-grupo-cab h3 { font-size: 13px; text-transform: uppercase; letter-spacing: .06em; color: var(--texto-secundario); }
.matriz-grupo-cab .acoes-grupo { display: flex; gap: 8px; flex-wrap: wrap; }
.matriz-auto { display: flex; gap: 16px; padding: 10px 16px; border-top: 1px dashed var(--borda); background: var(--fundo); font-size: 12.5px; align-items: center; flex-wrap: wrap; }
.matriz-auto label { display: flex; align-items: center; gap: 7px; }
.matriz-tab { width: 100%; border-collapse: collapse; font-size: 13.5px; table-layout: fixed; } /* fixed: Ver e Editar na mesma coluna em todo grupo */
.matriz-tab td, .matriz-tab th { padding: 9px 16px; border-bottom: 1px solid var(--borda); }
.matriz-tab th { text-align: center; width: 120px; font-size: 11.5px; text-transform: uppercase; color: var(--texto-secundario); }
.matriz-tab th:first-child { text-align: left; width: auto; }
.matriz-tab td:not(:first-child) { text-align: center; }
.matriz-tab tr:last-child td { border-bottom: none; }
.chk { width: 17px; height: 17px; accent-color: var(--cor-primaria); cursor: pointer; } .chk:disabled { cursor: not-allowed; }

/* ============ Home / cards de modulo ============ */
.mod-card { display: flex; gap: 12px; align-items: flex-start; padding: 16px; border: 1px solid var(--borda); border-radius: var(--raio); background: var(--branco); box-shadow: var(--sombra); transition: transform var(--transicao), box-shadow var(--transicao); }
.mod-card:hover { transform: translateY(-2px); box-shadow: var(--sombra-md); text-decoration: none; }
.mod-card.esmaecido { opacity: .6; }
.mod-card .mc-icone { width: 42px; height: 42px; border-radius: var(--raio-sm); display: grid; place-items: center; background: var(--cor-primaria-suave); color: var(--cor-primaria-escura); flex-shrink: 0; }
.mod-card .mc-icone i { font-size: 22px; }
.mod-card .mc-nome { font-weight: 600; color: var(--texto); font-size: 14px; }
.mod-card .mc-grupo { font-size: 11.5px; color: var(--texto-fraco); }

.tabela-info { padding: 10px 14px; font-size: 12.5px; color: var(--texto-suave); border-top: 1px solid var(--borda); }
.aviso-box { display: flex; gap: 10px; padding: 12px 14px; border-radius: var(--raio-sm); background: var(--info-suave); color: var(--texto-secundario); font-size: 13px; margin-bottom: 16px; }
.aviso-box i { color: var(--info); font-size: 18px; flex-shrink: 0; }

/* Espaco antes de um segundo cabecalho na mesma pagina (ex.: "Em breve" na home) */
.pagina-cab[data-espaco-topo] { margin-top: 30px; }

/* ---------- Ajuda da tela: a bolinha "?" e o balao (decisao 125) ----------
   O texto explicativo saia impresso por baixo do titulo e comia altura em toda
   listagem, justo onde o cabecalho e fixo e o espaco vertical e o da janela.
   Agora a tela mostra so a bolinha, e o texto abre no balao. Markup no macro
   `_ajuda.html`, comportamento no main.js.

   O balao nao mora no <body>, como o do "+N" da coluna Modulos: aqui nao ha
   overflow no caminho (o .pagina-cab nao recorta), entao position:absolute basta e
   nada precisa ser reposicionado a cada rolagem.
   Quem o ancora e a LINHA DO TITULO (.cab-titulo, que e quem tem position:
   relative), nao a bolinha - por isso o .ajuda nao pode ser posicionado. Preso a
   bolinha ele vazava pela direita no celular: o "?" fica no fim de um titulo de
   186px numa janela de 375, e 335px de balao nao cabiam ali (medido). Preso ao
   titulo, ele comeca sempre na margem esquerda da pagina, que e onde o paragrafo
   ficava antes, e o max-width garante o resto.
   Abre no hover (mouse) e na classe .aberto, que e quem carrega o estado: clique,
   toque e foco de teclado passam todos pelo main.js. Estado num lugar so, senao o
   ESC apaga a classe e o :focus-within do CSS mantem o balao na tela. */
.ajuda { display: inline-flex; flex-shrink: 0; }
/* O botao da ajuda NAO desenha circulo nenhum: quem desenha e a marca `.i-info` que
   ele carrega dentro, a MESMA dos avisos (pedido do Ricardo, 2026-09-08: "o layout e
   tamanho do i da caixa de informacao, para ficar padrao"). Antes eram dois desenhos
   para a mesma coisa - o circulo do botao com uma letra de 13px quase encostando na
   borda, e a marca do aviso com a letra em 0,59em e ar em volta. Agora o botao so
   carrega o clique, o foco e a COR: a marca herda a cor por currentColor.
   O font-size: 16px e o do texto do .aviso-info, e e ele que faz a marca do titulo
   sair com os mesmos 15px da marca de la. */
.ajuda-btn {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0; border: 0; background: none; cursor: pointer;
  font: inherit; font-size: 16px; line-height: 1;
  color: var(--texto-suave);
  transition: var(--transicao);
}
/* Contorno um degrau mais claro que a letra, como a bolinha ja era: a 15px, com o
   cinza de borda no contorno, ela quase sumia ao lado do titulo. No aviso nao ha esse
   degrau, porque la a marca inteira e da cor do aviso. */
.ajuda-btn .i-info { border-color: var(--texto-fraco); background: var(--branco); }
.ajuda-btn:hover, .ajuda-btn:focus-visible, .ajuda.aberto .ajuda-btn {
  color: var(--cor-primaria);
}
.ajuda-btn:hover .i-info, .ajuda-btn:focus-visible .i-info, .ajuda.aberto .i-info {
  border-color: var(--cor-primaria); background: var(--cor-primaria-suave);
}
/* A MARCA DE INFORMACAO do sistema: um "i" serifado em italico, que e LETRA e nao
   icone. O ph-info do Phosphor traz o circulo desenhado no proprio glifo, e dentro de
   outro circulo dava circulo dentro de circulo; escolhido pelo Ricardo em 2026-09-08,
   entre variantes vistas na tela, e espalhado no lugar de TODO ph-info do sistema.
   A serifa sai de fonte do SISTEMA (a CSP so aceita font-src 'self', nada e baixado) e
   nunca vira token: mora nesta classe e, por pedido do Ricardo (2026-09-09), na tela
   de modulos inteira (.po-tela, herdada pelos filhos); fora dai, nao ha serifa solta. A letra vem do ::before, como no proprio Phosphor:
   a tela escreve so a tag, e nao fica texto solto no meio da frase.
   E UMA so, do titulo ao toast: circulo e letra em `em`, herdando tamanho e cor de
   onde entrar (18px e --info no .aviso-box, 12,5px e --texto-suave no .tabela-info,
   16px e o cinza do botao no titulo). Por isso a borda e currentColor, e nao token. */
.i-info::before {
  content: "i";
  font-family: Georgia, "Times New Roman", serif;
  font-style: italic; font-weight: 700; line-height: 1;
}
.i-info {
  display: inline-flex; align-items: center; justify-content: center;
  /* 0.95em, e nao o 1.15em da primeira versao (pedido do Ricardo, 2026-09-08: "ficou
     grande"). No .aviso-box a marca caiu de 21px para 17px, perto da bolinha de 15px
     da ajuda; a letra desceu junto, na mesma proporcao (a razao letra/circulo segue
     em 0,62), senao ela encostaria na borda. */
  width: .95em; height: .95em; flex-shrink: 0;
  border: 1px solid currentColor; border-radius: 50%;
  font-style: normal;
}
.i-info::before { font-size: .59em; }
/* O DESENHO tem 15px; o alvo do dedo, 29. O ::after estende so a area clicavel,
   sem mexer no que se ve nem empurrar o titulo: circulo de 15px e menor que o
   minimo de toque, e no celular o "?" e o unico caminho para o texto. */
.ajuda-btn::after { content: ""; position: absolute; inset: -7px; border-radius: 50%; }
/* O balao PADRAO (tela estreita): embaixo do titulo, comecando na margem esquerda, que
   e onde o paragrafo ficava antes. Preso a bolinha ele precisaria da largura inteira a
   direita dela, e no celular o "?" fica no fim do titulo: medido a 375px, vazava 154px
   pela direita. Quem o ancora aqui e o .cab-titulo (layout.css). */
.ajuda-balao {
  display: none; position: absolute; top: calc(100% + 8px); left: 0;
  z-index: var(--z-balao); width: max-content; max-width: min(420px, calc(100vw - 40px));
  padding: 10px 12px; text-align: left;
  background: var(--branco); border: 1px solid var(--borda);
  border-radius: var(--raio-sm); box-shadow: var(--sombra-md);
  font-size: 12.5px; font-weight: 400; line-height: 1.5; color: var(--texto-secundario);
  white-space: normal;
}
.ajuda:hover .ajuda-balao, .ajuda.aberto .ajuda-balao { display: block; }
/* Balao ao LADO DIREITO da bolinha (pedido do Ricardo, 2026-09-08), quando cabe. Quem
   decide e a MEDIDA, no main.js, e nao um breakpoint: o que manda e o comprimento do
   TITULO, nao a largura da janela. Medido com o balao SEMPRE ao lado: a tela de Posicao
   financeira consolidada vazava 15px em 1024 e 139px em 900, enquanto Contas, de titulo
   curto, cabia nas duas. Sem o JS o balao fica embaixo do titulo, que e o lugar que
   sempre cabe.
   Ao lado, o topo sobe 6px em vez de centralizar na bolinha: balao de quatro linhas
   centralizado comeca ACIMA da janela (a bolinha fica a 37px do topo e ele mede 78).
   `.medindo` e o estado em que o main.js le a largura natural do balao: visivel para o
   layout, invisivel para o olho. */
.ajuda.medindo .ajuda-balao { display: block; visibility: hidden; }
.ajuda.ao-lado { position: relative; }
.ajuda.ao-lado .ajuda-balao { top: -6px; left: calc(100% + 10px); }
.ta-filtro-row th { padding-top: 0; padding-bottom: 8px; background: var(--fundo); }
.filtro-inline { max-width: 340px; }
.tabela-topo .ta-menu-wrapper { margin-left: auto; }

/* ============ Fase 2 - dominio financeiro ============ */

/* Badge de alerta (ambar) - vencido no aging. Vermelho forte fica reservado para
   erro e saldo projetado negativo (frontend-design 11.4). */
.badge-alerta { background: var(--alerta-suave); color: var(--alerta); }
.txt-atraso { color: var(--alerta); font-weight: 600; }

/* Realce sobrio de parcela vencida (nao e semaforo gritante). */
.te-tab tbody tr.linha-vencida td { background: var(--alerta-suave); }
.te-tab tbody tr.linha-vencida td:first-child { box-shadow: inset 3px 0 0 var(--alerta); }
.te-tab tbody tr.linha-vencida:hover td { background: var(--alerta-suave-hover); }

/* Resumo do aging (cabecalho do card). */
.resumo-totais { display: flex; gap: 18px; font-size: 13px; color: var(--texto-secundario); flex-wrap: wrap; }
.resumo-totais strong { color: var(--texto); }
.resumo-vencido strong { color: var(--alerta); }

/* Preview das parcelas no modal de titulo (secao 5.1). */
.preview-parcelas { border: 1px solid var(--borda); border-radius: var(--raio-sm); overflow: hidden; margin-top: 4px; }
.preview-cab { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 9px 12px; background: var(--fundo); border-bottom: 1px solid var(--borda); font-size: 12.5px; font-weight: 600; color: var(--texto-secundario); }
.preview-cab i { color: var(--cor-primaria); }
.preview-total { color: var(--texto); font-variant-numeric: tabular-nums; }
.mini-tab { width: 100%; border-collapse: collapse; font-size: 13px; }
.mini-tab th, .mini-tab td { padding: 7px 12px; text-align: left; border-bottom: 1px solid var(--borda); }
.mini-tab th { font-size: 10.5px; text-transform: uppercase; letter-spacing: .04em; color: var(--texto-fraco); font-weight: 700; background: var(--branco); }
.mini-tab tbody tr:last-child td { border-bottom: none; }
.mini-tab .num { font-variant-numeric: tabular-nums; text-align: right; }
.mini-tab .mini-vazia td { color: var(--texto-fraco); text-align: center; padding: 16px; font-size: 12.5px; }

/* Detalhe do cliente/fornecedor (LGPD). */
.det-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px 24px; }
.det-item { display: flex; flex-direction: column; gap: 3px; }
.det-item.det-full { grid-column: 1 / -1; }
.det-rot { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--texto-fraco); }
.det-val { font-size: 14px; color: var(--texto); }
@media (max-width: 560px) { .det-grid { grid-template-columns: 1fr; } }

/* ============ Fase 3 - baixa, movimentacao, transferencia, extrato ============ */

/* Segundo cabecalho na mesma pagina (ex.: "Baixas registradas"). */
.pagina-cab h2 { font-size: 17px; }

/* Valores com pesos distintos (frontend-design 11.4): entrada x saida, sem semaforo
   gritante. Vermelho forte so em erro e saldo negativo. Numeros tabulares. */
.val-entrada { color: var(--entrada); font-variant-numeric: tabular-nums; }
.val-saida { color: var(--saida); font-variant-numeric: tabular-nums; }
.saldo-negativo { color: var(--erro); font-weight: 600; }

/* Cabecalho da parcela no modal de baixa (dados read-only da parcela escolhida). */
.bx-parcela { background: var(--fundo); border: 1px solid var(--borda); border-radius: var(--raio-sm); padding: 10px 14px; margin-bottom: 16px; }
.bx-parcela-linha { display: flex; justify-content: space-between; gap: 12px; padding: 3px 0; font-size: 13px; color: var(--texto-secundario); }
.bx-parcela-linha strong { color: var(--texto); }
.bx-parcela-linha .num { font-variant-numeric: tabular-nums; }

/* Efeito da baixa (deteccao de diferenca + tratamento, briefing 11.3). */
.baixa-efeito { border: 1px solid var(--borda); border-radius: var(--raio-sm); padding: 12px 14px; margin-bottom: 14px; background: var(--cor-primaria-suave); }
.bx-efeito-cab { display: flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 700; color: var(--texto-secundario); text-transform: uppercase; letter-spacing: .03em; }
.bx-efeito-cab i { color: var(--cor-primaria); font-size: 15px; }
.bx-efeito-texto { margin-top: 8px; font-size: 13.5px; color: var(--texto); }
.bx-opcoes { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.bx-opt { display: inline-flex; align-items: center; gap: 6px; padding: 7px 12px; border: 1px solid var(--borda-forte); border-radius: var(--raio-sm); background: var(--branco); color: var(--texto-secundario); font-size: 12.5px; font-weight: 600; cursor: pointer; }
.bx-opt:hover { border-color: var(--cor-primaria); color: var(--cor-primaria); }
.bx-opt.ativo { background: var(--cor-primaria); border-color: var(--cor-primaria); color: var(--texto-sobre-primaria); }
.bx-opt i { font-size: 15px; }
/* Desconto, juros e multa dentro do bloco de efeito, um ao lado do outro. */
.bx-valores { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 10px; margin-top: 12px; }
.bx-valores label { font-size: 12px; }
/* Ver a regra GLOBAL de [hidden] no topo do arquivo: ela cobre .campo, .bx-opt e
   .bx-valores (e qualquer classe futura) de uma vez. Esta linha era o remendo
   caso a caso que a global aposentou. */

/* Saldo por conta na transferencia (briefing 11.3: saldo atual de cada conta visivel). */
.transf-saldo { margin-top: 6px; font-size: 12.5px; color: var(--texto-suave); }
.transf-saldo strong { color: var(--texto); font-variant-numeric: tabular-nums; }
.transf-saldo .transf-negativo { color: var(--erro); font-weight: 600; }

/* Extrato: linha de saldo inicial do periodo (realce sobrio). */
.te-tab tbody tr.extrato-inicial td { background: var(--fundo); color: var(--texto-secundario); font-weight: 600; }

/* ============ Fase 4 - conciliacao bancaria ============ */

/* Upload de extrato (Padrao_Upload_Arquivo, adaptado aos tokens e a CSP estrita). */
.im-card { background: var(--branco); border: 1px solid var(--borda); border-radius: var(--raio); box-shadow: var(--sombra); padding: 18px; margin-bottom: 16px; }
.im-card h3 { margin: 0 0 12px; font-size: 14px; font-weight: 700; display: flex; align-items: center; gap: 8px; justify-content: space-between; }
.im-card h3 i { color: var(--cor-primaria); }
.im-drop { display: block; border: 2px dashed var(--borda-forte); border-radius: var(--raio); padding: 30px; text-align: center; color: var(--texto-secundario); cursor: pointer; transition: var(--transicao); user-select: none; }
.im-drop:hover, .im-drop.over { border-color: var(--cor-primaria); background: var(--cor-primaria-suave); color: var(--cor-primaria-escura); border-style: solid; }
.im-drop.loaded { border-style: solid; border-color: var(--ok); background: var(--ok-suave); color: var(--ok); }
.im-drop i { font-size: 34px; display: block; margin-bottom: 6px; }
.im-drop small { display: block; margin-top: 6px; font-weight: 600; color: var(--ok); }
.im-inp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
.im-acao { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin-top: 14px; }
.im-acao .dica code { background: var(--fundo-2); padding: 1px 5px; border-radius: 4px; font-size: 12px; }

/* Resumo saldo do sistema x extrato. */
.concil-saldos { display: flex; gap: 28px; flex-wrap: wrap; align-items: flex-end; }
.cs-item { display: flex; flex-direction: column; gap: 3px; }
.cs-rot { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--texto-fraco); }
.cs-item strong.num { font-size: 18px; font-variant-numeric: tabular-nums; }
.concil-recasar { margin-top: 14px; }

/* Dois paineis lado a lado (extrato x movimentacoes); empilha no mobile. */
.concil-paineis { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; }
@media (max-width: 1024px) { .concil-paineis { grid-template-columns: 1fr; } }
.painel-titulo { font-weight: 700; font-size: 13px; display: inline-flex; align-items: center; gap: 8px; color: var(--texto-secundario); }
.painel-titulo i { color: var(--cor-primaria); font-size: 16px; }
.tabela-topo-dir { display: flex; align-items: center; gap: 10px; margin-left: auto; }

/* Linha pendente destacada (sobrio, ambar - nao e semaforo gritante). */
.te-tab tbody tr.linha-pendente td { background: var(--alerta-suave); }
.te-tab tbody tr.linha-pendente td:first-child { box-shadow: inset 3px 0 0 var(--alerta); }
.te-tab tbody tr.linha-pendente:hover td { background: var(--alerta-suave-hover); }

/* ==========================================================================
   Faturamento (Fase 5): grade de itens, controle venda/compra, reimpressao.
   ========================================================================== */
.cab-acoes { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }

/* Entrada x saida com pesos distintos, sem semaforo gritante (frontend-design 11.4). */
.badge-entrada { background: var(--ok-suave); color: var(--entrada); }
.badge-saida { background: var(--saida-suave); color: var(--saida); }

/* Aviso informativo (nota de credito e fato comercial). */
.aviso-info { display: flex; gap: 9px; align-items: flex-start; background: var(--info-suave);
  border: 1px solid var(--borda); border-radius: var(--raio-sm); padding: 10px 12px;
  font-size: 12.5px; color: var(--texto-secundario); line-height: 1.5; margin-bottom: 4px; }
.aviso-info i { color: var(--info); font-size: 16px; margin-top: 1px; }

/* Controle segmentado venda/compra (radio-livre, sem <select> nativo). */
/* align-self: flex-start e o que faz a caixa ter a largura dos botoes. O
   inline-flex sozinho nao basta: dentro de .campo (flex column) o padrao e
   align-items: stretch, e o filho estica ate a borda mesmo sendo inline. */
.seg { display: inline-flex; align-self: flex-start; border: 1px solid var(--borda-forte); border-radius: var(--raio-sm); overflow: hidden; }
.seg-btn { display: inline-flex; align-items: center; gap: 6px; padding: 8px 14px; background: var(--branco);
  border: none; cursor: pointer; font: inherit; font-size: 13px; color: var(--texto-secundario); transition: var(--transicao); }
.seg-btn + .seg-btn { border-left: 1px solid var(--borda-forte); }
.seg-btn.ativo { background: var(--cor-primaria); color: var(--texto-sobre-primaria); }
.seg-btn:not(.ativo):hover { background: var(--fundo-2); }
.seg.travado { opacity: .7; }
.seg.travado .seg-btn { cursor: not-allowed; }

/* Grade editavel de itens (mestre-detalhe). */
.itens-bloco { border: 1px solid var(--borda); border-radius: var(--raio-sm); margin-top: 4px; margin-bottom: 18px; }
.itens-cab { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 9px 12px; background: var(--fundo); border-bottom: 1px solid var(--borda);
  font-size: 12.5px; font-weight: 600; color: var(--texto-secundario); }
.itens-cab i { color: var(--cor-primaria); }
/* Lado direito do cabecalho: a chavinha "Produtos cadastrados" e o Adicionar item. */
.itens-cab-acoes { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.itens-modo { display: flex; align-items: center; gap: 8px; }
.itens-modo-rot { font-size: 12.5px; font-weight: 600; color: var(--texto-secundario); cursor: pointer; }
.itens-modo .cv-sw input:disabled + label { opacity: .45; cursor: not-allowed; }
/* O bloco da grade so rola de lado em tela estreita. Com overflow-x:auto SEMPRE, o
   navegador tambem recorta na vertical e o painel do SelectBusca (position:absolute,
   abre por baixo da celula) ficava escondido - achado do Ricardo na Nova Venda e na
   Nova Fatura (2026-09-05). No desktop as duas grades cabem no modal (fatura 760px,
   venda 880px, modal ~958px), entao nada precisa rolar. */
.itens-scroll { overflow: visible; }
@media (max-width: 940px) { .itens-scroll { overflow-x: auto; } }
/* A coluna Descricao e a unica sem largura fixa: sem um minimo, o select do
   catalogo caia para ~90px e o nome do produto quebrava em seis linhas. Com o
   minimo, a grade rola na horizontal dentro do bloco (.itens-scroll) em tela
   estreita, em vez de espremer a coluna que mais importa. */
.itens-grid .col-desc { min-width: 300px; }
.itens-grid .col-desc .selectbusca { min-width: 0; }
/* Nome longo nao pode esticar a linha: uma linha so, com reticencias. O nome
   inteiro continua legivel no painel aberto e no title. */
.itens-grid .col-desc .sb-label {
  display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* O painel pode passar da largura do gatilho: e onde se le o nome inteiro. */
.itens-grid .col-desc .sb-panel { min-width: 340px; }
/* table-layout: fixed faz a largura declarada VALER. No algoritmo automatico
   (o padrao) o width e so uma sugestao: o navegador nunca deixa a coluna menor
   que o conteudo minimo dela, que aqui e o texto do cabecalho - e por isso que
   ST e IPI ficavam mais estreitas que SEGURO e OUTROS pedindo o mesmo valor.
   Com fixed, quem nao tem width declarada divide o que sobra: e o caso da
   coluna Descricao, que continua esticando sozinha. */
.itens-grid { width: 100%; border-collapse: collapse; font-size: 13px; min-width: 760px;
  table-layout: fixed; }
/* Coluna do botao de remover (na venda, o <col class="col-remover">): fixa, para nao roubar o espaco da Descricao; no celular, o fim do arquivo. */
.itens-grid .no-sort, .itens-grid .col-remover { width: 46px; }
.itens-grid th { font-size: 10.5px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--texto-fraco); font-weight: 700; text-align: left; padding: 7px 8px; border-bottom: 1px solid var(--borda); }
.itens-grid td { padding: 5px 8px; border-bottom: 1px solid var(--borda); vertical-align: middle; }
.itens-grid tbody tr:last-child td { border-bottom: 1px solid var(--borda); }
.itens-grid .num { text-align: right; font-variant-numeric: tabular-nums; }
.itens-grid .col-qtd { width: 90px; }
.itens-grid .col-unit { width: 100px; }
.itens-grid .col-tot { width: 100px; white-space: nowrap; }
/* O .selectbusca herda min-width:200px da base e NAO cabia nos 170px da coluna: sobrava
   38px por cima da coluna do botao remover (medido pelo ADAO em 2026-09-05; defeito
   pre-existente, so ficou visivel agora). A coluna manda, como ja fazia a .col-desc. */
.itens-grid .col-imp { width: 170px; }
.itens-grid .col-imp .selectbusca { min-width: 0; }
/* Acrescimos por item (IPI, ST, Frete, Seguro, Desc., Outros): colunas recolhidas
   atras do expansor "Acrescimos" do cabecalho do bloco; a grade sem acrescimo
   continua identica a de antes (decisao 3b). */
.itens-grid .col-acr { display: none; width: 90px; }
.itens-grid.acr-aberto .col-acr { display: table-cell; }
/* Soma das colunas com o expansor aberto: 90 (qtd) + 100 (unit) + 6x120 (acr)
   + 100 (total) + 170 (imposto) + 46 (acao) + 250 minimos da descricao. Sem
   este piso a tabela comprimiria as colunas em vez de rolar. */
.itens-grid.acr-aberto { min-width: 1436px; }
.acr-btn i { transition: transform var(--transicao); }
.acr-btn.aberto i { transform: rotate(90deg); }
.acr-btn.aberto { border-color: var(--cor-primaria); color: var(--cor-primaria); }
/* Celula de acoes sem acao disponivel (linha cancelada): traco discreto. */
.acoes-vazio { font-size: 12px; }
/* Total de linha que nao fecha (desconto >= bruto ou valor negativo): o servidor
   recusa; aqui o numero avisa antes do POST. */
.itens-grid .tot-invalido { color: var(--vermelho); font-weight: 600; }

/* ===== Importacao de NF-e no modal de fatura (Padrao_Upload_Arquivo) =====
   REUSA .im-drop/.im-inp/.im-acao ja definidos acima (conciliacao); aqui so o
   que e proprio do bloco da NF-e, ESCOPADO em .nfe-imp para nao mexer nas
   outras telas de importacao (achado da verificacao adversarial: a redefinicao
   global mudava o layout da conciliacao sem a tela ter sido tocada). */
.nfe-imp { margin-bottom: 16px; }
.nfe-imp .im-drop { padding: 22px; }
/* Mensagem inline ANTES do botao no HTML: o margin-right:auto dela ancora o
   botao na direita (Acao_Primaria_a_Direita). */
.nfe-imp .im-acao { justify-content: flex-end; margin-top: 10px; }
.im-acao .im-msg { margin-right: auto; }
.im-arq { display: block; margin-top: 6px; font-weight: 600; color: var(--entrada); }
.im-msg { font-size: 12.5px; color: var(--texto-secundario); }
.im-msg.ok { color: var(--entrada); font-weight: 600; }
.im-msg.erro { color: var(--vermelho); font-weight: 600; }
/* Total das parcelas da NF-e que nao fecha com os itens editados. */
.preview-total.divergente { color: var(--vermelho); }
/* Avisos da importacao (NF-e repetida, ajuste de arredondamento): informam e
   nao bloqueiam (decisao 4a). */
.nfe-avisos { margin-top: 10px; }
/* Selo do modo "Parcelas da NF-e" no cabecalho do preview. */
.selo-nfe {
  display: inline-flex; align-items: center; gap: 4px; margin-left: 8px;
  font-size: 11px; font-weight: 600; padding: 2px 8px;
  border-radius: var(--raio-full); background: var(--cor-primaria-suave);
  color: var(--cor-primaria-escura);
}
/* Dados do fornecedor no modal de confirmacao da NF-e. */
.nfe-forn-dados { font-size: 13.5px; line-height: 1.6; color: var(--texto); }

/* ===== Finalidade de Produtos (Fase 6) ===== */
/* Abas por finalidade (Padrao_Tabs): sublinhado na cor da marca, nunca pilula. */
.pr-tabs { display: flex; gap: 6px; flex-wrap: wrap;
  border-bottom: 1px solid var(--borda); margin-bottom: 16px; }
.pr-tab { padding: 10px 16px; font-size: 13px; font-weight: 600;
  color: var(--texto-secundario); cursor: pointer; border: none;
  background: transparent; border-bottom: 2px solid transparent;
  display: inline-flex; align-items: center; gap: 6px; font-family: inherit; }
.pr-tab:hover { color: var(--texto); }
.pr-tab.ativo { color: var(--cor-primaria); border-bottom-color: var(--cor-primaria); }
/* Linha escondida pela aba (classe, nao style: convive com a busca da tabela). */
tr.fin-oculto { display: none; }
/* Toggle tipo 1 multi opcoes (Padrao_Toggle_Tipos): escolha na cor da marca. */
.pr-presets { display: inline-flex; align-items: center; gap: 4px; flex-wrap: nowrap;
  height: 38px; padding: 3px; border: 1px solid var(--borda);
  border-radius: 7px; background: var(--branco); }
.pr-presets button { height: 30px; border: 1px solid transparent;
  background: var(--branco); border-radius: 5px; padding: 0 10px;
  font-size: 12px; font-weight: 600; color: var(--texto-secundario);
  cursor: pointer; white-space: nowrap; font-family: inherit; }
.pr-presets button:hover { color: var(--cor-primaria); }
.pr-presets button.on { border-color: var(--cor-primaria);
  background: var(--cor-primaria-suave); color: var(--cor-primaria-escura); }
/* Opcao que um filtro do SelectBusca tirou de cena: .fin-oculto e a finalidade do
   produto no seletor da fatura; .sb-fora e o papel cliente/fornecedor
   (selectbusca.js, aplicarPapel). Classe e nao style: a busca mexe no display. */
.sb-opt.fin-oculto, .sb-opt.sb-fora { display: none !important; }
.itens-grid .input { min-height: 34px; padding: 6px 8px; }
.itens-grid td[data-item-total] span, .itens-grid .col-tot span { font-variant-numeric: tabular-nums; }
.itens-sub-rot { text-align: right; font-weight: 600; color: var(--texto-secundario); }

/* ==========================================================================
   Fase 6 (marco de corte): fluxo projetado (curva), DRE e posicao consolidada.
   ========================================================================== */
/* Curva de saldo projetado: SVG server-rendered (sem CDN, CSP-friendly). */
.graf-card { padding: 8px 8px 4px; }
.graf-fluxo { display: block; width: 100%; height: auto; }
.graf-fluxo .graf-area { fill: var(--cor-primaria-suave); opacity: .55; }
.graf-fluxo .graf-linha { fill: none; stroke: var(--cor-primaria); stroke-width: 2;
  stroke-linejoin: round; stroke-linecap: round; }
.graf-fluxo .graf-zero { stroke: var(--borda-forte); stroke-width: 1; stroke-dasharray: 4 4; }
/* Saldo projetado negativo: unico lugar (alem de erro) do vermelho forte (11.4). */
.graf-fluxo.negativo .graf-area { fill: var(--erro-suave); }
.graf-fluxo.negativo .graf-linha { stroke: var(--erro); }
.graf-eixo-rot { font-size: 12px; color: var(--texto-suave); display: flex; justify-content: space-between; padding: 0 6px 6px; }

/* Fase 8: segunda serie da curva (titulos + previstos). Tracejada e sem area, para
   ler como cenario, nao como fato - o que ja esta lancado e a linha cheia. */
.graf-fluxo .graf-linha-prev { fill: none; stroke: var(--texto-suave); stroke-width: 1.5;
  stroke-dasharray: 5 4; stroke-linejoin: round; stroke-linecap: round; }
.graf-legenda { display: flex; gap: 18px; flex-wrap: wrap; font-size: 12px;
  color: var(--texto-suave); padding: 0 6px 8px; }
.graf-legenda span { display: inline-flex; align-items: center; gap: 6px; }
.graf-legenda i.amostra { width: 16px; height: 0; border-top: 2px solid var(--cor-primaria); }
.graf-legenda i.amostra.prev { border-top: 2px dashed var(--texto-suave); }

/* Linha de dia com saldo projetado negativo: destaque forte (vermelho). */
.te-tab tbody tr.linha-negativa td { background: var(--erro-suave); }
.te-tab tbody tr.linha-negativa td:first-child { box-shadow: inset 3px 0 0 var(--erro); }
.te-tab tbody tr.linha-negativa:hover td { background: var(--erro-suave-hover); }
/* Linha "hoje" na projecao (ancora do saldo inicial). */
.te-tab tbody tr.linha-hoje td { background: var(--fundo); font-weight: 600; }

/* Recuo hierarquico da arvore de categorias no DRE (por nivel). */
.dre-n0 { font-weight: 700; }
.dre-n1 { padding-left: 22px; }
.dre-n2 { padding-left: 44px; }
.dre-n3 { padding-left: 66px; }
.dre-n4 { padding-left: 88px; }
.te-tab tbody tr.dre-sintetica td { background: var(--fundo); font-weight: 600; }
.te-tab tbody tr.dre-total td { border-top: 2px solid var(--borda-forte); font-weight: 700; background: var(--fundo-2); }
.dre-resultado .num { font-size: 15px; }

/* Cartoes da posicao consolidada (dashboard de abertura, nao e listagem). */
.pos-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 14px; margin-bottom: 16px; }
.pos-card { background: var(--branco); border: 1px solid var(--borda); border-radius: var(--raio); box-shadow: var(--sombra); padding: 16px 18px; }
.pos-card .rot { font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em; color: var(--texto-fraco); font-weight: 700; display: flex; align-items: center; gap: 7px; }
.pos-card .rot i { font-size: 15px; color: var(--cor-primaria); }
.pos-card .valor { font-size: 22px; font-weight: 700; margin-top: 8px; font-variant-numeric: tabular-nums; color: var(--texto); }
.pos-card .valor.saldo-negativo { color: var(--erro); }
.pos-card .detalhe { font-size: 12px; color: var(--texto-suave); margin-top: 4px; }
.pos-card .detalhe.vencido { color: var(--alerta); font-weight: 600; }
.itens-sub { font-weight: 700; font-variant-numeric: tabular-nums; }
.itens-grid tfoot td { border-top: 1px solid var(--borda-forte); border-bottom: none; padding-top: 9px; }

/* SelectBusca compacto dentro da grade. */
.sb-mini .sb-display { min-height: 34px; padding: 5px 8px; font-size: 12.5px; }

/* Reimpressao / detalhe da fatura. */
.doc-fatura { background: var(--branco); border: 1px solid var(--borda); border-radius: var(--raio);
  padding: 20px 22px; box-shadow: var(--sombra); }
.doc-cab { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 24px; padding-bottom: 16px;
  border-bottom: 1px solid var(--borda); margin-bottom: 6px; }
.doc-campo { display: flex; flex-direction: column; gap: 2px; }
.doc-campo-largo { grid-column: 1 / -1; }
.doc-rot { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--texto-fraco); }
.doc-val { font-size: 14px; color: var(--texto); }
.doc-secao { font-size: 13px; margin: 18px 0 8px; display: flex; align-items: center; gap: 8px; color: var(--texto-secundario); }
.doc-secao i { color: var(--cor-primaria); }
.doc-tab tfoot td { border-top: 1px solid var(--borda-forte); border-bottom: none; font-weight: 600; }
.doc-tot-rot { color: var(--texto-secundario); }
.doc-tot { font-size: 15px; font-weight: 700; color: var(--texto); }
@media (max-width: 720px) { .doc-cab { grid-template-columns: 1fr; } }

/* ===== Orcado x realizado (relatorio 6): resumo ===== */
.or-resumo { display: flex; flex-wrap: wrap; gap: 26px; padding: 14px 16px; }
.or-bloco { display: flex; flex-direction: column; gap: 3px; font-size: 13px; color: var(--texto-secundario); }
.or-bloco .or-rot { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--texto-fraco); margin-bottom: 2px; }
.or-bloco .num { font-variant-numeric: tabular-nums; }

/* ===== Grade de orcamento (digitacao mes x categoria) ===== */
.orc-topo { display: flex; align-items: center; gap: 12px; justify-content: space-between; flex-wrap: wrap; margin-bottom: 10px; }
/* A busca e a opcao andam juntas na esquerda: com as duas soltas o
   space-between jogaria a caixa de selecao para o meio da faixa, longe das duas
   pontas a que ela pertence. */
.orc-topo-esq { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; flex: 1 1 auto; min-width: 0; }
.orc-opt { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; cursor: pointer;
  font-size: 12.5px; font-weight: 600; color: var(--texto-secundario); }
.orc-acoes { display: flex; gap: 8px; flex-wrap: wrap; }
.orc-dica { font-size: 12.5px; color: var(--entrada); background: var(--ok-suave); border-radius: var(--raio-sm); padding: 8px 12px; margin-bottom: 10px; }
/* --cel-pad e o padding LATERAL da celula da grade, em token porque a largura da
   coluna Categoria desconta exatamente isto (ver "--cat-col" mais abaixo). */
.grade-orc { --cel-pad: 5px; }
.grade-orc th, .grade-orc td { padding: 5px var(--cel-pad); }
.grade-orc .orc-inp {
  width: 85px; height: 32px; padding: 4px 7px; text-align: right; font-variant-numeric: tabular-nums;
  border: 1px solid var(--borda); border-radius: var(--raio-sm); background: var(--branco); font: inherit; font-size: 12.5px;
}
.grade-orc .orc-inp:focus { outline: none; border-color: var(--cor-primaria); box-shadow: 0 0 0 2px var(--cor-primaria-suave); }
.grade-orc .orc-inp[readonly] { background: var(--fundo); color: var(--texto-secundario); }
.grade-orc .orc-cat-cod { color: var(--texto-secundario); font-variant-numeric: tabular-nums; margin-right: 2px; }
.grade-orc .orc-row-total { font-weight: 600; font-variant-numeric: tabular-nums; }
.grade-orc tfoot td { font-variant-numeric: tabular-nums; }
.orc-rep {
  display: inline-grid; place-items: center; width: 24px; height: 24px; margin-right: 4px; vertical-align: middle;
  border: 1px solid var(--borda-forte); border-radius: var(--raio-sm); background: var(--branco);
  color: var(--texto-secundario); cursor: pointer; font-size: 12px;
}
.orc-rep:hover { border-color: var(--cor-primaria); color: var(--cor-primaria); }
/* Coluna Categoria: largura DECLARADA, e o nome que nao couber sai com
   reticencias (pedido do Ricardo, 2026-09-08). Antes a coluna tinha o tamanho do
   MAIOR nome do plano: uma linha so ("2.02.015 DESPESAS ALIMENTACAO SOCIOS E/OU
   ADMINISTRADORES", 494px) esticava a coluna para 510px nas 148, e cada pixel
   dela e um pedaco de mes que sai da tela.

   O corte NAO passa por `table-layout: fixed`, o caminho das listagens de
   Clientes e de Produtos: la todas as colunas sao texto, aqui as outras treze tem
   tamanho proprio (o campo de digitacao e o total em dinheiro, que precisa caber
   "R$ 999.999,99") e o fixed passaria a reparti-las pela largura do quadro. Quem
   corta e o proprio bloco de texto, com largura em pixel: a celula ganha um
   tamanho maximo conhecido, a coluna para de crescer com o nome, e nada mais na
   tabela muda. Por isso a largura vive no bloco de dentro e nao so na celula -
   no algoritmo automatico a largura da celula e sugestao, e o conteudo a estica
   de volta.

   360px sao medidos, nao no olho: com o padding da celula sobram 344px de texto,
   que basta para ~88% do plano do seed (p50=273, p75=313, p90=352, maior=494) e
   devolve cerca de um mes e meio de grade a vista em 1440. Quem for cortado tem o
   nome inteiro no title da celula, como na listagem de Clientes e Fornecedores.

   O CODIGO da categoria e opcional, e sai por PADRAO (pedido do Ricardo,
   2026-09-08; a caixa "Mostrar Codigo da Categoria" o traz de volta). Sao DUAS
   larguras porque esconder o codigo sem encolher a coluna nao devolveria espaco
   nenhum - so deixaria um vao a direita de cada nome. 306px tambem sao medidos: o
   prefixo custa 52,7px em media, e nesta largura o numero de nomes cortados e o
   MESMO dos 360px com codigo (16 de 148), ou seja tirar o codigo nao piora a
   leitura dos nomes - so devolve meio mes de grade. O title da celula continua
   trazendo codigo E descricao, entao o codigo escondido esta a um hover de
   distancia. */
.grade-orc { --cat-col: 306px; }                  /* sem o codigo (o padrao) */
.grade-orc.com-codigo { --cat-col: 360px; }
.grade-orc .orc-cat-cod { display: none; }
.grade-orc.com-codigo .orc-cat-cod { display: inline; }
.grade-orc th.orc-col-cat, .grade-orc td.orc-cat { width: var(--cat-col); }
/* O desconto do padding sai do MESMO token que pinta o padding (--cel-pad, na
   regra de celula acima), e nao de um numero repetido aqui: com o "16px" escrito
   a mao, mexer no padding da grade deixava o bloco 6px mais estreito que a
   celula e a coluna parava de bater com a largura declarada - em silencio, porque
   sobra so um vao a direita. Quem pegou foi a suite de aceitacao. */
.grade-orc td.orc-cat > span {
  display: block; width: calc(var(--cat-col) - var(--cel-pad) * 2);
  overflow: hidden; text-overflow: ellipsis;
}
/* Primeira coluna fixa na rolagem horizontal (categoria sempre visivel). */
.grade-orc th.orc-col-cat, .grade-orc td.orc-cat { position: sticky; left: 0; z-index: 1; background: var(--branco); }
.grade-orc thead th.orc-col-cat { z-index: 2; background: var(--fundo); }
.grade-orc tbody tr.dre-sintetica td.orc-cat { background: var(--fundo); }
.grade-orc tbody tr:hover td.orc-cat { background: var(--fundo); }

/* [RODAPE FIXO] A linha de Totais gruda na base do quadro (pedido do Ricardo,
   2026-09-08). E o mesmo modelo do <thead> do cabecalho fixo, do outro lado: o
   corpo rola por baixo e o resultado do mes fica sempre a vista - antes era
   preciso descer as 148 categorias ate o fim para le-lo, e ele e justamente o
   numero que se olha enquanto se digita.

   Escopado em .grade-orc de proposito: outras cinco telas tem <tfoot> (DRE,
   orcado x realizado, posicao, fatura e o detalhe dela) e nenhuma pediu isto;
   ligar no .te-tab generico mudaria todas de uma vez.

   O FUNDO nao e enfeite, e requisito: sem ele as linhas passariam POR DENTRO do
   rodape enquanto rolam. A celula de Totais ja era --fundo-2 (ela e sticky na
   esquerda); agora a faixa inteira acompanha. A borda de cima vai como box-shadow
   porque com border-collapse a borda nao acompanha o sticky e some ao rolar - a
   mesma licao do cabecalho. z-index 3: acima das linhas (a coluna Categoria
   sticky e 1) e abaixo do popup do menu (60) e do painel do SelectBusca (50).

   O peso e a borda estao escritos AQUI, e nao herdados: o <tr> leva a classe
   .dre-total, mas a regra dela e ".te-tab tbody tr.dre-total td" e este <tr> mora
   no <tfoot> - nunca chegou a valer nesta tela.

   O sticky vai nas CELULAS e nao no <tfoot>, ao contrario do cabecalho. Com o
   <tfoot> sticky a coluna Totais PERDE o gruda da esquerda: medido, ela ia parar
   em -300px ao rolar a grade de lado, porque o sticky horizontal da celula passa
   a se resolver dentro do rodape ja deslocado, e nao no quadro. Na celula, cada
   uma gruda no eixo que lhe cabe e a primeira gruda nos DOIS - o canto. */
.grade-orc tfoot td {
  position: sticky; bottom: 0; z-index: 3;
  background: var(--fundo-2); font-weight: 700; border-bottom: none;
  box-shadow: inset 0 1px 0 var(--borda-forte);
}
/* O canto (Totais): gruda tambem na esquerda e passa por cima das vizinhas da
   propria faixa quando a grade rola de lado. */
.grade-orc tfoot td:first-child { left: 0; z-index: 4; }

/* Impressao: so o documento (esconde navegacao/acoes). */
@media print {
  .sidebar, .topbar, .overlay-mob, .flash-area, .loading-overlay, .cab-acoes,
  .btn-menu, .ajuda, #modalConfirm, #modalLink { display: none !important; }
  .conteudo { margin: 0 !important; }
  .app-shell { display: block !important; }
  .doc-fatura { border: none; box-shadow: none; padding: 0; }
}

/* ==========================================================================
   Toggle On/Off (Padrao_Toggle_OnOff da vault): switch 42x24, verde no on.
   Substitui o checkbox nativo em liga/desliga. Cor ON = token --ok do projeto.
   ========================================================================== */
/* `display: inline-block` nao e enfeite: o `.cv-sw` e um <span>, e em `display:
   inline` a largura e a altura NAO se aplicam. Nas telas antigas ele sempre caiu
   dentro de um container flex, que blockifica o filho e escondia o problema; posto
   numa celula de tabela (T9/F7), o componente colapsava para 0x0 e o switch sumia da
   tela. Em contexto flex esta declaracao e inofensiva, porque o container blockifica
   o filho de qualquer jeito. */
.cv-sw { position: relative; display: inline-block; width: 42px; height: 24px; flex: 0 0 auto; vertical-align: middle; }
/* O campo fica POR BAIXO do desenho, invisivel, e nao fora da pagina: com
   `display: none` o interruptor saia do Tab e do leitor de tela (auditoria 09/2026,
   ponto 6). O clique continua caindo no <label>, que vem depois e fica por cima. */
.cv-sw input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; }
.cv-sw label {
  position: absolute; inset: 0; background: var(--borda-forte);
  border-radius: 999px; cursor: pointer; transition: .15s;
}
.cv-sw label::after {
  content: ''; position: absolute; top: 2px; left: 2px; width: 20px; height: 20px;
  background: var(--branco); border-radius: 50%; transition: .15s; box-shadow: var(--sombra-bola);
}
.cv-sw input:checked + label { background: var(--ok); }
.cv-sw input:checked + label::after { transform: translateX(18px); }
.cv-sw input:focus-visible + label { outline: 2px solid var(--cor-primaria); outline-offset: 2px; }

/* ==========================================================================
   Editor do menu (/admin/menu): board de grupos e itens arrastaveis.
   Drag por handle dedicado (Padrao_Mural_Postit): o item nao arrasta pelo corpo.
   ========================================================================== */
.me-topo { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-bottom: 14px; }
.me-topo .me-dica { color: var(--texto-suave); font-size: 13px; flex: 1; min-width: 220px; }
.me-acoes { display: flex; gap: 8px; flex-wrap: wrap; }

.me-board { display: flex; flex-direction: column; gap: 12px; max-width: 720px; }

/* Grupo (card) */
.me-grupo {
  border: 1px solid var(--borda-forte); border-radius: var(--raio); background: var(--fundo);
}
.me-grupo.arrastando { opacity: .5; }
.me-grupo.alvo { border-color: var(--cor-primaria); box-shadow: 0 0 0 3px var(--cor-primaria-suave); }
.me-grupo-cab {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  border-bottom: 1px solid var(--borda); border-radius: var(--raio) var(--raio) 0 0;
  background: var(--fundo-2);
}
.me-grupo-nome { font-weight: 700; font-size: 13px; letter-spacing: .02em; flex: 1; }
.me-grupo-contagem { font-size: 12px; color: var(--texto-suave); }

/* Handle de arraste (grupo e item) */
.me-handle {
  cursor: grab; color: var(--texto-fraco); font-size: 18px; line-height: 1;
  display: inline-flex; padding: 2px; border-radius: var(--raio-sm);
}
.me-handle:active { cursor: grabbing; }
.me-handle:hover { color: var(--texto-secundario); background: var(--fundo); }
/* O cabecalho inteiro e a pegada do GRUPO (menu-editor.js arma o arraste no mousedown
   dele, nao so na alcinha: nao ha toggle no cabecalho). O grupo fixo (Admin) nao tem
   alcinha e fica sem a mao. :has() de um nivel so - aninhado o navegador descarta. */
.me-grupo-cab:has([data-handle-grupo]) { cursor: grab; user-select: none; }
.me-grupo-cab:has([data-handle-grupo]):active { cursor: grabbing; }

/* Lista e item */
.me-itens { list-style: none; margin: 0; padding: 6px; min-height: 42px; }
.me-itens.vazia { display: flex; align-items: center; justify-content: center;
  color: var(--texto-fraco); font-size: 12.5px; font-style: italic; }
.me-item {
  display: flex; align-items: center; gap: 10px; padding: 8px 10px;
  border: 1px solid transparent; border-radius: var(--raio-sm); background: var(--branco);
}
.me-item + .me-item { margin-top: 4px; }
.me-item:hover { border-color: var(--borda); }
.me-item.arrastando { opacity: .5; }
.me-item.oculto { background: repeating-linear-gradient(45deg, var(--fundo-2), var(--fundo-2) 6px, transparent 6px, transparent 12px); }
.me-item.oculto .me-item-nome { color: var(--texto-fraco); }
.me-item-ico { font-size: 17px; color: var(--texto-secundario); flex: 0 0 auto; }
.me-item-nome { flex: 1; font-size: 13.5px; font-weight: 500; }
.me-item-tag {
  font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  background: var(--fundo-2); color: var(--texto-fraco); padding: 2px 7px; border-radius: 999px;
}
.me-item-fix { font-size: 11px; color: var(--texto-fraco); display: inline-flex; align-items: center; gap: 3px; }
.me-item.arrastavel-alvo { border-color: var(--cor-primaria); background: var(--cor-primaria-suave); }

/* ==========================================================================
   Ficha de cadastro (cliente/fornecedor): grade de 12 colunas, secoes rotuladas,
   switch Ativo e retorno da validacao de documento.
   ========================================================================== */
/* Cabecalho da ficha: identificacao do registro (codigo + data de cadastro) na
   esquerda, seletor de origem (Brasil/Exterior) na direita. */
.ficha-origem {
  display: flex; justify-content: space-between; align-items: flex-end;
  gap: 14px; flex-wrap: wrap; margin-bottom: 16px;
}
.ficha-id { display: flex; gap: 14px; }
.ficha-id .campo { margin-bottom: 0; }
.ficha-id input[name="codigo"] { width: 96px; text-align: center; }
.ficha-id input[name="data_cadastro"] { width: 160px; }
/* Codigo e do sistema: parece campo, mas nao se digita nele. */
.ficha-id input[readonly] { background: var(--fundo-2); color: var(--texto-secundario); cursor: default; }
.ficha-id input[readonly]:focus { border-color: var(--borda); box-shadow: none; }

.ficha-grade { display: grid; grid-template-columns: repeat(12, 1fr); gap: 0 14px; }
.ficha-grade .col-2 { grid-column: span 2; }
.ficha-grade .col-3 { grid-column: span 3; }
.ficha-grade .col-4 { grid-column: span 4; }
.ficha-grade .col-5 { grid-column: span 5; }
.ficha-grade .col-6 { grid-column: span 6; }
.ficha-grade .col-8 { grid-column: span 8; }

/* Divisor com rotulo (CONTATO, ENDERECO): a linha ocupa o espaco que sobra. */
.ficha-secao {
  display: flex; align-items: center; gap: 8px; margin: 6px 0 14px;
  font-size: 11px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--texto-fraco);
}
.ficha-secao i { font-size: 14px; }
.ficha-secao::after { content: ""; flex: 1; height: 1px; background: var(--borda); }

/* Badge PF/PJ ao lado do rotulo do documento. */
.badge-doc {
  display: inline-flex; align-items: center; margin-left: 6px; padding: 1px 6px;
  border-radius: 999px; background: var(--cor-primaria-suave); color: var(--cor-primaria-escura);
  font-size: 9.5px; font-weight: 700; letter-spacing: .04em;
}
.badge-doc[hidden] { display: none; }

/* Retorno da validacao/consulta, na propria dica do campo. */
.dica-ok { color: var(--ok); }
.dica-erro { color: var(--erro); }
.dica-alerta { color: var(--alerta); }

.caixa-alta { text-transform: uppercase; }

/* Faixa do Ativo: destacada, como um interruptor de estado do registro. */
.ficha-ativo {
  display: flex; align-items: center; gap: 12px; margin-top: 4px;
  padding: 12px 14px; border: 1px solid var(--cor-primaria-suave);
  background: var(--cor-primaria-suave); border-radius: var(--raio-sm);
}
.ficha-ativo .sw-rot { font-size: 13.5px; font-weight: 600; color: var(--texto-secundario); }

/* Switch acionado por <button>: o estado real fica num hidden, entao o
   abrirModal() consegue preencher na edicao (o mesmo caminho dos outros campos). */
.sw {
  position: relative; width: 42px; height: 24px; flex: 0 0 auto; padding: 0;
  border: none; border-radius: 999px; cursor: pointer;
  background: var(--borda-forte); transition: var(--transicao);
}
.sw .sw-bola {
  position: absolute; top: 2px; left: 2px; width: 20px; height: 20px;
  background: var(--branco); border-radius: 50%; transition: var(--transicao);
  box-shadow: var(--sombra-bola);
}
.sw.ligado { background: var(--cor-primaria); }
.sw.ligado .sw-bola { transform: translateX(18px); }
.sw:focus-visible { outline: 2px solid var(--cor-primaria); outline-offset: 2px; }

@media (max-width: 720px) {
  .ficha-grade { grid-template-columns: repeat(6, 1fr); }
  .ficha-grade .col-8, .ficha-grade .col-6, .ficha-grade .col-5,
  .ficha-grade .col-4, .ficha-grade .col-3 { grid-column: span 6; }
  .ficha-grade .col-2 { grid-column: span 3; }
}

/* Campo recusado na trava de envio (ex.: Tipo em branco na ficha do cadastro). */
.campo-invalido .sb-display, .input.campo-invalido {
  border-color: var(--erro);
  box-shadow: 0 0 0 3px var(--erro-suave);
}

/* ==========================================================================
   Cadastro de conta financeira (/cadastros/contas): asterisco de obrigatorio,
   logo do banco na listagem e a caixa de upload do logo no modal.
   ========================================================================== */
.obrigatorio { color: var(--erro); font-weight: 700; }

/* Listagem: logo (ou o icone de fallback) colado na descricao da conta. */
.conta-cel { display: flex; align-items: center; gap: 9px; }
.conta-logo {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; flex: 0 0 auto;
  border: 1px solid var(--borda); border-radius: var(--raio-sm);
  background: var(--fundo-2); color: var(--texto-fraco); font-size: 15px;
}
.conta-logo img { width: 100%; height: 100%; object-fit: contain; border-radius: var(--raio-sm); }

/* Caixa de upload: previa a esquerda, seletor + regras a direita. */
.logo-box {
  display: flex; align-items: center; gap: 14px; margin: 4px 0 14px;
  padding: 14px; border: 1px solid var(--borda); border-radius: var(--raio);
  background: var(--fundo-2);
}
.logo-box.arrastando { border-color: var(--cor-primaria); background: var(--cor-primaria-suave); }
.logo-previa {
  display: flex; align-items: center; justify-content: center;
  width: 72px; height: 72px; flex: 0 0 auto; padding: 6px;
  border: 1px solid var(--borda-forte); border-radius: var(--raio-sm);
  background: var(--branco); color: var(--texto-fraco); font-size: 30px;
}
.logo-previa img { max-width: 100%; max-height: 100%; object-fit: contain; }
.logo-corpo { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.logo-titulo {
  font-size: 11px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--texto-fraco);
}
.logo-chamada {
  display: inline-flex; align-items: center; gap: 5px; cursor: pointer;
  font-size: 12.5px; font-weight: 600; color: var(--cor-primaria);
}
.logo-file { font-size: 12px; color: var(--texto-suave); max-width: 100%; }
.btn-remover-logo {
  align-self: flex-start; margin-top: 2px; padding: 0; border: 0; background: none;
  cursor: pointer; font-size: 12px; color: var(--erro);
  display: inline-flex; align-items: center; gap: 4px;
}
.btn-remover-logo[hidden] { display: none; }

@media (max-width: 620px) {
  .logo-box { flex-direction: column; align-items: flex-start; }
}

/* ============ Importacao de cadastro por planilha (.xlsx) ============ */

/* Passo a passo curto no topo do modal: baixar o modelo antes de enviar. */
.imp-passos {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  background: var(--cor-primaria-suave); border: 1px solid var(--borda);
  border-radius: var(--raio-sm); padding: 12px 14px; margin-bottom: 16px;
}
.imp-passos p { margin: 0; font-size: 13px; color: var(--texto-secundario); flex: 1 1 260px; }
.imp-passos p strong { color: var(--texto); }

/* Relatorio da importacao (o que entrou e o que ficou de fora, por linha). */
.imp-resultado { margin-top: 16px; }
.imp-resultado[hidden] { display: none; }
.imp-linha {
  border-radius: var(--raio-sm); padding: 10px 12px; margin-bottom: 8px;
  font-size: 13px; font-weight: 600;
}
.imp-ok { background: var(--ok-suave); color: var(--ok); }
.imp-erro { background: var(--erro-suave); color: var(--erro); }
.imp-aviso { background: var(--alerta-suave); color: var(--alerta); }
.imp-erros {
  margin: 0; padding: 8px 12px 8px 28px; max-height: 220px; overflow-y: auto;
  border: 1px solid var(--borda); border-radius: var(--raio-sm);
  background: var(--fundo); font-size: 12.5px; color: var(--texto-secundario);
}
.imp-erros li { margin: 3px 0; }
.imp-erros strong { color: var(--texto); }

/* ==========================================================================
   Adiantamentos (Trabalho 4): slots fixos de acao na listagem, fila de
   parcelas do modal Utilizar e detalhe (utilizacoes/devolucoes).
   ========================================================================== */

/* Acao indisponivel: o slot NAO some (padrao Tabela, na vault) - vira a versao
   esmaecida, nao clicavel, com title especifico dizendo por que. */
.btn-icone.desabilitado {
  opacity: .38; cursor: not-allowed; pointer-events: auto;
  display: inline-flex; align-items: center; justify-content: center;
}
.btn-icone.desabilitado:hover { border-color: var(--borda); color: inherit; }

/* Celula de acoes com 4 slots lado a lado. */
.acoes-adiant { white-space: nowrap; }
.acoes-adiant .btn-icone { margin-right: 4px; }
/* Todo slot pousa na MESMA linha, seja ele <button>, <a>, <span> ou o <form> do
   POST sem JS. Sem isto o form (que ja vinha com vertical-align: middle) ficava
   3,6px ABAIXO dos botoes soltos, que caem no baseline - medido na tela de
   Clientes da plataforma, onde suporte e ativar/desativar sao form e os outros
   tres slots sao botao. Como todo slot tem 25px de altura, alinhar pelo meio
   deixa a fileira reta em qualquer mistura. */
.acoes-adiant > * { vertical-align: middle; }

/* Fila de parcelas do modal Utilizar e tabelas do detalhe. */
.ut-lista { border: 1px solid var(--borda); border-radius: var(--raio-sm); overflow-x: auto; }
.ut-tab { width: 100%; }
.ut-tab td input.input { height: 34px; max-width: 130px; margin-left: auto; }
.ut-tab tr.ut-estourada td { background: var(--erro-suave); }
.ut-vazio {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 22px 14px; font-size: 13px; color: var(--texto-fraco);
}
.ut-vazio[hidden] { display: none; }
.ut-total {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: 12px; padding: 10px 14px;
  border: 1px solid var(--borda); border-radius: var(--raio-sm);
  background: var(--fundo-2); font-size: 13px; font-weight: 600;
}
.ut-aviso {
  margin-top: 10px; padding: 10px 12px; border-radius: var(--raio-sm);
  background: var(--erro-suave); color: var(--erro);
  font-size: 13px; font-weight: 600;
}
.det-sub {
  display: flex; align-items: center; gap: 6px;
  margin: 16px 0 8px; font-size: 13px; font-weight: 700; color: var(--texto);
}
.det-sub:first-of-type { margin-top: 4px; }
.det-nada { font-size: 13px; margin: 4px 0 8px; }

/* Aviso no modal de baixa: a pessoa tem credito de adiantamento (segunda porta).
   Informativo, na familia da marca - nao e erro. */
.bx-adiant {
  display: flex; align-items: flex-start; gap: 8px;
  margin-bottom: 14px; padding: 10px 12px;
  border: 1px solid var(--borda); border-radius: var(--raio-sm);
  background: var(--cor-primaria-suave); font-size: 13px;
  color: var(--texto-secundario);
}
.bx-adiant[hidden] { display: none; }
.bx-adiant i { font-size: 16px; color: var(--cor-primaria-escura); flex: 0 0 auto; margin-top: 1px; }
.bx-adiant a { font-weight: 600; color: var(--cor-primaria-escura); }

/* ===== Desconto de Duplicatas (Trabalho 5, Fase 21) ===== */
/* Modal com SelectBusca dentro = dialog HTML5 top-layer (padrao Modal
   Popup-Centrado, na vault): o top-layer dispensa z-index (padrao Elevacao, na
   vault). E o primeiro dialog do projeto; os modais sem SelectBusca continuam no
   .modal-bg de sempre.
   Centrado pelo jeito do proprio <dialog> (inset 0 e margin auto, com a altura
   fit-content que o navegador ja da a ele), e nao por transform (auditoria
   09/2026, RESP-02; decisao 133): transform faz da caixa a referencia de todo
   position:fixed de dentro, e o painel do SelectBusca, que aberto e fixed, se
   mediria pela caixa, e nao pela tela (o selectbusca.js mede a origem do painel
   e acerta a conta mesmo assim; sem o transform, a conta e a da tela). */
dialog.popup-centrado {
  position: fixed; inset: 0; margin: auto;
  border: 0; padding: 0;
  border-radius: var(--raio-lg);
  background: var(--branco);
  width: 92%; max-width: 520px;
  box-shadow: var(--sombra-lg);
  /* O visible nasceu para o painel do SelectBusca, quando ele era absolute e
     saia pela borda. Fica porque o overflow:auto que o navegador da ao dialog
     faria a caixa INTEIRA rolar, cabecalho e rodape junto: quem rola e o corpo. */
  overflow: visible !important;
  /* O dialog nativo ja nasce com max-height do navegador; com overflow
     visivel, conteudo alem dela VAZA para fora da caixa (o rodape apareceu
     solto na tela do Ricardo, 2026-08-18). Coluna flexivel: cabecalho e rodape
     ficam fixos, e quem encolhe e rola e o CORPO. O dvh desconta a barra do
     navegador do celular, que o vh nao desconta; o vh fica de fallback. */
  max-height: calc(100vh - 48px);
  max-height: calc(100dvh - 48px);
}
/* O display SO com [open]: declarar display direto no dialog sobrescreve o
   display:none nativo do dialog FECHADO e ele nasce aberto por CSS, sem
   backdrop, travando a tela (bug pego pelo Ricardo em 2026-08-18; mesma
   familia do [hidden] x display de classe da F13). */
dialog.popup-centrado[open] { display: flex; flex-direction: column; }
dialog.popup-centrado::backdrop { background: var(--veu-dialogo); }
dialog.popup-centrado.popup-largo { max-width: 1000px; }
/* O aviso de sessao encerrada (main.js, window.api): a caixa da confirmacao, num
   <dialog> para ficar por cima de qualquer modal aberto. */
dialog.popup-centrado.modal-confirm { max-width: 440px; text-align: center; }
dialog.popup-centrado > .modal-cab { flex: 0 0 auto; }
dialog.popup-centrado form {
  display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0;
}
dialog.popup-centrado .modal-corpo {
  display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0;
  /* Quem rola quando falta altura (auditoria 09/2026, RESP-02; decisao 133).
     Ate entao nao rolava: o overflow daqui recortava o painel do SelectBusca
     (achado do verificador da F21), e na janela sem fila para encolher o fim do
     corpo ia para baixo do rodape (com o celular deitado, o Valor do Pagar
     fatura e 15 dos 21 campos do Receber venda ficavam fora de alcance). O
     painel aberto agora e fixed, e o overflow nao o alcanca. O contain segura a
     rolagem aqui: no fim do corpo, ela nao passa para a pagina atras da janela. */
  overflow-y: auto; overscroll-behavior: contain;
}
dialog.popup-centrado .modal-rodape { flex: 0 0 auto; }
/* Quem rola e a FILA: ocupa o que sobrar da altura e nunca empurra o rodape
   para fora. Quando nem os 140px dela cabem (celular), rola o corpo inteiro. */
dialog.popup-centrado .ut-lista {
  flex: 1 1 auto; min-height: 140px; overflow-y: auto;
}
/* O totalizador reusado aqui tem TRES resumos (face/encargos/liquido), nao o
   par rotulo+valor do modal de adiantamentos: alinha a esquerda com folego e
   quebra em tela estreita. */
dialog.popup-centrado .ut-total {
  justify-content: flex-start; gap: 8px 22px; flex-wrap: wrap;
}
dialog.popup-centrado .ut-total strong { margin-left: 6px; }

/* Checkbox proprio da selecao em lote (padrao Selecao em Lote, na vault):
   nunca o do sistema operacional. O check e uma borda em L girada 45 graus. */
.tsel {
  appearance: none; -webkit-appearance: none;
  width: 18px; height: 18px; flex: none; margin: 0; position: relative;
  border: 1.5px solid var(--borda); border-radius: 5px;
  background: var(--branco); cursor: pointer;
  transition: background .12s, border-color .12s;
}
.tsel:hover { border-color: var(--cor-primaria); }
.tsel:checked { background: var(--cor-primaria); border-color: var(--cor-primaria); }
.tsel:checked::after {
  content: ''; position: absolute; left: 5px; top: 1px;
  width: 5px; height: 10px;
  border: solid var(--branco); border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
/* Cabecalho tem TRES estados: o traco do indeterminate e o "parte marcada". */
.tsel:indeterminate { background: var(--cor-primaria); border-color: var(--cor-primaria); }
.tsel:indeterminate::after {
  content: ''; position: absolute; left: 3px; top: 7px;
  width: 10px; height: 2px; background: var(--branco); border: 0; transform: none;
}
.tsel:focus-visible { outline: 2px solid var(--cor-primaria); outline-offset: 2px; }

/* Aviso de validacao DENTRO do modal (padrao Modal Nao Fecha Sozinho, na
   vault): erro nao fecha nem recarrega; a pessoa decide. */
.ds-aviso {
  margin-top: 12px; padding: 10px 12px;
  border: 1px solid var(--erro); border-radius: var(--raio-sm);
  background: var(--erro-suave); color: var(--erro); font-size: 13px;
}
.ds-aviso[hidden] { display: none; }

/* Grade de taxas da adquirente (Trabalho 7, /cadastros/adquirentes).
   NAO reusa .ut-lista de proposito: aquela tem overflow-x auto, e overflow em UM
   eixo faz o navegador computar auto no OUTRO tambem - o painel do SelectBusca
   da linha seria recortado pela propria caixa da grade, que e o mesmo defeito
   que o popup-centrado resolve no <dialog>. Aqui a caixa nao recorta nada, e
   quem rola, se precisar, e o corpo do modal. */
.adq-grade { border: 1px solid var(--borda); border-radius: var(--raio-sm); }
.adq-grade .ut-tab td { vertical-align: middle; }
.adq-grade .ut-tab td .selectbusca { min-width: 170px; }
/* 34px, a MESMA altura dos campos numericos da linha. O .sb-mini sozinho nao
   resolve: ele so baixa o min-height, e o height: 40px da regra base do
   SelectBusca continua valendo - medido no navegador, o controle ficava 6px
   mais alto que os irmaos da propria linha. */
.adq-grade .ut-tab td .selectbusca .sb-display { height: 34px; }
.adq-grade .ut-tab td input.input { max-width: 110px; }
.adq-grade .ut-tab td input.input:disabled { background: var(--fundo-2); cursor: not-allowed; }

/* ============================================================================
   Faixa de acoes da selecao em lote (Trabalho 7, Fase 30).
   Padrao_Selecao_em_Lote, na vault: "as acoes sobre o que foi marcado moram
   numa faixa escura que sobe do rodape, nunca em botoes soltos acima da tabela,
   ligados o tempo todo". So existe com algo marcado, e escura (nao na cor da
   marca) para se ler como MODO temporario, e nunca passa por baixo do menu.
   Elevacao por TOKEN nomeado (--z-barra-acao), como manda o
   Padrao_Elevacao_Zindex. O token nasce aqui porque esta e a camada nova; as
   camadas ANTIGAS do projeto continuam com numero no olho, e migra-las para a
   escala inteira e a decisao GLOBAL registrada na F29b.
   ========================================================================== */
.tsel-bar {
  position: fixed; bottom: 0; left: var(--sidebar-width); right: 0;
  z-index: var(--z-barra-acao);
  display: none; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 24px; background: var(--barra-acao); color: var(--branco);
  font-size: 13.5px; box-shadow: var(--sombra-barra-acao);
  animation: tselSobe .18s ease;
}
.tsel-bar:not([hidden]) { display: flex; }
.tsel-bar .btn { min-height: 36px; }
.tsel-bar-sub { color: color-mix(in srgb, var(--branco) 72%, transparent); margin-left: 6px; }
.tsel-bar-acoes { margin-left: auto; display: flex; gap: 8px; }
@keyframes tselSobe { from { transform: translateY(100%); } to { transform: translateY(0); } }
@media (max-width: 880px) { .tsel-bar { left: 0; } }

/* Coluna do checkbox da listagem: largura do controle, sem virar coluna larga. */
.col-sel { width: 34px; text-align: center; }

/* ============================================================================
   Painel da PLATAFORMA (Trabalho 8, F40; sidebar na F2 do Trabalho 9). O casco
   do DONO reusa a sidebar, os tokens e os componentes do operador; aqui so mora
   o que nao existia. A barra de topo horizontal saiu: com seis telas ela virava
   fila de abas, e a sidebar de 248px ja e a navegacao da casa.
   ============================================================================ */

/* Posicionamento, e so isso, e o que separa este casco do casco do operador. No
   layout.css a .sidebar e `position: fixed` em `top: 0`, e aqui existe a faixa de
   suporte ACIMA de tudo: fixed passaria por baixo dela e comeria a marca. Em grid,
   a faixa empurra as duas colunas de uma vez, e ela pode crescer de altura no
   celular (o texto quebra) sem descolar nada. */
.pf-shell { display: grid; grid-template-columns: var(--sidebar-width) 1fr; align-items: start; }
.pf-shell > .sidebar { position: sticky; top: 0; height: 100vh; height: 100dvh; }
.pf-shell > .conteudo { margin-left: 0; min-width: 0; }
/* [CABECALHO FIXO] no painel do dono. A faixa de suporte (.pf-suporte) fica ACIMA
   do shell, entao .conteudo com 100vh estouraria o body pela altura da faixa e o
   documento rolaria esse tanto. Aqui quem vira coluna de 100vh e o BODY: a faixa
   fica com a altura propria, o shell (grid) recebe o resto com a linha travada em
   minmax(0,1fr), e a sidebar deixa o height:100vh do sticky para esticar junto
   com a linha. Condicao identica a de layout.css. */
body:has(> .pf-shell > .conteudo > .pagina:not(.pagina-rola) > .tabela-wrap) {
  height: 100vh; height: 100dvh; display: flex; flex-direction: column;
}
body:has(> .pf-shell > .conteudo > .pagina:not(.pagina-rola) > .tabela-wrap) > .pf-shell {
  flex: 1 1 auto; min-height: 0; grid-template-rows: minmax(0, 1fr); align-items: stretch;
}
body:has(> .pf-shell > .conteudo > .pagina:not(.pagina-rola) > .tabela-wrap) > .pf-shell > .sidebar { height: auto; }
body:has(> .pf-shell > .conteudo > .pagina:not(.pagina-rola) > .tabela-wrap) > .pf-shell > .conteudo { height: auto; min-height: 0; }

/* Rodape de acoes de um formulario que vive dentro de card (nao de modal): a acao
   primaria encosta na DIREITA do bloco, como manda a Acao_Primaria_a_Direita. A ancora
   mora aqui, no container, e nunca num style= no botao - botao que se alinha sozinho
   funciona na tela de hoje e falha na proxima, porque a proxima esquece o atributo. */
.form-acoes { display: flex; justify-content: flex-end; gap: 10px; margin-top: 16px; }

/* Faixa de suporte: o dono esta DENTRO da sala de um cliente. Fica no topo,
   nao rola junto e diz de quem e a sala, com saida a um clique
   (Padrao_Impersonacao_Segura, cenario 4). Cor de AVISO, nunca a da marca:
   nao e estado normal do sistema, e confundir os dois e como o administrador
   esquece a aba aberta. */
.pf-suporte {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 20px; font-size: 13px;
  /* no portal de modulos o fundo e serifado (.po-tela): a faixa e do sistema */
  font-family: var(--fonte);
  background: var(--alerta-suave); color: var(--alerta);
  border-bottom: 1px solid var(--alerta);
  position: sticky; top: 0; z-index: var(--z-faixa-suporte);
}
.pf-suporte i { font-size: 18px; flex-shrink: 0; }
.pf-suporte span { flex: 1; min-width: 220px; }
.pf-suporte strong { color: var(--texto); }
.pf-suporte form { margin-left: auto; }

/* Acao de linha resolvida por <form> (POST com CSRF, sem JS): o form nao pode
   virar bloco, senao cada slot cai numa linha e a coluna desalinha. O alinhamento
   vertical dele e o mesmo dos outros slots, e mora no bloco .acoes-adiant. */
.acoes-adiant form { display: inline-flex; }

@media (max-width: 880px) {
  /* No celular a sidebar volta a ser gaveta e cobre a tela quando abre, que e o
     comportamento do layout.css e o certo aqui tambem: em tela estreita nao ha
     coluna de 248px pra reservar. */
  .pf-shell { grid-template-columns: 1fr; }
  .pf-shell > .sidebar { position: fixed; height: auto; }
  .pf-suporte { padding: 10px 14px; }
  /* Na tela do operador a faixa do link de acesso vem logo depois da barra do topo,
     que tambem e sticky: ela gruda embaixo da barra, e nao por baixo dela. */
  .topbar + .pf-suporte { top: var(--topbar-h); }
}

/* ============================================================================
   KPI de painel (Padrao_KPI_Dashboard). Estrutura LITERAL da nota: grid de 6 no
   desktop, 3 em <=1300px e 2 em <=720px; cada card e icone + corpo, com faixa de
   3px no topo. O `min-height` da label e da legenda nao e enfeite: e o que mantem
   os valores na MESMA linha-base quando um card tem label de duas linhas e o
   vizinho tem de uma, e o que iguala a altura de card com legenda e sem legenda.

   DUAS coisas divergem da nota, as duas declaradas:
   1. As variantes de cor da nota sao do dominio dela (faturamento, trafego pago,
      imposto, custo financeiro) e nao existem aqui. As deste painel saem dos
      tokens semanticos do projeto, nunca de hex copiado, como manda o
      Padrao_Box_Card ("nao use valores soltos, sempre token").
   2. O valor grande vai em Sora 700 28px, que e o que o Sistema_de_Estilos manda
      para valor de dashboard, e nao os 20px/800 do exemplo da nota. Decisao do
      plano da F3, e o CHECKLIST cobra assim.
   ============================================================================ */

.mg-kpis { display: grid; grid-template-columns: repeat(6, 1fr); gap: 10px; margin-bottom: 18px; align-items: stretch; }
.mg-kpi {
  background: var(--branco); border: 1px solid var(--borda); border-radius: var(--raio);
  padding: 14px; position: relative; overflow: hidden;
  display: flex; align-items: center; gap: 12px; height: 100%;
}
.mg-kpi::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--borda-forte); }
.mg-kpi.ac-cli::before  { background: var(--cor-primaria); }
.mg-kpi.ac-ok::before   { background: var(--ok); }
.mg-kpi.ac-sala::before { background: var(--info); }
.mg-kpi.ac-user::before { background: var(--alerta); }

.mg-kpi .ico { width: 44px; height: 44px; border-radius: var(--raio-sm); display: grid; place-items: center; font-size: 22px; flex-shrink: 0; align-self: center; }
.mg-kpi.ac-cli  .ico { background: var(--cor-primaria-suave); color: var(--cor-primaria-escura); }
.mg-kpi.ac-ok   .ico { background: var(--ok-suave); color: var(--ok); }
.mg-kpi.ac-sala .ico { background: var(--info-suave); color: var(--info); }
.mg-kpi.ac-user .ico { background: var(--alerta-suave); color: var(--alerta); }

.mg-kpi .corpo { min-width: 0; flex: 1; display: flex; flex-direction: column; }
.mg-kpi .lbl {
  font-size: 10.5px; color: var(--texto-secundario); text-transform: uppercase;
  letter-spacing: .03em; font-weight: 700; line-height: 1.2;
  min-height: 25px; display: flex; align-items: flex-end;
}
.mg-kpi .val {
  font-family: var(--fonte-titulo); font-size: 28px; font-weight: 700;
  letter-spacing: -.02em; line-height: 1; font-variant-numeric: tabular-nums; margin-top: 3px;
}
.mg-kpi .disc { font-size: 10.5px; color: var(--texto-fraco); margin-top: 4px; line-height: 1.2; font-style: italic; min-height: 14px; }

@media (max-width: 1300px) { .mg-kpis { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 720px) {
  .mg-kpis { grid-template-columns: repeat(2, 1fr); gap: 8px; }
  .mg-kpi { padding: 12px 11px; gap: 9px; }
  .mg-kpi .ico { width: 36px; height: 36px; font-size: 18px; }
  /* 12px e o piso de leitura no celular (auditoria 09/2026, RESP-01): eram 9,5 e
     10px, menores que os 10,5 do computador. O min-height guarda as duas linhas
     do rotulo e a uma da nota, para os valores ficarem na mesma altura. */
  .mg-kpi .lbl { font-size: 12px; min-height: 29px; }
  .mg-kpi .val { font-size: 22px; }
  .mg-kpi .disc { font-size: 12px; min-height: 15px; }
}

/* As duas listas curtas da visao geral, lado a lado. align-items: stretch para os
   dois cards terem a MESMA altura mesmo com numero diferente de linhas
   (Padrao_Box_Card, a regra critica da grid). A trilha e minmax(0, 1fr), e nao
   1fr: o 1fr nao encolhe abaixo do conteudo, e a tabela mais larga que o card
   (celula sem quebra de linha) alargava o card em vez de rolar dentro dele. No
   celular a PAGINA rolava de lado (medido no banco de desenvolvimento: 172px em
   320 e 132px em 360), e no computador um card tomava a largura do outro. */
.pf-resumo { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px; align-items: stretch; }
.pf-resumo > .card { display: flex; flex-direction: column; }
.pf-resumo .tabela-scroll { overflow-x: auto; }
@media (max-width: 1000px) { .pf-resumo { grid-template-columns: minmax(0, 1fr); } }

/* Vazio de uma SECAO de card: nao ha area sobrando para centrar na janela, entao
   aqui ele nao estica, so respira (Padrao_Estado_Vazio). */
.vz-inline { flex: none; min-height: 150px; padding: 22px 16px; }
.vz-inline .vz-icone { font-size: 30px; margin-bottom: 10px; }
.vz-inline .vz-titulo { font-size: 14.5px; }
.vz-inline .vz-sub { font-size: 12.5px; }

/* Formulario de conta: tres campos de senha esticados por 1100px de card ficam
   ilegiveis, e a linha de leitura confortavel nao passa muito disso. */
.pf-conta { max-width: 520px; }

/* Troca da PROPRIA senha (decisao 158, o desenho do anexo do Ricardo): um cartao so,
   o do macro _troca_de_senha.html, na troca exigida (base_publico, sem layout.css) e
   nas duas Minha conta. O cartao tem a largura da linha de leitura, o rotulo e o da
   tela nova (13px, 600, sem caixa alta, como o .au-form) e a lista de requisitos vem
   embaixo dos campos, em duas colunas que se leem linha a linha. O cartao da
   verificacao em duas etapas (.sf-conta, decisao 159), logo abaixo dele nas duas
   Minha conta, tem a mesma medida e o mesmo rotulo. */
.troca-senha, .sf-conta { max-width: 520px; }
.troca-senha > .card-corpo, .sf-conta > .card-corpo { padding: 26px 26px 24px; }
.ts-titulo { font-size: 16px; }
.ts-sub { margin: 8px 0 18px; font-size: 13px; line-height: 1.6; color: var(--texto-suave); }
.troca-senha .campo, .sf-conta .campo { gap: 7px; margin-bottom: 18px; }
.troca-senha .campo > label, .sf-conta .campo > label { font-size: 13px; font-weight: 600; text-transform: none; letter-spacing: 0; }
.troca-publica { width: 100%; max-width: 520px; }

/* A lista dos requisitos da senha nova, marcada pelo main.js ("Regras da senha")
   enquanto a pessoa digita. A marca e a bolinha vazada que se enche de --ok com o
   visto; o TEXTO fica na cor de sempre, porque o --ok sobre o branco nao chega ao
   contraste de texto pequeno, e quem diz o estado ao leitor de tela e o texto
   escondido da linha. O ::after nao herda o box-sizing do `*`: o visto e medido de
   fora da borda. */
.regras-senha {
  margin: 2px 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 14px;
  font-size: 13px; color: var(--texto-secundario);
}
.regras-senha li { display: flex; gap: 9px; line-height: 1.35; }
.rs-marca {
  flex: none; position: relative; width: 13px; height: 13px; margin-top: 2px;
  border: 1.5px solid var(--texto-fraco); border-radius: var(--raio-full);
}
.rs-ok .rs-marca { background: var(--ok); border-color: var(--ok); }
.rs-ok .rs-marca::after {
  content: ""; position: absolute; left: 3px; top: 0.5px; width: 3px; height: 6px;
  border: solid var(--branco); border-width: 0 1.5px 1.5px 0; transform: rotate(45deg);
}
@media (max-width: 560px) {
  .troca-senha > .card-corpo, .sf-conta > .card-corpo { padding: 22px 18px; }
  .regras-senha { grid-template-columns: minmax(0, 1fr); }
}

/* O cartao da verificacao em duas etapas (o macro _segundo_fator_da_conta.html): a
   contagem dos codigos de recuperacao e a explicacao das duas acoes, que fica junto
   dos botoes porque e ali que a pessoa decide. */
.sf-conta { margin-top: 16px; }
.sf-codigos { margin: 0 0 18px; font-size: 13px; line-height: 1.6; color: var(--texto-secundario); }
.sf-explica { margin: 0 0 16px; font-size: 12.5px; line-height: 1.6; color: var(--texto-suave); }

/* As telas da porta do segundo fator (o macro _segundo_fator_da_porta.html, decisao
   159), nas duas portas: na moldura da tela de login (.au-form) e no cartao escuro do
   dono (.pl-card, que acerta as cores no fim do bloco). O codigo do aplicativo se le
   em numeros de largura igual; a chave e os codigos de recuperacao, na letra de
   largura fixa (--fonte-mono). As cores do QR code moram no tokens.css. */
.df-conta { color: var(--texto); overflow-wrap: anywhere; }
.df-numero { font-variant-numeric: tabular-nums; letter-spacing: .12em; }
.df-recuperacao { font-family: var(--fonte-mono); text-transform: uppercase; letter-spacing: .04em; }
.campo.df-lembrar > label { display: flex; align-items: center; gap: 9px; cursor: pointer; font-weight: 500; }
.df-lembrar .dica-inline { padding-left: 26px; }
.df-perdi {
  margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--borda);
  text-align: left; font-size: 13px; color: var(--texto-suave);
}
.df-perdi > summary { cursor: pointer; font-weight: 600; color: var(--cor-primaria); }
.df-perdi[open] > summary { margin-bottom: 14px; }
.df-perdi .btn { width: 100%; }
.df-sem { margin: 12px 0 0; font-size: 12.5px; line-height: 1.5; }

/* Os tres passos da configuracao, numerados pelo CSS (o numero e desenho: o <ol> ja
   diz a ordem ao leitor de tela). O link otpauth:// so aparece no toque: e o caminho
   de quem configura no proprio celular, e no computador ele nao abre nada. O QR code
   e o link ficam no meio do cartao, e nao no da coluna do passo: a margem da
   esquerda devolve o recuo do numero (a coluna dele e o vao), e o centro passa a ser
   o da largura inteira do passo. A chave e o copiar dividem uma linha quando cabem. */
.df-passos {
  --df-bolinha: 26px; --df-vao: 12px;
  list-style: none; margin: 0; padding: 0; counter-reset: df-passo;
  display: flex; flex-direction: column; gap: 18px; text-align: left;
}
.df-passos > li { counter-increment: df-passo; display: grid; grid-template-columns: var(--df-bolinha) minmax(0, 1fr); gap: var(--df-vao); }
.df-passos > li::before {
  content: counter(df-passo); width: var(--df-bolinha); height: var(--df-bolinha); border-radius: var(--raio-full);
  display: grid; place-items: center; font-size: 13px; font-weight: 700;
  background: var(--cor-primaria-suave); color: var(--cor-primaria-escura);
}
.df-passo {
  display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
  font-size: 13px; line-height: 1.5; color: var(--texto-secundario);
}
.df-passo > strong { margin-top: 3px; font-weight: 600; color: var(--texto); }
.df-passo > form { align-self: stretch; }
.df-qr, .df-abrir { align-self: center; margin-left: calc(-1 * (var(--df-bolinha) + var(--df-vao))); }
.df-qr {
  display: block; width: 184px; height: 184px;
  background: var(--qr-fundo); border: 1px solid var(--borda); border-radius: var(--raio-sm);
}
.df-qr path { fill: var(--qr-tinta); }
.df-abrir { display: none; }
@media (pointer: coarse) {
  .df-abrir { display: inline-flex; }
}
.df-chave {
  padding: 6px 10px; font-family: var(--fonte-mono); font-size: 14px; letter-spacing: .04em;
  color: var(--texto); background: var(--fundo); border: 1px solid var(--borda);
  border-radius: var(--raio-sm);
}
.df-chave-linha { display: flex; flex-wrap: wrap; gap: 8px; }

/* Os codigos de recuperacao: duas colunas que se leem linha a linha (uma no celular),
   e o codigo nao quebra no hifen. */
.df-codigos {
  list-style: none; margin: 4px 0 16px; padding: 14px 12px;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 12px;
  font-family: var(--fonte-mono); font-size: 13px; text-align: center; white-space: nowrap;
  color: var(--texto); background: var(--fundo); border: 1px solid var(--borda);
  border-radius: var(--raio-sm);
}
.df-acoes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin-bottom: 12px; }
@media (max-width: 560px) {
  .df-codigos { grid-template-columns: minmax(0, 1fr); }
}

/* No cartao escuro do dono, as mesmas pecas com a paleta --pl-*. */
.pl-card .dica-inline, .pl-card .df-perdi, .pl-card .df-passo { color: var(--pl-muted); }
.pl-card .df-conta, .pl-card .df-passo > strong { color: var(--pl-texto); }
.pl-card .df-perdi { border-top-color: var(--pl-borda); }
.pl-card .df-perdi > summary { color: var(--pl-destaque); }
.pl-card .df-passos > li::before {
  background: color-mix(in srgb, var(--cor-primaria) 22%, transparent); color: var(--pl-destaque);
}
.pl-card .df-chave, .pl-card .df-codigos { color: var(--pl-texto); background: var(--pl-input); border-color: var(--pl-borda); }
.pl-card .btn:not(.btn-primario) { color: var(--pl-texto); background: transparent; border-color: var(--pl-borda); }
.pl-card .btn:not(.btn-primario):hover { background: var(--pl-input); }

/* O cartao largo da configuracao do aplicativo e da tela seguinte, a dos codigos de
   recuperacao (nas duas portas; pedido do Ricardo, 2026-10-04): com o QR code no
   meio e a chave na linha do copiar, a tela fica mais baixa, e o cartao nao muda de
   largura de uma tela para a outra. No dono, o cartao inteiro; no operador, a coluna
   do formulario, e a da marca cede. Ate 820px a moldura do operador e uma coluna so,
   como no login: a regra de la (.au-cartao) perde para esta, mais especifica, e por
   isso a coluna unica se repete aqui. */
.pl-card.df-largo { max-width: 600px; }
.au-cartao.df-largo { max-width: 1000px; grid-template-columns: minmax(0, 3fr) minmax(0, 5fr); }
@media (max-width: 820px) {
  .au-cartao.df-largo { grid-template-columns: minmax(0, 1fr); max-width: 600px; }
}

/* O segundo fator na janela que edita usuario (decisao 159; o macro
   _segundo_fator_do_usuario.html, na Administracao > Usuarios e nos Usuarios da empresa
   do painel do dono): um bloco abaixo da senha, separado por um fio, com o titulo no
   desenho do rotulo de campo (.campo > label, la em cima) e o Zerar na linha do
   estado, que quebra quando a janela e estreita. */
.sf-usuario { display: flex; flex-direction: column; gap: 6px; padding-top: 14px; border-top: 1px solid var(--borda); }
.sf-usuario-estado { display: flex; flex-direction: column; gap: 6px; }
.sf-usuario p { margin: 0; }
.sf-usuario-linha { display: flex; align-items: center; justify-content: space-between; gap: 8px 12px; flex-wrap: wrap; }
.sf-usuario-texto { font-size: 13px; color: var(--texto-secundario); }
.sf-usuario-texto strong { color: var(--texto); }

/* Faixa de CONTEXTO do painel do dono: ele esta mexendo em dado de UMA empresa.
   NAO e a faixa de suporte (aquela e de AVISO, amarela, e diz que a SESSAO atravessou
   a fronteira). Esta e informativa, e existe porque esquecer em qual empresa se esta e
   o acidente mais comum deste tipo de tela (Padrao_Impersonacao_Segura, cenario 4). */
.pf-contexto {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 14px; margin-bottom: 16px;
  background: var(--info-suave); color: var(--info);
  border: 1px solid var(--info); border-radius: var(--raio-sm); font-size: 13px;
}
.pf-contexto i { font-size: 18px; flex-shrink: 0; }
.pf-contexto strong { color: var(--texto); }

/* ============================================================================
   O toggle de tres opcoes do painel do dono: o modo da protecao por IP (Seguranca) e
   o acesso por IP de cada empresa (Livre, So observar, Restrito). `.sg-presets` e o
   TIPO 1 da `Padrao_Toggle_Tipos`: o escolhido fica em SUAVE com borda, porque solido
   no tipo 1 pesaria a barra.

   Havia um TIPO 2 aqui (`.sg-tipo`, bloquear ou liberar a regra, o solido da decisao
   96). Saiu na auditoria de 09/2026 junto com o Liberar da lista geral, que gravava a
   regra e nenhuma porta lia (decisao 128); a lista geral agora so bloqueia.

   Cor sempre por token. Hex chumbado na tela e o que a nota proibe com todas as
   letras, e a prova e `grep -rniE "#[0-9a-fA-F]{3,8}" templates/plataforma/`.
   ============================================================================ */

.sg-presets {
  display: inline-flex; align-items: center; gap: 4px; flex-wrap: wrap;
  padding: 3px; border: 1px solid var(--borda); border-radius: 7px;
  background: var(--branco);
}
.sg-presets button {
  height: 32px; border: 1px solid transparent; background: var(--branco);
  border-radius: 5px; padding: 0 12px; font-size: 12px; font-weight: 600;
  color: var(--texto-secundario); cursor: pointer; white-space: nowrap;
}
.sg-presets button:hover { color: var(--cor-primaria); }
.sg-presets button.on {
  border-color: var(--cor-primaria);
  background: var(--cor-primaria-suave);
  color: var(--cor-primaria-escura);
}
/* Opcao que ainda nao vale (o Restrito de uma empresa sem endereco liberado): o
   `disabled` sozinho nao muda nada na tela, porque a cor vem da classe, e o botao
   pareceria clicavel sem fazer nada. O title diz o que falta. */
.sg-presets button:disabled,
.sg-presets button:disabled:hover { color: var(--texto-fraco); cursor: not-allowed; }

/* O aviso de acessos barrados da visao geral fica entre os numeros e as duas listas. */
.pf-barrados { margin-bottom: 16px; }

/* ---- Portal de modulos (/modulos, Trabalho 10 F1). Prefixo .po- ----
   Tela sem sidebar (base_publico), na composicao do modelo do Ricardo (2026-09-08):
   barra fina no topo (marca a esquerda, "nome · perfil" e Sair a direita) e o resto da
   janela com UM bloco centrado nos dois eixos - a data por extenso, a saudacao com o
   primeiro nome em destaque, o subtitulo e, embaixo, os cards. As CORES seguem os
   tokens do sistema; a FONTE e a serifa do modelo do Ricardo (pedido 2026-09-09), a
   mesma Georgia da marca de informacao (quirk 13), definida UMA vez no .po-tela e
   herdada por todo o portal - nunca em token. O .po-centro e dono do espaco (gap,
   Padrao_Espacamento_e_Respiro); os cards nascem com a mesma altura pelo
   align-items: stretch da linha (Padrao_Box_Card). Raio, sombra, cor e transicao so
   por token; o hover mexe em borda, sombra e translate, nunca no fundo.
   O centro vertical e por margin:auto no .po-centro, e NAO por justify-content:center
   no .po-wrap: com o conteudo mais alto que a janela (celular deitado) o justify-content
   empurra o topo do bloco para fora da vista e ele nao volta nem rolando; a margem
   automatica cai a zero e o bloco flui do topo. */
.po-tela { min-height: 100vh; min-height: 100dvh; background: var(--fundo); display: flex; flex-direction: column; font-family: Georgia, "Times New Roman", serif; }
.po-topo {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 10px 24px; background: var(--branco); border-bottom: 1px solid var(--borda);
  flex-wrap: wrap;
}
.po-marca { display: flex; align-items: center; gap: 10px; min-width: 0; }
.po-usuario { display: flex; align-items: center; gap: 14px; min-width: 0; }
.po-quem { font-size: 13px; color: var(--texto-suave); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.po-quem .nome { font-weight: 600; color: var(--texto); }
.po-wrap {
  flex: 1; width: 100%; max-width: 1080px; margin: 0 auto; padding: var(--sp-6) var(--sp-5);
  display: flex; flex-direction: column;
}
.po-centro { margin: auto 0; width: 100%; display: flex; flex-direction: column; align-items: center; gap: var(--sp-6); text-align: center; }
.po-saudacao { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); }
.po-data { font-size: 11px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--texto-fraco); }
.po-ola { font-family: inherit; font-weight: 600; font-size: 36px; letter-spacing: -.02em; line-height: 1.15; margin: 0; }
.po-ola em { font-style: italic; color: var(--cor-primaria); }
/* marca-nome e vz-titulo fixam --fonte-titulo (uso global); dentro do portal
   herdam a serifa do .po-tela, sem tocar a sidebar, que segue Sora. */
.po-marca .marca-nome, .po-centro .vz-titulo { font-family: inherit; }
.po-sub { font-size: 13.5px; color: var(--texto-suave); margin: 0; }
/* Card de largura FIXA, centrado com os irmaos (bug do Ricardo 2026-09-08, cliente
   Brasil Madeiras): a grade de auto-fit colapsava a coluna vazia e um card sozinho
   (empresa com um modulo so no contrato) esticava a largura toda do .po-wrap - 1032px
   em 1280 de janela, contra os 508px de cada card do Delluane, que tem dois. Com a
   largura declarada no card e a linha so centrando, o card mede o mesmo tenha a empresa
   um, dois ou tres modulos, contratado ou em breve; ate 720px ele ocupa a coluna
   inteira. Prova em tests/test_card_do_portal.py, com o CSS real no navegador. */
.po-cards { display: flex; flex-wrap: wrap; justify-content: center; align-items: stretch; gap: var(--sp-4); width: 100%; }
.po-card {
  width: 280px; max-width: 100%; display: flex; flex-direction: column; align-items: center;
  gap: var(--sp-2); padding: var(--sp-5) var(--sp-4);
  background: var(--branco); border: 1px solid var(--borda); border-radius: var(--raio);
  box-shadow: var(--sombra); color: var(--texto);
  transition: border-color var(--transicao), box-shadow var(--transicao), transform var(--transicao);
}
a.po-card:hover { border-color: var(--cor-primaria); box-shadow: var(--sombra-md); transform: translateY(-2px); color: var(--texto); text-decoration: none; }
/* O icone e um bloco cheio da cor da marca com o glifo branco, como no modelo; o card
   parado (em breve / sem acesso) apaga o bloco e vira borda tracejada sem fundo. */
.po-medal {
  width: 56px; height: 56px; border-radius: var(--raio); display: grid; place-items: center;
  background: var(--cor-primaria); color: var(--branco); margin-bottom: var(--sp-1);
}
.po-medal i { font-size: 26px; }
.po-titulo { font-family: inherit; font-weight: 700; font-size: 15px; letter-spacing: -.01em; display: inline-flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 6px; }
.po-desc { font-size: 13px; line-height: 1.5; color: var(--texto-suave); }
.po-selo {
  font-family: inherit; font-size: 9.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--texto-fraco); border: 1px solid var(--borda); border-radius: var(--raio-full); padding: 2px 7px;
}
.po-card.esmaecido, .po-card.em-breve { opacity: .65; cursor: not-allowed; box-shadow: none; border-style: dashed; background: transparent; }
.po-card.esmaecido .po-medal, .po-card.em-breve .po-medal { background: var(--fundo-2); color: var(--texto-fraco); }
@media (max-width: 720px) {
  .po-topo { padding: 10px 16px; }
  .po-topo .btn { min-height: 44px; }
  .po-quem { display: none; }
  .po-wrap { padding: var(--sp-5) var(--sp-4); }
  .po-centro { gap: var(--sp-5); }
  .po-ola { font-size: 28px; }
  .po-card { width: 100%; padding: var(--sp-4); }
}

/* Editor de menu: modulo de cada grupo, so rotulo (mover grupo entre modulos fica
   fora da v1; o modulo e do seed, decisao 102 do T10). */
.me-grupo-modulo {
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  color: var(--texto-fraco); background: var(--fundo-2); padding: 2px 8px;
  border-radius: var(--raio-full);
}
/* Painel SaaS > Tela de Login: linhas da lista dinamica de itens (input + remover). */
.tl-item { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.tl-item .input { flex: 1; }
.tl-itens [data-tl-adicionar] { margin-top: 4px; }

/* Grupo transversal (Admin): aparece em todo modulo, sempre no pe da sidebar. */
.me-grupo-fixo { margin-top: 12px; border-color: var(--cor-primaria); }
.me-grupo-fixo .me-grupo-cab { background: var(--cor-primaria-suave); }
.me-grupo-fixo .me-grupo-modulo { color: var(--cor-primaria-escura); background: var(--fundo); }

/* ---- CRM: Configuracoes do Catalogo e Parametros (Trabalho 10 F2). Prefixo .cr- ----
   Grid de cards com a mesma altura (align-items: stretch); o card-corpo e uma coluna
   com gap, entao nenhum bloco carrega margin-bottom para se afastar do vizinho. A barra
   de adicionar segue Padrao_Formulario: controles de 40px, label 13px/600, alinhamento
   pela base e <label>&nbsp;</label> no botao. */
.cr-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(380px, 1fr)); gap: var(--sp-4); align-items: stretch; }
/* Catalogo (F2): cada linha carrega nome + meta + tres acoes, e com o minimo de
   380px do .cr-grid a tela larga abria TRES colunas de ~400px, apertadas demais
   (pedido do Ricardo, 2026-09-05). Com 460px sao sempre DUAS colunas no desktop:
   medido no navegador, card de 400 -> 608 em 1536 e de 444 -> 674 em 1920.
   O 460 e escolhido pelo INTERVALO, nao no olho: abaixo de 406 a terceira coluna
   volta em 1536, e acima de 480 a segunda coluna some em 1280 (medido: caia para
   uma coluna de 976px, pior que o problema original).
   O minimo do .cr-grid fica como esta de proposito: o cr-detalhe tem dois cards so,
   e subir o minimo la os derrubaria para uma coluna cedo demais no tablet.
   O min() evita o transbordo classico do minmax fixo com container menor que ele. */
.cr-grid.cr-catalogo { grid-template-columns: repeat(auto-fit, minmax(min(460px, 100%), 1fr)); }
.cr-grid > .card { display: flex; flex-direction: column; height: 100%; }
.cr-grid .card-corpo { display: flex; flex-direction: column; gap: var(--sp-4); flex: 1; }
.cr-contagem { font-size: 12px; color: var(--texto-suave); font-weight: 500; white-space: nowrap; }
.cr-bar { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: flex-end; }
.cr-bar .campo { margin-bottom: 0; flex: 1 1 150px; }
.cr-bar .campo.cr-campo-cor { flex: 0 0 auto; }
.cr-bar .campo.cr-acao { flex: 0 0 auto; }
.cr-bar .input, .cr-bar .btn { height: 40px; box-sizing: border-box; }
.cr-bar .cr-aviso { flex: 1 1 100%; }
.cr-cor-input { width: 56px; padding: 3px 4px; cursor: pointer; }
.cr-aviso {
  display: flex; gap: 8px; align-items: flex-start; padding: 10px 12px;
  border-radius: var(--raio-sm); background: var(--erro-suave); color: var(--erro);
  font-size: 13px; line-height: 1.4;
}
.cr-lista { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.cr-item {
  display: flex; align-items: center; gap: var(--sp-3); padding: 8px 10px;
  border: 1px solid var(--borda); border-radius: var(--raio-sm); background: var(--branco);
}
.cr-item.inativo .cr-item-nome, .cr-item.inativo .cr-item-meta,
.cr-sub.inativo > .cr-sub-cab .cr-item-nome { color: var(--texto-fraco); }
.cr-sw { width: 18px; height: 18px; border-radius: var(--raio-full); border: 1px solid var(--borda-forte); flex: 0 0 auto; background: var(--fundo-2); }
.cr-item-nome { font-weight: 600; font-size: 13.5px; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cr-item-meta { font-size: 12px; color: var(--texto-suave); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 45%; }
.cr-acoes { display: flex; align-items: center; gap: 6px; margin-left: auto; flex: 0 0 auto; }
.cr-sub { border: 1px solid var(--borda); border-radius: var(--raio-sm); padding: var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-3); }
.cr-sub-cab { display: flex; align-items: center; gap: var(--sp-3); }
.cr-sub-cab .cr-item-nome { font-size: 14px; }
.cr-sub .cr-item { padding: 6px 10px; }
.cr-param { max-width: 860px; }
/* Dois cards da mesma aba em sequencia (a aba WhatsApp tem quatro); o card de outra aba, escondido, nao conta. */
.cr-param:not([hidden]) ~ .cr-param:not([hidden]) { margin-top: 16px; }
.cr-rodape-form { display: flex; justify-content: flex-end; }
/* Aba WhatsApp dos Parametros (Trabalho 11, F6). */
.wa-ficha { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--sp-3); margin: var(--sp-4) 0; }
.wa-ficha dt { font-size: 12px; color: var(--texto-fraco); }
.wa-ficha dd { margin: 2px 0 0; font-size: 14px; color: var(--texto); }
.wa-auto-liga { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-3); }
.wa-auto-rotulo { margin: 0; font-size: 13px; color: var(--texto); cursor: pointer; }
.wa-vazio { margin: var(--sp-4) 0; color: var(--texto-secundario); font-size: 13px; }
.wa-qr { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); margin: var(--sp-4) 0; text-align: center; font-size: 13px; color: var(--texto-secundario); }
.wa-qr-img { width: 240px; max-width: 100%; height: auto; background: var(--qr-fundo); border: 1px solid var(--borda); border-radius: var(--raio-sm); }
.wa-acoes { gap: var(--sp-2); flex-wrap: wrap; }
.wa-texto { margin: 0 0 var(--sp-3); font-size: 13px; color: var(--texto-secundario); }
.wa-dono { margin-top: var(--sp-4); padding-top: var(--sp-4); border-top: 1px solid var(--borda); }
.wa-etq-nome { display: inline-flex; align-items: center; gap: var(--sp-2); }
.wa-resposta-texto { white-space: pre-wrap; max-width: 420px; font-size: 13px; color: var(--texto-secundario); }
/* Caixa de entrada do WhatsApp (Trabalho 11, F7; o desenho do prototipo aprovado):
   tres colunas (lista, conversa, contato) da altura da janela. Ate 1300px o contato
   troca de lugar com a conversa pelo botao; ate 880px e uma coluna por vez. */
.pagina.wa-pagina { max-width: none; padding-bottom: 20px; }
.wa-aviso-conta { max-width: 860px; }
.wa-tabs { display: flex; gap: 6px; border-bottom: 1px solid var(--borda); margin-bottom: 16px; overflow-x: auto; scrollbar-width: thin; }
.wa-tab { padding: 10px 14px; font-size: 13px; font-weight: 600; color: var(--texto-secundario); cursor: pointer; border: none; background: transparent; border-bottom: 2px solid transparent; display: inline-flex; align-items: center; gap: 6px; font-family: inherit; white-space: nowrap; }
.wa-tab:hover { color: var(--texto); }
.wa-tab.ativo { color: var(--cor-primaria); border-bottom-color: var(--cor-primaria); }
.wa-conta { font-size: 11px; font-weight: 700; background: var(--fundo-2); color: var(--texto-secundario); border-radius: var(--raio-full); padding: 1px 7px; }
.wa-tab.ativo .wa-conta { background: var(--cor-primaria-suave); color: var(--cor-primaria-escura); }
.wa-conta.forte { background: var(--cor-primaria); color: var(--texto-sobre-primaria); }
.wa-central {
  display: grid; grid-template-columns: 330px minmax(0, 1fr) 300px;
  background: var(--branco); border: 1px solid var(--borda); border-radius: var(--raio); box-shadow: var(--sombra);
  height: calc(100vh - 210px); height: calc(100dvh - 210px); min-height: 480px; overflow: hidden;
}
.wa-col { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
.wa-col + .wa-col { border-left: 1px solid var(--borda); }
.wa-lista-topo { padding: 12px; border-bottom: 1px solid var(--borda); display: flex; }
.wa-lista-topo .input { flex: 1; min-width: 0; }
.wa-lista { overflow-y: auto; flex: 1; }
.wa-lista-vazia { padding: 16px; font-size: 13px; color: var(--texto-suave); }
.wa-lista-pe { padding: 10px; border-top: 1px solid var(--borda); display: flex; justify-content: center; }
.wa-item {
  display: grid; grid-template-columns: 40px minmax(0, 1fr) auto; gap: 10px; align-items: start;
  padding: 12px; width: 100%; cursor: pointer; text-align: left; font: inherit; color: inherit; background: transparent;
  border: 0; border-bottom: 1px solid var(--borda); border-left: 3px solid transparent;
}
.wa-item:hover { background: var(--fundo); }
.wa-item:focus-visible { outline: 2px solid var(--cor-primaria); outline-offset: -2px; }
.wa-item.ativo { background: var(--cor-primaria-suave); border-left-color: var(--cor-primaria); }
.wa-av { position: relative; overflow: hidden; width: 40px; height: 40px; flex: 0 0 auto; border-radius: var(--raio-full); display: grid; place-items: center; font-family: var(--fonte-titulo); font-weight: 700; font-size: 14px; background: var(--fundo-2); color: var(--texto-secundario); }
/* A foto de perfil (decisao 175) cobre as iniciais, que ficam por baixo enquanto ela
   carrega e voltam quando ela falha (o JS a tira). */
.wa-av > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
.wa-item-nome { font-weight: 600; font-size: 13.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wa-item.nao-lida .wa-item-nome { font-weight: 700; }
.wa-item-prev { font-size: 12.5px; color: var(--texto-suave); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 2px; }
.wa-item.nao-lida .wa-item-prev { color: var(--texto); font-weight: 500; }
.wa-item-meta { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 6px; align-items: center; }
.wa-item-dir { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
.wa-hora { font-size: 11px; color: var(--texto-fraco); white-space: nowrap; }
.wa-item.nao-lida .wa-hora { color: var(--cor-primaria); font-weight: 700; }
.wa-nl { min-width: 20px; height: 20px; border-radius: var(--raio-full); background: var(--cor-primaria); color: var(--texto-sobre-primaria); font-size: 11px; font-weight: 700; display: grid; place-items: center; padding: 0 6px; }
/* A cor da etiqueta vem do cadastro, conferida pelo JS (so #RRGGBB) e posta em --etq. */
.wa-etq { display: inline-flex; align-items: center; gap: 5px; font: inherit; font-size: 10.5px; font-weight: 600; padding: 1px 7px; border-radius: var(--raio-full); background: var(--fundo-2); color: var(--texto-secundario); white-space: nowrap; border: 1px solid transparent; }
.wa-etq::before { content: ""; width: 7px; height: 7px; border-radius: var(--raio-full); background: var(--etq, var(--texto-fraco)); }
.wa-resp { font-size: 11px; color: var(--texto-fraco); }
.wa-conv { position: relative; }
.wa-conv-vazia { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; color: var(--texto-suave); font-size: 13px; background: var(--fundo); }
.wa-conv-vazia i { font-size: 40px; color: var(--texto-fraco); }
.wa-conv-cab { display: flex; align-items: center; gap: 10px; padding: 10px 14px; border-bottom: 1px solid var(--borda); flex-wrap: wrap; }
.wa-conv-quem { flex: 1; min-width: 160px; }
.wa-conv-quem .nome { font-weight: 700; font-size: 14.5px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.wa-conv-quem .fone { font-size: 12px; color: var(--texto-suave); }
.wa-conv-acoes { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.wa-voltar { display: none; }
.wa-msgs { flex: 1; overflow-y: auto; padding: 16px 18px; background: var(--fundo); display: flex; flex-direction: column; }
.wa-anteriores { align-self: center; margin-bottom: 8px; }
.wa-msgs-lista { display: flex; flex-direction: column; gap: 6px; }
.wa-dia { align-self: center; font-size: 11px; font-weight: 600; color: var(--texto-suave); background: var(--branco); border: 1px solid var(--borda); border-radius: var(--raio-full); padding: 2px 10px; margin: 8px 0; }
.wa-bolha { max-width: min(72%, 520px); padding: 8px 11px 6px; border-radius: var(--raio); font-size: 13.5px; line-height: 1.45; background: var(--branco); border: 1px solid var(--borda); align-self: flex-start; box-shadow: var(--sombra); overflow-wrap: anywhere; }
.wa-bolha.sai { align-self: flex-end; background: var(--cor-primaria-suave); border-color: var(--cor-primaria-suave); }
.wa-bolha .autor { font-size: 11px; font-weight: 700; color: var(--cor-primaria-escura); margin-bottom: 2px; }
.wa-bolha .rodape { font-size: 10.5px; color: var(--texto-fraco); display: flex; justify-content: flex-end; gap: 6px; align-items: center; margin-top: 3px; }
.wa-msg-texto { white-space: pre-wrap; }
.wa-msg-tipo { color: var(--texto-suave); font-style: italic; }
.wa-situacao.falhou { color: var(--erro); font-weight: 700; }
/* Editar e apagar a mensagem da empresa (decisao 176). */
.wa-msg-apagada { display: flex; align-items: center; gap: 5px; color: var(--texto-suave); font-style: italic; }
.wa-editada { font-style: italic; }
.wa-apagar-conversa:hover { border-color: var(--erro); color: var(--erro); }
/* O menu da bolha (decisao 177): a setinha no canto da bolha abre o menu, com a barra
   de reacoes em cima e as acoes embaixo, como no WhatsApp. A setinha aparece no hover e
   no foco; no toque, sempre. */
.wa-linha { display: flex; flex-direction: column; position: relative; border-radius: var(--raio); }
.wa-linha.destaque { animation: waDestaque 1.6s ease; }
@keyframes waDestaque { from { background: color-mix(in srgb, var(--cor-primaria) 18%, transparent); } to { background: transparent; } }
.wa-linha .wa-bolha { position: relative; }
.wa-seta { position: absolute; top: 3px; right: 3px; width: 26px; height: 22px; display: grid; place-items: center; border: 0; border-radius: var(--raio-sm); background: inherit; color: var(--texto-suave); font-size: 15px; cursor: pointer; opacity: 0; transition: opacity .12s; }
.wa-linha:hover .wa-seta, .wa-linha.com-menu .wa-seta, .wa-seta:focus-visible { opacity: 1; }
.wa-seta:hover { color: var(--texto); }
.wa-seta:focus-visible { outline: 2px solid var(--cor-primaria); outline-offset: -2px; }
@media (hover: none) { .wa-seta { opacity: 1; } }
.wa-encaminhada { display: flex; align-items: center; gap: 4px; font-size: 11.5px; font-style: italic; color: var(--texto-suave); margin-bottom: 2px; padding-right: 22px; }
.wa-citada { display: flex; flex-direction: column; gap: 1px; width: 100%; margin: 0 0 5px; padding: 5px 8px; border: 0; border-left: 3px solid var(--texto-suave); border-radius: var(--raio-sm); background: color-mix(in srgb, var(--texto) 6%, transparent); text-align: left; font: inherit; color: inherit; cursor: default; }
button.wa-citada { cursor: pointer; }
.wa-citada.da-empresa { border-left-color: var(--cor-primaria); }
.wa-citada .quem { font-size: 11px; font-weight: 700; color: var(--cor-primaria-escura); }
.wa-citada .texto { font-size: 12.5px; color: var(--texto-secundario); overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; white-space: pre-wrap; }
.wa-marca { font-size: 11px; }
.wa-reacoes { display: flex; flex-wrap: wrap; gap: 4px; margin: -6px 0 0 10px; align-self: flex-start; position: relative; }
.wa-linha.sai .wa-reacoes { align-self: flex-end; margin: -6px 10px 0 0; }
.wa-reacao { display: inline-flex; align-items: center; gap: 3px; min-height: 22px; padding: 1px 7px; border: 1px solid var(--borda); border-radius: var(--raio-full); background: var(--branco); box-shadow: var(--sombra); font: inherit; font-size: 13px; line-height: 1.3; color: var(--texto); }
button.wa-reacao { cursor: pointer; }
.wa-reacao.minha { border-color: var(--cor-primaria); background: var(--cor-primaria-suave); }
.wa-reacao .conta { font-size: 11px; font-weight: 600; color: var(--texto-secundario); }
.wa-selecionar { position: absolute; left: 0; top: 4px; width: 28px; height: 28px; display: grid; place-items: center; border: 0; border-radius: var(--raio-sm); background: transparent; color: var(--texto-suave); font-size: 20px; cursor: pointer; }
.wa-selecionar[aria-pressed="true"] { color: var(--cor-primaria); }
.wa-linha:has(> .wa-selecionar) { padding-left: 36px; }
.wa-linha.marcada { background: color-mix(in srgb, var(--cor-primaria) 8%, transparent); }
.wa-menu { position: fixed; z-index: var(--z-menu-tabela); width: 248px; max-height: calc(100vh - 16px); max-height: calc(100dvh - 16px); overflow-y: auto; background: var(--branco); border: 1px solid var(--borda); border-radius: var(--raio); box-shadow: var(--sombra-md); padding: 6px 0; }
.wa-menu-reacoes { display: flex; align-items: center; justify-content: space-between; gap: 2px; padding: 2px 8px 6px; border-bottom: 1px solid var(--borda); margin-bottom: 4px; }
.wa-emoji { width: 32px; height: 32px; display: grid; place-items: center; border: 0; border-radius: var(--raio-full); background: transparent; font-family: "Segoe UI Emoji", "Apple Color Emoji", "Noto Color Emoji", sans-serif; font-size: 20px; line-height: 1; cursor: pointer; transition: transform .1s; }
.wa-emoji:hover, .wa-emoji:focus-visible { background: var(--fundo); transform: scale(1.15); outline: none; }
.wa-emoji.minha { background: var(--cor-primaria-suave); }
.wa-emoji-mais { font-size: 16px; color: var(--texto-secundario); border: 1px solid var(--borda); }
.wa-menu-lista, .wa-menu-topo { display: flex; flex-direction: column; }
.wa-menu-topo { border-bottom: 1px solid var(--borda); margin-bottom: 4px; padding-bottom: 4px; }
.wa-menu-item { display: flex; align-items: center; gap: 12px; width: 100%; padding: 8px 16px; border: 0; background: transparent; font: inherit; font-size: 13.5px; color: var(--texto); text-align: left; cursor: pointer; }
.wa-menu-item i { font-size: 17px; color: var(--texto-secundario); }
.wa-menu-item:hover, .wa-menu-item:focus-visible { background: var(--fundo); outline: none; }
.wa-menu-item.perigo, .wa-menu-item.perigo i { color: var(--erro); }
.wa-menu-grade { display: grid; grid-template-columns: repeat(6, 1fr); gap: 2px; padding: 4px 8px; }
.wa-fixadas { display: flex; align-items: center; gap: 8px; width: 100%; padding: 7px 16px; border: 0; border-bottom: 1px solid var(--borda); background: var(--branco); font: inherit; font-size: 12.5px; color: var(--texto-secundario); text-align: left; cursor: pointer; }
.wa-fixadas:hover { background: var(--fundo); }
.wa-fixada-texto { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wa-fixada-conta { font-size: 11px; color: var(--texto-suave); white-space: nowrap; }
.wa-respondendo { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; padding: 6px 8px 6px 10px; border-left: 3px solid var(--cor-primaria); border-radius: var(--raio-sm); background: var(--fundo); }
.wa-respondendo > i { color: var(--cor-primaria); font-size: 16px; }
.wa-respondendo-corpo { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.wa-respondendo-corpo .quem { font-size: 11.5px; font-weight: 700; color: var(--cor-primaria-escura); }
.wa-respondendo-corpo .texto { font-size: 12.5px; color: var(--texto-secundario); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wa-selecao { display: flex; align-items: center; gap: 10px; border-top: 1px solid var(--borda); padding: 10px 12px; background: var(--branco); }
.wa-selecao-conta { flex: 1; font-size: 13px; font-weight: 600; color: var(--texto-secundario); }
.wa-enc-resumo { font-size: 13px; font-weight: 500; color: var(--texto-suave); }
.wa-enc-lista { display: flex; flex-direction: column; max-height: 300px; overflow-y: auto; border: 1px solid var(--borda); border-radius: var(--raio-sm); margin-top: 8px; }
.wa-enc-item { display: flex; align-items: center; gap: 10px; padding: 9px 12px; font-size: 13.5px; cursor: pointer; }
.wa-enc-item + .wa-enc-item { border-top: 1px solid var(--borda); }
.wa-enc-item:hover { background: var(--fundo); }
.wa-enc-item .nome { flex: 1; min-width: 0; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wa-enc-item .fone { font-size: 12px; color: var(--texto-suave); }
.wa-dados { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 6px 16px; margin: 0; font-size: 13.5px; }
.wa-dados dt { color: var(--texto-suave); }
.wa-dados dd { margin: 0; }
.wa-dados-tit { margin: 16px 0 6px; font-size: 13px; }
.wa-dados-reacoes { margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; font-size: 13.5px; }
.wa-dados-reacoes li { display: flex; align-items: center; gap: 10px; }
.wa-dados-reacoes .emoji { font-size: 18px; }
.wa-dados-reacoes .wa-hora { margin-left: auto; }
.wa-erro { margin-top: 4px; font-size: 12px; color: var(--erro); }
.wa-midia { display: block; max-width: 100%; margin-bottom: 4px; border-radius: var(--raio-sm); }
.wa-midia img { display: block; max-width: 100%; max-height: 260px; border-radius: var(--raio-sm); }
.wa-arq { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-radius: var(--raio-sm); background: var(--fundo); border: 1px solid var(--borda); margin-bottom: 4px; font-size: 12.5px; font-weight: 600; color: var(--texto); }
.wa-arq i { font-size: 22px; color: var(--texto-suave); }
.wa-arq-espera { font-weight: 400; color: var(--texto-suave); }
.wa-compor { position: relative; border-top: 1px solid var(--borda); padding: 10px 12px; background: var(--branco); }
.wa-compor-linha { display: flex; gap: 8px; align-items: flex-end; }
.wa-compor .textarea { min-height: 42px; height: 42px; max-height: 160px; resize: none; flex: 1; }
.wa-clipe { position: relative; flex: 0 0 auto; }
.wa-clipe:focus-within { border-color: var(--cor-primaria); color: var(--cor-primaria); }
.wa-arquivo { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.wa-anexo { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-size: 12.5px; color: var(--texto-secundario); }
.wa-anexo-nome { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wa-compor .cr-aviso { margin-top: 8px; }
.wa-rapidas { position: absolute; left: 12px; right: 12px; bottom: 100%; margin-bottom: 4px; border: 1px solid var(--borda); border-radius: var(--raio-sm); box-shadow: var(--sombra-md); background: var(--branco); max-height: 200px; overflow-y: auto; z-index: var(--z-lista); }
.wa-rapida { display: flex; gap: 8px; padding: 8px 12px; font-size: 12.5px; cursor: pointer; color: var(--texto); }
.wa-rapida b { font-family: var(--fonte-mono); font-weight: 600; color: var(--cor-primaria-escura); }
.wa-rapida span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--texto-secundario); }
.wa-rapida:hover, .wa-rapida.destacado { background: var(--cor-primaria-suave); }
.wa-painel { overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 18px; }
.wa-painel h3 { font-size: 11px; text-transform: uppercase; letter-spacing: .08em; color: var(--texto-fraco); font-weight: 700; margin: 0 0 8px; }
.wa-painel-topo { display: none; }
.wa-contato-topo { text-align: center; }
.wa-contato-topo .wa-av { width: 56px; height: 56px; font-size: 19px; margin: 0 auto 8px; }
.wa-contato-topo .nome { font-weight: 700; font-size: 15px; overflow-wrap: anywhere; }
.wa-contato-topo .fone { font-size: 12.5px; color: var(--texto-suave); }
.wa-p-texto { margin: 0 0 4px; font-size: 12.5px; color: var(--texto-secundario); overflow-wrap: anywhere; }
.wa-p-texto.forte { font-weight: 600; color: var(--texto); }
.wa-p-botoes { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
.wa-desconhecido { margin: 0; background: var(--alerta-suave); border-radius: var(--raio-sm); padding: 10px 12px; font-size: 12.5px; }
.wa-etqs { display: flex; gap: 6px; flex-wrap: wrap; }
.wa-etqs .wa-etq { font-size: 11.5px; padding: 3px 9px; }
.wa-etqs button.wa-etq { cursor: pointer; background: transparent; border-style: dashed; border-color: var(--borda-forte); }
.wa-etqs .wa-etq.marcada { background: color-mix(in srgb, var(--etq, var(--texto-fraco)) 18%, var(--branco)); color: var(--texto); border-style: solid; border-color: transparent; }
.wa-op { display: flex; flex-direction: column; gap: 2px; margin: 0 0 8px; border: 1px solid var(--borda); border-radius: var(--raio-sm); padding: 10px 12px; font-size: 12.5px; color: var(--texto-secundario); }
.wa-op .forte { font-weight: 600; font-size: 13px; color: var(--texto); }
.wa-obs-form { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; margin-bottom: 8px; }
.wa-obs-form .textarea { width: 100%; resize: vertical; }
.wa-obs, .wa-arqs { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.wa-obs-texto { font-size: 12.5px; white-space: pre-wrap; overflow-wrap: anywhere; }
.wa-obs-quem { font-size: 11px; color: var(--texto-fraco); }
.wa-arqs li { display: flex; gap: 8px; align-items: center; justify-content: space-between; }
.wa-arqs a { display: flex; gap: 8px; align-items: center; min-width: 0; font-size: 12.5px; color: var(--texto); overflow-wrap: anywhere; }
.wa-arqs a i { font-size: 18px; color: var(--texto-suave); }
@media (min-width: 1301px) {
  .wa-conv-acoes [data-wa-contato] { display: none; }
}
@media (max-width: 1300px) and (min-width: 881px) {
  .wa-central { grid-template-columns: 300px minmax(0, 1fr); }
  .wa-central .wa-painel { display: none; }
  .wa-central.contato .wa-conv { display: none; }
  .wa-central.contato .wa-painel { display: flex; }
  .wa-painel-topo { display: block; }
}
@media (max-width: 880px) {
  .pagina.wa-pagina { padding: 12px 0 0; }
  .wa-pagina > .pagina-cab, .wa-pagina > .wa-tabs, .wa-pagina > .wa-aviso-conta { margin-left: 16px; margin-right: 16px; }
  .wa-central { grid-template-columns: minmax(0, 1fr); border-radius: 0; border-left: 0; border-right: 0; height: calc(100vh - var(--topbar-h) - 130px); height: calc(100dvh - var(--topbar-h) - 130px); min-height: 360px; }
  .wa-col + .wa-col { border-left: 0; }
  .wa-central .wa-conv, .wa-central .wa-painel { display: none; }
  .wa-central.abriu .wa-lista-col { display: none; }
  .wa-central.abriu .wa-conv { display: flex; }
  .wa-central.abriu.contato .wa-conv { display: none; }
  .wa-central.abriu.contato .wa-painel { display: flex; }
  .wa-voltar { display: inline-grid; }
  .wa-painel-topo { display: block; }
  .wa-bolha { max-width: 86%; }
  /* Conversa aberta no celular: ela toma a tela, como no aplicativo. */
  .wa-pagina:has(.wa-central.abriu) > .pagina-cab,
  .wa-pagina:has(.wa-central.abriu) > .wa-tabs,
  .wa-pagina:has(.wa-central.abriu) > .wa-aviso-conta { display: none; }
  .wa-pagina:has(.wa-central.abriu) { padding-top: 0; }
  .wa-central.abriu { height: calc(100vh - var(--topbar-h)); height: calc(100dvh - var(--topbar-h)); min-height: 0; border-top: 0; }
  .wa-conv-cab { flex-wrap: nowrap; padding: 8px 10px; gap: 8px; }
  .wa-conv-cab > .wa-av { display: none; }
  .wa-conv-quem { min-width: 0; }
  .wa-conv-quem .nome { flex-wrap: nowrap; white-space: nowrap; overflow: hidden; }
  .wa-conv-quem .nome .badge { display: none; }
  .wa-conv-acoes { flex-wrap: nowrap; gap: 4px; overflow-x: auto; }
  .wa-compor-linha .rot-enviar { display: none; }
}
/* Rotulo de form moderno (Padrao_Formulario, correcao 02/07): 13px, 600, sem caixa
   alta. O .campo > label global do projeto e o legado em caixa alta; as telas novas
   (.au-form, .pl-card) ja sobrescrevem, e o CRM faz o mesmo no seu escopo. */
.cr-bar .campo > label, .cr-param .campo > label, .cr-modal .campo > label {
  font-size: 13px; font-weight: 600; text-transform: none; letter-spacing: 0;
  color: var(--texto-secundario);
}
/* Quem so VE: o toggle mostra o estado e nao age (slot do mesmo tamanho, esmaecido). */
.cr-acoes .cv-sw input:disabled + label { opacity: .45; cursor: not-allowed; }
@media (max-width: 720px) {
  .cr-grid, .cr-grid.cr-catalogo { grid-template-columns: 1fr; }
  .cr-bar .campo { flex: 1 1 100%; }
  .cr-bar .campo.cr-campo-cor { flex: 0 0 auto; }
  .cr-bar .btn { min-height: 44px; }
  .cr-item { flex-wrap: wrap; }
  .cr-item-meta { max-width: 100%; }
  /* Duas colunas com SelectBusca (min-width 200px) vazam a viewport de 375px:
     medido scrollWidth 451 na instancia. Uma coluna no celular. */
  .cr-param .linha-campos { grid-template-columns: 1fr; }
  .cr-param .selectbusca { min-width: 0; }
  .cr-rodape-form .btn { min-height: 44px; }
}

/* ---- CRM > Produtos (F3): listagem e ficha ---- */
.cr-td-foto { width: 56px; padding-top: 4px; padding-bottom: 4px; }
.cr-mini { width: 40px; height: 40px; border-radius: var(--raio-sm); object-fit: cover; display: block; border: 1px solid var(--borda); background: var(--fundo-2); }
.cr-mini-vazia { display: grid; place-items: center; color: var(--texto-fraco); font-size: 18px; }
img.cr-mini { cursor: zoom-in; }

/* Lightbox das fotos do produto (clique na miniatura). Escurece a tela, centraliza a
   foto em tamanho cheio e navega entre as fotos com as setinhas ou as teclas <- ->. */
.cr-lightbox { position: fixed; inset: 0; z-index: var(--z-foto); display: none; align-items: center;
  justify-content: center; gap: 10px; padding: 4vh 2vw; padding: 4dvh 2vw; background: var(--veu-foto); }
.cr-lightbox.aberto { display: flex; }
body.cr-lb-aberto { overflow: hidden; }
.cr-lb-palco { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 12px; min-width: 0; }
.cr-lb-img { max-width: min(90vw, 1100px); max-height: 84vh; max-height: 84dvh; object-fit: contain; border-radius: 8px;
  background: var(--branco); box-shadow: var(--sombra-foto); }
.cr-lb-contador { color: color-mix(in srgb, var(--branco) 88%, transparent); font-size: 13px; font-weight: 600; letter-spacing: .04em; }
.cr-lb-fechar { position: absolute; top: 16px; right: 20px; width: 44px; height: 44px; }
.cr-lb-seta { flex: none; width: 52px; height: 52px; }
.cr-lb-fechar, .cr-lb-seta { border: none; border-radius: var(--raio-full, 999px); cursor: pointer;
  color: var(--branco); background: color-mix(in srgb, var(--branco) 13%, transparent); display: flex; align-items: center;
  justify-content: center; font-size: 24px; transition: background .15s ease; }
.cr-lb-fechar:hover, .cr-lb-seta:hover { background: color-mix(in srgb, var(--branco) 26%, transparent); }
.cr-lb-fechar:focus-visible, .cr-lb-seta:focus-visible { outline: 2px solid var(--branco); outline-offset: 2px; }
@media (max-width: 640px) {
  .cr-lb-seta { width: 44px; height: 44px; font-size: 20px; }
  .cr-lb-img { max-width: 94vw; }
}
.cr-tab-produtos .cr-td-desc { max-width: 360px; overflow: hidden; text-overflow: ellipsis; }
.cr-ficha-corpo { display: flex; flex-direction: column; gap: var(--sp-5); }
.cr-secao { display: flex; flex-direction: column; gap: var(--sp-3); }
.cr-secao-titulo { margin: 0; display: flex; align-items: center; gap: var(--sp-2); font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--texto-secundario); padding-bottom: var(--sp-2); border-bottom: 1px solid var(--borda); }
.cr-secao-titulo i { color: var(--cor-primaria); font-size: 16px; }
.cr-secao .campo { margin-bottom: 0; }
.cr-secao .linha-campos { gap: var(--sp-4); }
.cr-drop { padding: var(--sp-4); }
.cr-faixa-inativa { opacity: .6; }
.cr-galeria { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: var(--sp-3); }
.cr-foto { position: relative; border: 1px solid var(--borda); border-radius: var(--raio-sm); overflow: hidden; background: var(--fundo-2); aspect-ratio: 1 / 1; }
.cr-foto img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cr-foto.pendente { border-style: dashed; border-color: var(--cor-primaria); }
.cr-foto-tag { position: absolute; top: 6px; left: 6px; padding: 2px 8px; border-radius: var(--raio-full); background: var(--cor-primaria); color: var(--branco); font-size: 11px; font-weight: 700; }
.cr-foto.pendente .cr-foto-tag { background: var(--texto-secundario); }
.cr-foto-acoes { position: absolute; right: 4px; bottom: 4px; display: flex; gap: 4px; }
.cr-foto-acoes .btn-icone { background: var(--branco); width: 30px; height: 30px; }
.cr-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.cr-chip { position: relative; display: inline-flex; align-items: center; gap: 8px; padding: 6px 12px; border: 1px solid var(--borda); border-radius: var(--raio-full); background: var(--branco); font-size: 13px; font-weight: 600; color: var(--texto-secundario); cursor: pointer; user-select: none; transition: var(--transicao); }
.cr-chip input { position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none; }
.cr-chip:hover { border-color: var(--borda-forte); color: var(--texto); }
.cr-chip.marcada { border-color: var(--cor-primaria); background: var(--cor-primaria-suave); color: var(--cor-primaria-escura); }
.cr-chip.inativa { opacity: .55; }
.cr-chip:has(input:disabled) { cursor: not-allowed; }
/* Foco do teclado: o contorno e do chip inteiro. O input e transparente, e o chip
   de modelo nao tem a bolinha que o de cor tem: com o contorno so nela, o Tab
   chegava ao modelo sem marca nenhuma (auditoria 09/2026, ponto 6). */
.cr-chip:has(input:focus-visible) { outline: 2px solid var(--cor-primaria); outline-offset: 2px; }
.cr-chip-sw { width: 14px; height: 14px; border-radius: var(--raio-full); border: 1px solid var(--borda-forte); background: var(--fundo-2); flex: 0 0 auto; }
.cr-chip-mais { border-style: dashed; }
.cr-precos { display: flex; flex-direction: column; gap: var(--sp-2); }
.cr-faixa { display: grid; grid-template-columns: 90px minmax(120px, 1fr) 160px 160px; gap: var(--sp-3); align-items: end; padding: 8px 10px; border: 1px solid var(--borda); border-radius: var(--raio-sm); }
.cr-faixa.em-uso, .cr-faixa-padrao { border-color: var(--cor-primaria); background: var(--cor-primaria-suave); }
.cr-faixa-cab { border: none; padding: 0 10px; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--texto-suave); }
.cr-faixa-usar { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600; cursor: pointer; align-self: center; }
.cr-faixa-usar input { width: 16px; height: 16px; accent-color: var(--cor-primaria); }
.cr-faixa-fixa { color: var(--cor-primaria); cursor: default; }
.cr-faixa-nome { font-weight: 600; font-size: 13.5px; align-self: center; display: flex; align-items: center; gap: 8px; }
.cr-faixa .campo > label.cr-label-sm { font-size: 11px; color: var(--texto-suave); }
.cr-faixa .input:disabled { opacity: .5; }
.cr-ficha-loading { display: flex; align-items: center; justify-content: center; gap: var(--sp-3); padding: var(--sp-4); background: var(--fundo-2); border-radius: var(--raio-sm); }
.cr-ficha-loading .spinner-circle { width: 28px; height: 28px; border-width: 3px; }
@media (max-width: 720px) {
  .cr-faixa { grid-template-columns: 1fr 1fr; }
  .cr-faixa-cab { display: none; }
  .cr-faixa .cr-faixa-nome { grid-column: 2; }
  .cr-galeria { grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); }
  .cr-secao .linha-campos { grid-template-columns: 1fr; }
  .cr-ficha .selectbusca { min-width: 0; }
  /* Nova Venda no celular: as linhas planas (sem .cr-secao) empilham em uma coluna; a
     grade de itens rola de lado dentro do bloco, como a Nova Fatura. */
  .cr-venda-corpo .linha-campos, .cr-venda-corpo .cr-tres { grid-template-columns: 1fr; }
  .cr-ficha .modal-rodape .btn, .cr-chip { min-height: 44px; }
  .cr-foto-acoes .btn-icone { width: 44px; height: 44px; }
  .cr-tab-produtos .cr-td-desc { max-width: 220px; }
}

/* ---- CRM > Clientes (F5) ---- */
.cr-link { color: inherit; text-decoration: none; border-bottom: 1px dotted var(--borda-forte); }
.cr-link:hover { color: var(--cor-primaria); border-bottom-color: var(--cor-primaria); }
.cr-apelido { display: block; font-size: 12px; color: var(--texto-suave); }
.cr-apelido-h1 { font-weight: 500; color: var(--texto-suave); }
.cr-tab-clientes .cr-td-desc { max-width: 280px; overflow: hidden; text-overflow: ellipsis; }
.cr-tres { grid-template-columns: 1fr 1fr 1fr; }
.cr-tres .cr-col-2 { grid-column: span 2; }
.cr-consent { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3); border: 1px solid var(--borda); border-radius: var(--raio-sm); background: var(--fundo-2); }
.cr-consent-texto { font-size: 13px; color: var(--texto); cursor: pointer; margin: 0; }
.cr-pref-lista { display: flex; flex-direction: column; gap: var(--sp-2); }
.cr-pref-titulo { font-size: 12px; font-weight: 700; color: var(--texto-suave); }
.cr-presets-quebra { flex-wrap: wrap; height: auto; padding: 3px; }
.cr-detalhe { margin-bottom: var(--sp-5); }
.cr-dl { display: grid; grid-template-columns: max-content 1fr; gap: var(--sp-2) var(--sp-4); margin: 0; font-size: 13.5px; }
.cr-dl dt { color: var(--texto-suave); font-weight: 600; }
.cr-dl dd { margin: 0; color: var(--texto); overflow-wrap: anywhere; }
.cr-chips-leitura { margin-bottom: var(--sp-3); }
.cr-chips-leitura .cr-chip { cursor: default; }
.cr-compras .tabela-topo { justify-content: space-between; }
.cr-compras + .cr-compras { margin-top: var(--sp-4); }   /* dois cards de secao empilhados sem costura */
.cr-tab-titulo { margin: 0; font-size: 15px; }
@media (max-width: 720px) {
  .cr-tres { grid-template-columns: 1fr; }
  .cr-tres .cr-col-2 { grid-column: auto; }
  .cr-dl { grid-template-columns: 1fr; gap: 2px var(--sp-3); }
  .cr-dl dd { margin-bottom: var(--sp-2); }
}

.me-modulo-atual { display: inline-block; margin-left: 8px; padding: 2px 10px; border-radius: var(--raio-full); background: var(--cor-primaria-suave); color: var(--cor-primaria-escura); font-size: 13px; font-weight: 600; vertical-align: middle; }
/* ---- CRM > Vendas (F6) ---- */
.cr-tab-vendas .cr-td-desc { max-width: 260px; overflow: hidden; text-overflow: ellipsis; }
.cr-tab-followup .cr-td-desc { max-width: 280px; overflow: hidden; text-overflow: ellipsis; }
/* Grade de itens da Nova Venda (aprovada 2026-09-05): a .itens-grid da fatura com cada
   coluna de largura propria (colgroup no template; Produto fica com a sobra), cabecalho
   sobre o conteudo e cada controle preso a sua celula - o .selectbusca herda min-width
   200px da base e invadia a coluna vizinha; aqui a coluna manda. */
.venda-grid { table-layout: fixed; min-width: 880px; }
/* sem overflow:hidden na celula: o painel do SelectBusca abre por baixo dela e seria
   recortado (achado do Ricardo 2026-09-05); quem prende o controle e o width/min-width. */
.venda-grid th, .venda-grid td { padding: 8px 8px; }
.venda-grid th.num, .venda-grid td.num { text-align: right; }
.venda-grid .input, .venda-grid .input.num, .venda-grid .selectbusca, .venda-grid .sb-display {
  width: 100%; min-width: 0; max-width: 100%; box-sizing: border-box; }
.venda-grid .sb-label { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.venda-grid td.col-sub { font-weight: 700; white-space: nowrap; }
.venda-grid td .btn-icone { margin: 0; }
/* (a regra de overflow do .itens-scroll e global: ver o bloco da fatura acima) */
.cr-venda-corpo .campo { margin-bottom: 0; }
.cr-venda-corpo > .linha-campos { margin-bottom: 14px; }
.cr-venda-corpo .preview-parcelas { margin-top: 4px; }
.cr-selo-entrada { margin-left: 8px; vertical-align: middle; }

/* Duas opcoes do MESMO tamanho (pedido do Ricardo 2026-09-05): o par ocupa a largura do
   campo e reparte 50/50 - iguais entre si e nunca mais largas que o espaco (com
   inline-grid as duas mediam o rotulo maior e o par estourava o campo de ~420px). */
.cr-duo { display: grid; grid-template-columns: 1fr 1fr; width: 100%; align-items: stretch; height: 38px; border: 1px solid var(--borda); border-radius: var(--raio-sm); overflow: hidden; box-sizing: border-box; background: var(--branco); }
.cr-duo button { border: none; background: var(--branco); padding: 0 14px; font-size: 12.5px; font-weight: 700; color: var(--texto-secundario); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 6px; white-space: nowrap; }
.cr-duo button + button { border-left: 1px solid var(--borda); }
.cr-duo button.on { background: var(--cor-primaria); color: var(--branco); }
.cr-aviso-param { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); border: 1px solid var(--alerta); border-radius: var(--raio-sm); background: var(--alerta-suave); color: var(--texto); font-size: 13px; margin-bottom: var(--sp-4); }
.cr-encomenda-acoes { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
@media (max-width: 720px) {
  .cr-duo button, .cr-encomenda-acoes .btn { min-height: 44px; }
}

/* ============================================================================
   [PAINEL DO DONO] Modulos contratados por cliente (2026-09-06)

   A lista de caixas dos modais "Novo cliente" e "Modulos liberados", e a celula de
   badges da listagem. Uma opcao por card do portal, com o icone do proprio modulo
   (services.portal.MODULOS) para o dono reconhecer o que esta liberando. Cor por
   token; o estado invalido reusa o .campo-invalido dos inputs.
   ============================================================================ */
.pf-mod-lista { display: grid; gap: 8px; }
/* No modal de 700px as opcoes cabem lado a lado: o "Novo cliente" ja tinha nove campos
   e passava dos 90vh em 1280x800 (medido: caixa 720px para 967px de conteudo); em uma
   coluna o bloco custava 185px, em duas custa ~120px. No celular volta a empilhar:
   721px, porque em 720 exatos ainda e celular (o max-width: 720px do resto). */
@media (min-width: 721px) { .pf-mod-lista { grid-template-columns: 1fr 1fr; } }
.pf-mod-opcao {
  display: grid; grid-template-columns: auto auto 1fr; align-items: center; gap: 12px;
  padding: 10px 12px; border: 1px solid var(--borda); border-radius: 7px;
  background: var(--branco); cursor: pointer;
}
.pf-mod-opcao:hover { border-color: var(--cor-primaria); }
.pf-mod-opcao:has(input:checked) { background: var(--cor-primaria-suave); border-color: var(--cor-primaria); }
.pf-mod-icone {
  width: 32px; height: 32px; border-radius: 7px; display: inline-flex;
  align-items: center; justify-content: center; font-size: 18px;
  background: var(--fundo-2); color: var(--cor-primaria);
}
.pf-mod-texto { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pf-mod-texto strong { font-size: 13px; }
.pf-mod-lista.campo-invalido { outline: 1px solid var(--erro); outline-offset: 3px; border-radius: 7px; }
.pf-modulos { white-space: nowrap; }
.pf-modulos .badge { margin-right: 4px; }
.pf-modulos .badge i { font-size: 13px; }
/* A marca do acesso por IP antes do nome da empresa (decisao 128): so nas excecoes,
   azul no restrito e ambar no so observar. Livre, o padrao, nao leva marca. */
.pf-acesso-marca { margin-right: 6px; font-size: 14px; vertical-align: -2px; }
.pf-acesso-marca.restrito { color: var(--info); }
.pf-acesso-marca.observar { color: var(--alerta); }

/* O "+N" da celula e o balao com o que nao coube. A celula mostra tres badges (o corte
   e de services.plataforma.modulos_da_listagem): sem o corte, um contrato de dez
   modulos faz a linha passar de 1.700px, a tabela rola de lado e a coluna de Acoes sai
   da vista. O "+N" e um <button> com cara de badge, e nao um <span>, porque ele ABRE o
   modal de modulos: no toque nao ha hover, e o balao sozinho deixaria o celular sem a
   lista. O balao mora no <body>, com position:fixed, e nao dentro da celula: a
   .tabela-scroll tem overflow-x, e overflow recorta nos DOIS eixos - filho da celula, o
   balao sairia cortado na altura da linha. Quem o posiciona e plataforma-clientes.js. */
.pf-mod-mais {
  border: 0; font-family: inherit; cursor: pointer;
  background: var(--fundo-2); color: var(--texto-secundario);
}
.pf-mod-mais:hover, .pf-mod-mais:focus-visible { background: var(--borda-forte); color: var(--texto); }
.pf-mod-balao {
  position: fixed; z-index: var(--z-balao); max-width: 260px;
  display: flex; flex-wrap: wrap; gap: 4px; padding: 8px;
  background: var(--branco); border: 1px solid var(--borda);
  border-radius: var(--raio-sm); box-shadow: var(--sombra-md);
}

/* Foco pelo teclado nas pecas que o teclado passou a alcancar (auditoria 09/2026, UX-02;
   decisao 130). So :focus-visible: quem usa o mouse nao ve nada novo.
   - o campo do SelectBusca ganha o MESMO contorno de um .input em foco (a borda e a
     sombra suave), e nao o anel geral de 2px do base.css: e campo, e tem de parecer
     campo. O outline transparente fica para o modo de alto contraste do Windows, que
     troca a cor dele e ignora a sombra;
   - o cabecalho ordenavel e o item do menu da tabela levam o anel POR DENTRO (offset
     negativo): o cabecalho vive dentro da .tabela-scroll, que recorta o que passa da
     borda, e o item ocupa a largura do menu inteiro. */
.selectbusca .sb-display:focus-visible {
  outline: 2px solid transparent;
  border-color: var(--cor-primaria); box-shadow: 0 0 0 3px var(--cor-primaria-suave);
}
.te-tab thead th[tabindex]:focus-visible { outline: 2px solid var(--cor-primaria); outline-offset: -2px; }
.ta-menu-item:focus-visible {
  outline: 2px solid var(--cor-primaria); outline-offset: -2px;
  background: var(--fundo); color: var(--cor-primaria);
}
.ta-menu-item:focus-visible i { color: var(--cor-primaria); }

/* ============================================================================
   Celular: alvo de toque e fonte de campo (auditoria 09/2026, UX-08 e RESP-01;
   decisao 133). Ate 720px, onde o projeto vira celular:
   - os botoes mais tocados (as acoes da linha, a paginacao, o X da janela e o
     do aviso) sobem a 44px, o minimo da regra Responsividade_Sempre e o que o
     CRM e o portal ja davam aos deles, contra os 25 a 34px de antes.
     min-width/min-height, e nao width/height: vencem a largura de qualquer
     regra de contexto e nao encolhem quem ja e maior. O X da janela (34x24) e
     o do aviso (30x23: o <i> dele herda os 18px de .flash i) ganham margem
     negativa do tanto que cresceram: o cabecalho da janela e a faixa do aviso
     ficam da altura de antes, e o desenho do X fica no mesmo lugar. Mudou o
     tamanho de um X, refaz a margem dele;
   - o rodape da paginacao empilha: a contagem em cima e os controles embaixo,
     centrados. Na grade de tres colunas (contagem, controles, vazio) a coluna
     da contagem nao encolhe abaixo da palavra mais longa, e com os botoes de
     44px o rodape passava da janela (medido: a pagina rolava de lado 9px em
     360 e 49px em 320). Os controles ainda podem quebrar linha: e a rede para
     uma posicao longa (Pagina 100 de 120) numa janela de 320;
   - a coluna de largura fixa que guarda botao cresce com ele: a largura dela
     era a conta dos botoes de 25px, e com os de 44 a celula recortava o ultimo
     (medido: o Excluir ficava com 30px de fora em Clientes e Fornecedores e
     14px em Produtos) ou o botao passava dela (o remover da grade de itens:
     6px, na fatura e na venda). A conta fica escrita no calc: os botoes,
     os vaos de 6px do .acoes-cel e o padding da celula. Coluna fixa nova com
     botao entra aqui;
   - o filtro de coluna da tabela fica com os 16px dos outros campos (a regra de
     input, select e textarea, la no topo, perde para .te-tab .col-filtro, que e
     mais especifica): com menos de 16px o iPhone amplia a tela ao focar o
     campo, e ela continua ampliada depois.
   ========================================================================== */
@media (max-width: 720px) {
  .btn-icone, .pg-btn { min-width: 44px; min-height: 44px; }
  /* o .seg (Quadro/Lista, tipo da fatura, pessoa do cadastro) e toque de toda hora */
  .seg-btn { min-height: 44px; }
  .modal-x { min-width: 44px; min-height: 44px; margin: -10px -5px -10px 0; }
  .flash-x {
    min-width: 44px; min-height: 44px; margin: -10.5px -7px -10.5px auto;
    display: inline-grid; place-items: center;
  }
  .pg-rodape { grid-template-columns: 1fr; justify-items: center; row-gap: 6px; }
  .pg-nav { flex-wrap: wrap; justify-content: center; }
  .te-tab[data-ta="cad_clientes_fornecedores"] th.no-sort { width: calc(4 * 44px + 3 * 6px + 20px); }
  .te-tab[data-ta="cad_produtos"] th.no-sort { width: calc(3 * 44px + 2 * 6px + 20px); }
  .itens-grid .no-sort, .itens-grid .col-remover { width: calc(44px + 16px); }
  .te-tab .col-filtro { font-size: 16px; height: 36px; }
}

/* ============ Sair por POST (auditoria 09/2026, SEC-11; decisao 146) ============ */
/* Onde a tela tinha um link de texto para sair, o formulario leva este botao, com o
   desenho do link. */
.btn-como-link { background: none; border: 0; padding: 0; font: inherit; color: var(--cor-primaria); cursor: pointer; }
.btn-como-link:hover { text-decoration: underline; }
/* A pergunta da porta do dono ("Deseja sair?"), no cartao escuro. */
.pl-texto { margin: 8px 0 22px; font-size: 13.5px; color: var(--pl-muted); }

/* ============ Matriz de permissoes no celular ============ */
/* A .matriz-tab tem table-layout: fixed, para Ver e Editar ficarem na mesma coluna em
   todo grupo (com o layout automatico, cada tabela media as colunas pelo proprio
   conteudo, e elas andavam de um grupo para o outro). No celular os 120px de cada
   coluna de marca espremiam o nome do modulo (46px em 320); aqui elas encolhem, e o
   cabecalho mais longo (Concedida) ainda cabe. */
@media (max-width: 720px) {
  .matriz-tab th:not(:first-child) { width: 84px; }
  .matriz-tab td:not(:first-child), .matriz-tab th:not(:first-child) { padding-left: 6px; padding-right: 6px; }
}

/* ============ Oportunidades: o funil (Trabalho 11, F3) ============ */
/* A tela tem a Lista (a .tabela-wrap de sempre, que liga o cabecalho fixo do quirk
   10 mesmo escondida) e o Quadro, que vem ANTES dela. Com a pagina presa na altura
   da janela, o painel do quadro toma o que sobra (flex 1, min-height 0), o quadro
   rola de lado e cada coluna rola os proprios cartoes: o documento nao rola. */
.op-painel-quadro { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; gap: 12px; }
.op-visoes { margin-bottom: 14px; }
.op-busca { max-width: 420px; }
.op-quadro {
  flex: 1 1 auto; min-height: 0; display: flex; gap: 12px; align-items: stretch;
  overflow-x: auto; overflow-y: hidden; padding-bottom: 6px;
  scroll-snap-type: x proximity; overscroll-behavior-x: contain;
}
.op-quadro > .vz { flex: 1; }
.op-coluna {
  flex: 0 0 280px; min-height: 0; display: flex; flex-direction: column;
  background: var(--fundo-2); border: 1px solid var(--borda); border-radius: var(--raio);
  scroll-snap-align: start;
}
.op-coluna.op-alvo { border-color: var(--cor-primaria); background: var(--cor-primaria-suave); }
.op-coluna-cab {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 12px; border-bottom: 1px solid var(--borda);
  border-top: 3px solid var(--borda-forte); border-radius: var(--raio) var(--raio) 0 0;
}
.op-tipo-ganha .op-coluna-cab { border-top-color: var(--ok); }
.op-tipo-perdida .op-coluna-cab { border-top-color: var(--erro); }
.op-coluna-cab h2 { margin: 0; font-size: 14px; font-weight: 700; flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.op-contagem {
  font-size: 12px; font-weight: 700; color: var(--texto-suave);
  background: var(--branco); border-radius: var(--raio-full); padding: 1px 8px;
}
.op-soma { flex: 1 0 100%; font-size: 12px; color: var(--texto-suave); font-variant-numeric: tabular-nums; }
.op-cartoes {
  flex: 1 1 auto; min-height: 60px; overflow-y: auto; overscroll-behavior: contain;
  display: flex; flex-direction: column; gap: 8px; padding: 10px;
}
.op-cartao {
  background: var(--branco); border: 1px solid var(--borda); border-radius: var(--raio-sm);
  box-shadow: var(--sombra); padding: 10px 12px;
  display: flex; flex-direction: column; gap: 4px;
}
.op-cartao[draggable="true"] { cursor: grab; }
.op-cartao.op-arrastando { opacity: .5; }
.op-cartao-titulo { margin: 0; font-size: 13.5px; font-weight: 600; overflow-wrap: anywhere; }
.op-cartao-quem, .op-cartao-resp, .op-cartao-motivo { margin: 0; font-size: 12.5px; color: var(--texto-suave); overflow-wrap: anywhere; }
.op-cartao-motivo { font-style: italic; }
.op-cartao-linha { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.op-fechada { background: var(--fundo); }
.op-cartao-valor { font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums; }
.op-cartao .acoes-cel { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 4px; }
.op-coluna-pe { padding: 8px 10px 10px; text-align: center; border-top: 1px solid var(--borda); }
.op-fim { font-size: 12px; color: var(--texto-fraco); }
.op-mover-nome { margin: 0 0 12px; font-weight: 600; overflow-wrap: anywhere; }
/* A aba Funil dos Parametros: as etapas e o campo da etapa nova. */
.op-form-inline { display: inline-flex; margin: 0; }
.op-etapa-nova { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; margin-top: 16px; }
.op-etapa-nova .campo { flex: 1 1 260px; margin: 0; }
@media (max-width: 720px) {
  /* No celular a coluna de 280px cabe ate em 320, e o dedo passa de uma para a outra
     pelo encaixe do scroll-snap. */
  .op-busca { max-width: none; }
  .op-coluna-pe .btn { min-height: 44px; }
}
