.ips-header { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); margin-bottom: var(--space-5); flex-wrap: wrap; } .ips-header h2 { font-size: 1.05rem; font-weight: 700; } .ips-header-actions { display: flex; gap: var(--space-3); } .ips-subtitle { font-size: 0.85rem; color: var(--text-muted); margin-top: 2px; } /* "Revisão " — pedido explícito do usuário pra identificar de cara qual empresa está sendo importada, sem precisar abrir a aba de linhas. Cor mais discreta que o próprio "Revisão", pra não competir com o título. */ .ips-review-empresa { font-size: 0.85rem; font-weight: 400; color: var(--text-muted); } .ips-empty { text-align: center; color: var(--text-muted); font-size: 0.9rem; padding: var(--space-6); border: 1px dashed var(--border-subtle); border-radius: var(--radius-md); } /* Ordenação por coluna no histórico (#ips-list-table) — mesma linguagem visual do ícone ↕ estático de ramais-lookup.js, só que com classes próprias (esta página não carrega ramais-lookup.css). */ #ips-list-table th[data-sort] { cursor: pointer; user-select: none; white-space: nowrap; } .ips-sort-icon { color: var(--text-muted); font-size: 0.75rem; } #ips-list-table th[data-sort].is-sort-asc .ips-sort-icon, #ips-list-table th[data-sort].is-sort-desc .ips-sort-icon { color: var(--accent); } /* Filtro "estilo Excel" por coluna do histórico (ips-list-table) — botão de funil dentro do próprio de ordenação (não conflita com o clique de ordenar: o JS ignora cliques dentro de .ips-col-filter antes de tratar como ordenação) + popup com busca/checklist (reaproveita .checklist-* de components.css, mesmo componente já usado nos checklists de Perfis de Acesso/Departamento). .pa-table-wrap normalmente usa overflow:hidden pra arredondar os cantos da tabela — sem abrir mão disso pra tabela nenhuma, ips-list-table-wrap (só esta tabela) sobrescreve pra visible, senão o popup (que precisa "vazar" pra fora do cabeçalho, sobre as linhas) seria cortado ali. */ .ips-list-table-wrap { overflow: visible; } .ips-col-filter { position: relative; display: inline-block; margin-left: var(--space-1); } .ips-col-filter__btn { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; padding: 0; border: none; background: none; color: var(--text-muted); cursor: pointer; border-radius: var(--radius-sm); vertical-align: middle; } .ips-col-filter__btn:hover { color: var(--text-primary); background: var(--bg-canvas); } .ips-col-filter__btn.is-active { color: var(--accent); } .ips-col-filter__popup { position: absolute; top: calc(100% + 6px); left: 0; z-index: 20; width: 220px; padding: var(--space-3); background: var(--bg-surface-raised); border: 1px solid var(--border-subtle); border-radius: var(--radius-sm); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35); text-align: left; text-transform: none; font-weight: 400; letter-spacing: normal; color: var(--text-primary); } .ips-col-filter__popup .checklist-box { max-height: 220px; } .ips-col-filter__actions { display: flex; justify-content: space-between; gap: var(--space-2); margin-top: var(--space-2); } .ips-col-filter__actions button { flex: 1; padding: var(--space-1) var(--space-2); font-size: 0.8rem; } /* Paginação do histórico — só Anterior/Próxima + "Página X de Y", sem numeração de páginas (lista tende a ser curta; um seletor de tamanho de página, como em ramais-lookup.js, seria demais pra esse caso). */ .ips-list-pagination { display: flex; align-items: center; justify-content: center; gap: var(--space-3); margin-top: var(--space-4); } .ips-list-pagination__info { font-size: 0.85rem; color: var(--text-muted); } /* Quantidade de registros do histórico, abaixo da paginação. */ .ips-list-count { text-align: center; font-size: 0.8rem; color: var(--text-muted); margin-top: var(--space-2); } /* Coluna de checkbox de seleção (primeira do #ips-list-table). */ .ips-select-col { width: 36px; text-align: center; } /* Barra de exclusão em lote — só aparece com pelo menos 1 linha selecionada (ver updateBulkActionsUI em importacao-plano-saude.js). */ .ips-list-bulk-actions { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-3); padding: var(--space-3) var(--space-4); border: 1px solid var(--border-subtle); border-radius: var(--radius-sm); background: var(--bg-surface); } .ips-list-bulk-actions span { font-size: 0.85rem; color: var(--text-secondary); } /* Formulário de nova importação */ .ips-form { background: var(--bg-surface); border: 1px solid var(--border-subtle); border-radius: var(--radius-md); padding: var(--space-5); max-width: 640px; margin: 0 auto; } .ips-upload-box { border: 1px solid var(--border-subtle); border-radius: var(--radius-sm); padding: var(--space-3); margin-bottom: var(--space-3); } .ips-upload-box:last-child { margin-bottom: 0; } .ips-upload-box__title { font-size: 0.85rem; font-weight: 600; color: var(--text-primary); } .ips-upload-box__hint { font-size: 0.78rem; color: var(--text-muted); margin-top: 2px; margin-bottom: var(--space-3); } /* Toggle "Buscar automaticamente do Questor" / "Anexar manualmente" — só dois radios lado a lado, mesmo espírito de .ips-custeio-radios (radio + .modal-checkbox), sem o recuo/coluna deles porque aqui não há titular/dependente por baixo, só a escolha em si. */ .ips-planilha-origem-opcoes { display: flex; gap: var(--space-5); margin-bottom: var(--space-3); } .ips-file-field { position: relative; display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; } .ips-file-field__btn { display: inline-flex; align-items: center; gap: var(--space-2); cursor: pointer; flex-shrink: 0; } .ips-file-field__input { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; } .ips-file-field__input:focus-visible + .ips-file-field__name { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-sm); } .ips-file-field__name { font-size: 0.85rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 260px; } .ips-file-field__remove { flex-shrink: 0; } /* Resultado da pré-validação (endpoint /validar-arquivo/), abaixo do campo de upload — some enquanto não há arquivo anexado ou enquanto a validação está em andamento. */ .ips-file-field__status { font-size: 0.8rem; margin-top: var(--space-2); margin-bottom: 0; } .ips-file-field__status--pendente { color: var(--text-muted); } .ips-file-field__status--ok { color: #2f9e6e; } .ips-file-field__status--erro { color: var(--danger); } /* "Tipo de importação" fica visualmente bem separado do quadro "2. Arquivo da operadora" logo acima — sem esse respiro extra, os dois blocos ficavam colados o bastante pra confundir onde termina um e começa o outro. */ .ips-tipo-field { margin-top: var(--space-7); } .ips-regra-actions__hint { font-size: 0.78rem; color: var(--text-muted); margin: 0; } /* Combobox pesquisável genérico — usado pelos pares Empresa/Operadora de "Nova Importação" (#ips-imp-*) e "Cadastro de Regras" (#ips-regracad-*). O já herda o estilo padrão de .modal-field input (components.css); aqui só cuida do posicionamento (ocupa o espaço de um nativo. */ .ips-combo__clear { right: 30px; } .ips-combo__toggle { right: var(--space-2); } .ips-combo__clear:hover, .ips-combo__toggle:hover { color: var(--text-primary); } .ips-combo__toggle:disabled { opacity: 0.35; cursor: not-allowed; } .ips-combo__list { position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 20; max-height: 220px; overflow-y: auto; background: var(--bg-surface); border: 1px solid var(--border-subtle); border-radius: var(--radius-sm); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35); } .ips-combo__item { padding: var(--space-2) var(--space-3); font-size: 0.88rem; cursor: pointer; color: var(--text-primary); } .ips-combo__item:hover { background: var(--accent); color: var(--accent-contrast); } .ips-combo__empty { padding: var(--space-2) var(--space-3); font-size: 0.85rem; color: var(--text-muted); } /* Lista de regras salvas — reaproveita .checklist-box como moldura rolável, mas cada linha tem seus próprios botões de ação em vez do checkbox usado pelos outros consumidores de .checklist-box. */ .ips-regras-lista { max-height: 320px; } .ips-regra-row { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); padding: var(--space-2) 0; border-bottom: 1px solid var(--border-subtle); } .ips-regra-row:last-child { border-bottom: none; } .ips-regra-row__info { min-width: 0; flex: 1; } .ips-regra-row__nome { margin: 0; font-weight: 600; font-size: 0.9rem; } .ips-regra-row__meta { margin: 2px 0 0; font-size: 0.78rem; color: var(--text-muted); } .ips-regra-row__obs { margin: var(--space-1) 0 0; font-size: 0.78rem; color: var(--text-muted); white-space: pre-wrap; overflow-wrap: break-word; } .ips-regra-row__actions { display: flex; align-items: center; gap: var(--space-2); flex-shrink: 0; } .ips-tipo-option { border: 1px solid var(--border-subtle); border-radius: var(--radius-sm); padding: var(--space-3); margin-bottom: var(--space-3); } .ips-tipo-option:last-child { margin-bottom: 0; } .ips-custeio-radios { display: flex; flex-direction: column; gap: var(--space-4); margin-top: var(--space-3); padding-left: var(--space-6); } /* "Regra empresa" — alternativa ao custeio manual de mensalidade (.ips-custeio-radios acima), por isso o mesmo recuo/espaçamento, mas só com um texto de estado atual + botão, sem radios titular/dependente. */ .ips-regra-empresa-box { display: flex; flex-direction: column; gap: var(--space-2); align-items: flex-start; margin-top: var(--space-3); padding-left: var(--space-6); } .ips-regra-empresa-box__hint, .ips-regra-empresa-box__atual { margin: 0; font-size: 0.82rem; color: var(--text-muted); } .ips-regra-empresa-box__atual { font-weight: 600; color: var(--text-primary); } /* Observações da regra empresa na tela de Revisão — só leitura, mesma linguagem visual de .ips-regra-observacoes (formulário de nova importação), fica entre o cabeçalho "Revisão" e as abas Mensalidade/Coparticipação/Auditoria/Alterações. */ .ips-regra-empresa-observacoes { margin-bottom: var(--space-4); padding: var(--space-3) var(--space-4); border-radius: var(--radius-sm); background: var(--bg-canvas); border: 1px solid var(--border-subtle); } .ips-regra-empresa-observacoes__label { margin: 0 0 var(--space-1); font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); } .ips-regra-empresa-observacoes__texto { margin: 0; font-size: 0.85rem; color: var(--text-secondary); white-space: pre-wrap; } /* Cada tipo de lançamento tem uma regra própria pra titular e outra pra dependente — este é o agrupamento visual dessas duas sub-listas de radios dentro de .ips-custeio-radios. */ .ips-custeio-pessoa { display: flex; flex-direction: column; gap: var(--space-2); } .ips-custeio-pessoa__label { font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); margin: 0; } .ips-regra-especifica { margin-top: var(--space-3); margin-left: var(--space-6); padding: var(--space-3); border: 1px solid var(--border-subtle); border-radius: var(--radius-sm); background: var(--bg-canvas); } .ips-regra-especifica .modal-field { margin-bottom: var(--space-3); } .ips-regra-especifica .modal-field:last-of-type { margin-bottom: 0; } .ips-regra-especifica__hint { font-size: 0.78rem; color: var(--text-muted); margin-top: var(--space-2); } /* Resumo por tipo, acima de cada tabela da revisão */ .ips-resumo { display: flex; gap: var(--space-5); flex-wrap: wrap; margin-bottom: var(--space-4); font-size: 0.85rem; color: var(--text-secondary); } .ips-resumo strong { color: var(--text-primary); } /* Tabela editável da revisão */ .ips-table-input { width: 100%; /* Só o suficiente pra não ficar colado na borda — a largura real da coluna agora vem do (JS), ajustável até PID_IPS_COL_MIN_WIDTH (60px) pela alça de redimensionar; um min-width maior aqui faria o input vazar do antes desse limite. */ min-width: 30px; padding: var(--space-2); border: 1px solid transparent; border-radius: var(--radius-sm); background: transparent; color: var(--text-primary); font-size: 0.85rem; outline: none; } .ips-table-input:hover { border-color: var(--border-subtle); } .ips-table-input:focus { border-color: var(--accent); background: var(--bg-canvas); } /* Célula não editável (todo campo fora de Valor Empresa/Valor, numa linha que não foi incluída manualmente via "Adicionar linha") — mesmo padding de .ips-table-input, pra não desalinhar a coluna, mas sem borda/hover de input, já que não é editável. */ .ips-table-value { display: block; width: 100%; min-width: 30px; padding: var(--space-2); color: var(--text-secondary); font-size: 0.85rem; overflow: hidden; text-overflow: ellipsis; } .ips-table-scroll { width: 100%; height: 420px; min-width: 320px; min-height: 160px; max-height: 80vh; max-width: 100%; /* `resize` exige overflow != visible pra mostrar a alça de redimensionar no canto inferior direito — o usuário arrasta pra ver mais linhas (altura) e mais colunas de uma vez (largura), até 100% da largura de .page-content (que aqui é .page-content--wide, 1600px em vez do padrão 1200px, ver layout.css). */ resize: both; overflow-y: auto; /* .pa-table-wrap (perfis-acesso.css) tem overflow:hidden, que corta colunas em vez de rolar quando a tabela é mais larga que o container — sobrescreve aqui porque esta tabela tem 10 colunas editáveis, bem mais larga que as tabelas normais de .pa-table. */ overflow-x: auto; } .ips-table-scroll .pa-table { width: auto; /* `table-layout: fixed` + (importacao-plano-saude.js) é o que permite cada coluna ter uma largura própria e ajustável — com o `auto` padrão o navegador recalcula a largura pelo conteúdo e ignora o que a alça de redimensionar define. */ table-layout: fixed; } .ips-table-scroll .pa-table th, .ips-table-scroll .pa-table td { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* Coluna de ações (ícone fixo) não recebe alça de redimensionar, então fica de fora do `position: relative` — evita conflitar com o `position: sticky` dela (ver regra mais abaixo). */ .ips-table-scroll .pa-table th:not(.ips-table-actions) { position: relative; } .ips-col-resize-handle { position: absolute; top: 0; right: -3px; bottom: 0; width: 6px; cursor: col-resize; z-index: 2; } .ips-col-resize-handle:hover, .ips-col-resize-handle:active { background: var(--accent); opacity: 0.5; } /* Enquanto arrasta, trava o cursor em col-resize e desliga seleção de texto na página inteira — sem isso, passar o mouse sobre um da tabela durante o arraste troca o cursor pra texto e pode selecionar conteúdo. */ body.is-resizing-column, body.is-resizing-column * { cursor: col-resize !important; user-select: none; } /* Clicar no cabeçalho ordena a tabela por aquela coluna (alterna asc/desc) — mesmo ícone ↕ estático de #ips-list-table (ver th[data-sort] mais acima), só que aqui aplicado a qualquer .ips-col-sortable. As colunas em si têm ordem fixa (não são mais arrastáveis) — só as linhas são reordenáveis, por ordenação. */ .ips-col-sortable { cursor: pointer; user-select: none; } .ips-col-sortable.is-sort-asc .ips-sort-icon, .ips-col-sortable.is-sort-desc .ips-sort-icon { color: var(--accent); } /* Coluna de ações fixa na primeira posição — fica visível mesmo rolando a tabela pra ver as colunas mais à direita (ex.: Descrição). */ .pa-table th.ips-table-actions, .pa-table td.ips-table-actions { position: sticky; left: 0; z-index: 1; text-align: center; } .pa-table td.ips-table-actions { background: var(--bg-surface); } .pa-table th.ips-table-actions { background: var(--bg-surface-raised); } .ips-remove-linha { width: 28px; height: 28px; } .ips-remove-linha:hover { color: var(--danger); } .ips-add-row { margin-top: var(--space-3); } .ips-add-row button { display: inline-flex; align-items: center; gap: var(--space-2); } .ips-auditoria-motivo { display: inline-flex; align-items: center; padding: 2px 10px; border-radius: var(--radius-pill); font-size: 0.72rem; font-weight: 700; color: var(--danger); background: rgba(var(--danger-rgb), 0.14); white-space: nowrap; } /* Coluna "Ação" da aba Auditoria: botão pra vincular manualmente (motivos de leitura/grafia de nome) ou o selo de já resolvido — mesmo verde de .status-pill--ativo (perfis-acesso.css), pra reaproveitar a mesma linguagem visual de "confirmado/ativo" já usada no resto do portal. */ .ips-auditoria-resolvido { display: inline-flex; align-items: center; padding: 2px 10px; border-radius: var(--radius-pill); font-size: 0.72rem; font-weight: 700; color: #2f9e6e; background: rgba(47, 158, 110, 0.14); white-space: normal; } .ips-empty-cell { color: var(--text-muted); } /* Aba "Alterações" — badge de tipo (edição/inclusão/exclusão) e selo de "Revertida", mesma linguagem visual de .ips-auditoria-motivo/ .ips-auditoria-resolvido acima. Cores por tipo: dourado (edição — uma mudança de valor, neutra), teal (inclusão — algo foi adicionado), vermelho (exclusão — algo foi removido, mesmo tom de alerta de .ips-auditoria-motivo). */ .ips-alteracao-tipo { display: inline-flex; align-items: center; padding: 2px 10px; border-radius: var(--radius-pill); font-size: 0.72rem; font-weight: 700; white-space: nowrap; } .ips-alteracao-tipo--edicao { color: var(--gold); background: rgba(var(--gold-rgb), 0.16); } .ips-alteracao-tipo--inclusao { color: var(--teal); background: rgba(var(--teal-rgb), 0.16); } .ips-alteracao-tipo--exclusao { color: var(--danger); background: rgba(var(--danger-rgb), 0.14); } .ips-alteracao-revertida { display: inline-flex; align-items: center; padding: 2px 10px; border-radius: var(--radius-pill); font-size: 0.72rem; font-weight: 700; color: #2f9e6e; background: rgba(47, 158, 110, 0.14); white-space: nowrap; } /* Modal "Cadastro de Regras" (#ips-regracad-modal) — o formulário de custeio relocado pra dentro dele (checkboxes + radios titular/dependente de dois tipos + observações) é bem mais alto que qualquer outro modal do app; sem isso, `.modal-card` (components.css) cresce livremente e o conteúdo de baixo (Observações, botões de ação) fica cortado fora da viewport em telas mais baixas/com zoom — aqui o cartão vira ele mesmo a área rolável, em vez do overlay inteiro. */ #ips-regracad-modal .modal-card { max-height: 90vh; overflow-y: auto; } /* #ips-regra-empresa-modal é aberto por cima de #ips-regracad-modal (ao clicar "Selecionar regra" dentro do formulário de custeio) — como os dois são .modal-overlay com o mesmo z-index (components.css), a ordem no DOM decidiria quem fica por cima, e #ips-regra-empresa-modal vem ANTES de #ips-regracad-modal no HTML, então ficava escondido atrás dele. Sobe o z-index explicitamente pra sempre renderizar acima, independente da ordem no DOM. */ #ips-regra-empresa-modal { z-index: 110; } /* Toolbar com os comboboxes de Empresa/Operadora (navegar) + "+ Nova regra"; o bloco .ips-regracad-form reaproveita o mesmo .ips-tipo-field/.ips-custeio-radios de antes, só que relocado pra dentro deste modal. */ /* Empresa (com o nome resolvido do Questor ao lado, quando existe) fica sempre numa linha própria, com a Operadora numa linha abaixo — pedido explícito do usuário, tanto aqui quanto em "+ Nova regra" abaixo, pra não competir visualmente com o nome da empresa. */ .ips-regracad-toolbar { display: flex; flex-direction: column; gap: var(--space-3); margin-bottom: var(--space-4); } .ips-regracad-toolbar__row { display: flex; align-items: flex-end; gap: var(--space-3); flex-wrap: wrap; } .ips-regracad-toolbar .modal-field { margin-bottom: 0; flex: 1; min-width: 220px; } .ips-regracad-toolbar__row .btn-outline { flex-shrink: 0; } /* Indica claramente se o formulário abaixo está editando uma regra existente ou criando uma nova — pedido explícito do usuário, pra não confundir os dois modos (ver regracadCarregarParaEdicao()/ regracadEntrarModoNovo() em importacao-plano-saude.js). */ .ips-regracad-modo { margin: 0 0 var(--space-3); font-size: 0.85rem; font-weight: 700; padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); background: var(--bg-canvas); border: 1px solid var(--border-subtle); } .ips-regracad-modo--editando { color: var(--accent); } .ips-regracad-modo--novo { color: var(--gold); } .ips-regracad-novo { display: flex; flex-direction: column; gap: var(--space-3); padding-bottom: var(--space-4); margin-bottom: var(--space-4); border-bottom: 1px solid var(--border-subtle); } .ips-regracad-novo .modal-field { flex: 1; min-width: 220px; } .ips-regracad-novo__empresa-row { display: flex; align-items: flex-end; gap: var(--space-3); flex-wrap: wrap; } /* Nome da empresa resolvido no Questor (ver empresas_questor.py), exibido ao lado do campo "Código da empresa" — os três estados (buscando/ encontrado/não encontrado) só diferem na cor do texto. */ .ips-regracad-novo__empresa-nome { margin: 0 0 10px; font-size: 0.88rem; color: var(--text-secondary); flex: 1; min-width: 220px; } .ips-regracad-novo__empresa-nome--buscando { color: var(--text-muted); } .ips-regracad-novo__empresa-nome--nao-encontrada { color: var(--text-muted); font-style: italic; } /* Resumo só-leitura da regra resolvida em "Nova Importação" — nenhum campo editável aqui, só texto explicando o que a regra cadastrada configura. */ .ips-imp-resumo { margin: var(--space-4) 0; padding: var(--space-3) var(--space-4); border-radius: var(--radius-sm); background: var(--bg-canvas); border: 1px solid var(--border-subtle); display: flex; flex-direction: column; gap: var(--space-2); } .ips-imp-resumo__tipos { margin: 0; font-size: 0.78rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); } .ips-imp-resumo__linha { margin: 0; font-size: 0.85rem; color: var(--text-secondary); } .ips-imp-resumo__obs { margin: 0; font-size: 0.82rem; color: var(--text-muted); white-space: pre-wrap; } .ips-vincular-resumo { font-size: 0.85rem; color: var(--text-secondary); margin-bottom: var(--space-3); }