portal_publico/static/css/importacao-plano-saude.css
2026-08-18 16:35:55 -03:00

615 lines
14 KiB
CSS

.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;
}
.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);
}
/* 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);
}
.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);
}
/* Regra de custeio salva — fica no início do modal, antes até de "Operadora"
(decisão explícita do usuário: aplicar uma regra já preenche a operadora
junto, então escolher a regra é o primeiro passo natural do fluxo, não um
apêndice no final). Por vir antes de tudo, a borda de separação fica
embaixo (não em cima), pra separar do campo "Operadora" logo abaixo. */
.ips-regra-field {
margin-bottom: var(--space-5);
padding-bottom: var(--space-5);
border-bottom: 1px solid var(--border-subtle);
}
.ips-regra-actions {
display: flex;
gap: var(--space-2);
flex-wrap: wrap;
}
.ips-regra-actions button,
.ips-regra-actions label {
display: inline-flex;
align-items: center;
gap: var(--space-2);
}
.ips-regra-actions__hint {
font-size: 0.78rem;
color: var(--text-muted);
margin: 0;
}
/* Combobox pesquisável de "Regra de custeio salva" — o <input> já herda o
estilo padrão de .modal-field input (components.css); aqui só cuida do
posicionamento (ocupa o espaço do antigo <select>) e da lista flutuante
de resultados filtrados. */
.ips-regra-combo {
position: relative;
flex: 1;
min-width: 220px;
}
.ips-regra-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-regra-combo__item {
padding: var(--space-2) var(--space-3);
font-size: 0.88rem;
cursor: pointer;
color: var(--text-primary);
}
.ips-regra-combo__item:hover {
background: var(--accent);
color: var(--accent-contrast);
}
.ips-regra-combo__empty {
padding: var(--space-2) var(--space-3);
font-size: 0.85rem;
color: var(--text-muted);
}
.ips-regra-observacoes {
margin: var(--space-2) 0 0;
padding: var(--space-2) var(--space-3);
border-radius: var(--radius-sm);
background: var(--bg-canvas);
border: 1px solid var(--border-subtle);
font-size: 0.82rem;
color: var(--text-muted);
white-space: pre-wrap;
}
/* "Salvar regra atual..." fica no final do formulário (não mais junto de
Aplicar/Limpar/Ver regras salvas no topo) — salvar só faz sentido depois
de parametrizar o custeio abaixo, é o último passo do fluxo de
parametrização de uma regra nova. */
.ips-regra-salvar-field {
margin-top: var(--space-5);
padding-top: var(--space-5);
border-top: 1px solid var(--border-subtle);
}
/* Lista de regras salvas (#ips-regras-modal) — 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);
}
/* 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 <colgroup> (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 <td> 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);
}
.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` + <colgroup> (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 <input> 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);
}
.ips-vincular-resumo {
font-size: 0.85rem;
color: var(--text-secondary);
margin-bottom: var(--space-3);
}