1235 lines
32 KiB
CSS
1235 lines
32 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-title-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--space-2);
|
|
}
|
|
|
|
.ips-header-actions {
|
|
display: flex;
|
|
gap: var(--space-3);
|
|
}
|
|
|
|
.ips-subtitle {
|
|
font-size: 0.85rem;
|
|
color: var(--text-muted);
|
|
margin-top: 2px;
|
|
}
|
|
|
|
/* "Revisão <código - nome da empresa>" — 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 <th> 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);
|
|
}
|
|
|
|
/* Botão "borracha" no fim do cabeçalho do histórico — limpa de uma vez todos
|
|
os filtros por coluna (ver criarFiltroColuna) e volta a ordenação pro
|
|
padrão (mais recente primeiro). Reaproveita o mesmo visual de botão de
|
|
ícone do funil (.ips-col-filter__btn), só um pouco maior por ficar sozinho
|
|
na célula, sem texto ao lado. */
|
|
.ips-list-reset-btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 22px;
|
|
height: 22px;
|
|
padding: 0;
|
|
border: none;
|
|
background: none;
|
|
color: var(--text-muted);
|
|
cursor: pointer;
|
|
border-radius: var(--radius-sm);
|
|
}
|
|
|
|
.ips-list-reset-btn:hover {
|
|
color: var(--text-primary);
|
|
background: var(--bg-canvas);
|
|
}
|
|
|
|
.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;
|
|
flex-wrap: wrap;
|
|
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);
|
|
}
|
|
|
|
/* Lista de arquivos anexados em "2. Arquivo da operadora" — várias
|
|
operadoras (ex.: Unimed em PDF) mandam mensalidade e coparticipação em
|
|
arquivos separados, então o campo aceita 1+ arquivos. Cada item tem seu
|
|
próprio status de validação (mesmas cores de .ips-file-field__status
|
|
acima) e um botão de remover individual. */
|
|
.ips-arquivo-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-2);
|
|
margin-top: var(--space-3);
|
|
}
|
|
|
|
.ips-arquivo-list__item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--space-3);
|
|
padding: var(--space-2) var(--space-3);
|
|
border-radius: var(--radius-sm);
|
|
background: var(--bg-canvas);
|
|
border: 1px solid var(--border-subtle);
|
|
}
|
|
|
|
.ips-arquivo-list__info {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
.ips-arquivo-list__name {
|
|
display: block;
|
|
font-size: 0.85rem;
|
|
color: var(--text-primary);
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.ips-arquivo-list__status {
|
|
display: block;
|
|
font-size: 0.78rem;
|
|
margin-top: 2px;
|
|
}
|
|
|
|
.ips-arquivo-list__status--pendente {
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.ips-arquivo-list__status--ok {
|
|
color: #2f9e6e;
|
|
}
|
|
|
|
.ips-arquivo-list__status--erro {
|
|
color: var(--danger);
|
|
}
|
|
|
|
.ips-arquivo-list__remove {
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* "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 <input> já herda o estilo padrão de .modal-field input
|
|
(components.css); aqui só cuida do posicionamento (ocupa o espaço de um
|
|
<select>) e da lista flutuante de resultados filtrados. */
|
|
.ips-combo {
|
|
position: relative;
|
|
flex: 1;
|
|
min-width: 220px;
|
|
}
|
|
|
|
/* Espaço reservado pros dois botões embutidos (.ips-combo__clear e
|
|
.ips-combo__toggle abaixo) — mesmo padrão de .modal-field select
|
|
(components.css), que já reserva espaço pra seta customizada do lado
|
|
direito. */
|
|
.ips-combo__input {
|
|
padding-right: 56px !important;
|
|
}
|
|
|
|
.ips-combo__clear,
|
|
.ips-combo__toggle {
|
|
position: absolute;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 22px;
|
|
height: 22px;
|
|
border: none;
|
|
background: none;
|
|
color: var(--text-muted);
|
|
cursor: pointer;
|
|
z-index: 1;
|
|
}
|
|
|
|
/* "x" pra limpar (só aparece com algo selecionado/digitado) fica mais
|
|
perto do texto; a seta "ver todos" (.ips-combo__toggle abaixo, sempre
|
|
visível) fica na borda — mesma posição de uma seta de <select> 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;
|
|
overscroll-behavior: contain;
|
|
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);
|
|
}
|
|
|
|
/* Resumo da regra aplicada + observações na tela de Revisão — só leitura,
|
|
mesma linguagem visual de .ips-imp-resumo (formulário de nova
|
|
importação, cujas classes __tipos/__linha são reaproveitadas aqui dentro),
|
|
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);
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-2);
|
|
}
|
|
|
|
.ips-regra-empresa-observacoes__label {
|
|
margin: 0;
|
|
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;
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
|
|
/* Agrupa "Limite de desconto do empregado" visualmente separado dos dois
|
|
campos do lado da empresa acima (linha divisória) — são mutuamente
|
|
exclusivos (ver atualizarExclusividadeRegraEspecifica(), JS), então o
|
|
divisor reforça que são dois "modos" alternativos, não um conjunto só. */
|
|
.ips-regra-especifica__alt {
|
|
margin-top: var(--space-3);
|
|
padding-top: var(--space-3);
|
|
border-top: 1px solid var(--border-subtle);
|
|
}
|
|
|
|
.ips-regra-especifica input:disabled {
|
|
opacity: 0.45;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
/* 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);
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
/* 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 `width` inline no <th> (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);
|
|
}
|
|
|
|
/* 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:vertical` (só altura, não largura — pedido explícito do usuário)
|
|
exige overflow != visible pra mostrar a alça de redimensionar no canto
|
|
inferior direito — o usuário arrasta só pra baixo, pra ver mais linhas de
|
|
uma vez, até 80vh. Largura já rola sozinha via overflow-x (abaixo), não
|
|
precisa de alça própria. */
|
|
resize: vertical;
|
|
overflow-y: auto;
|
|
overscroll-behavior: contain;
|
|
/* .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;
|
|
}
|
|
|
|
/* Usada só pela aba "Alterações" (panelHtmlAlteracoes, JS) — um <table>
|
|
de verdade, sem coluna redimensionável. As tabelas de Mensalidade/
|
|
Coparticipação/Auditoria usam CSS Grid (.ips-grid, mais abaixo), não
|
|
<table> — ver a nota grande em wireColumnResize() no JS pro motivo. */
|
|
.ips-table-scroll .pa-table {
|
|
width: auto;
|
|
table-layout: fixed;
|
|
}
|
|
|
|
.ips-table-scroll .pa-table th,
|
|
.ips-table-scroll .pa-table td {
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
/* Tabela de Mensalidade/Coparticipação/Auditoria (panelHtmlParaTipo/
|
|
panelHtmlAuditoria, JS) — CSS Grid em vez de <table>/<colgroup>/<col>,
|
|
trocado depois de confirmar ao vivo com o usuário que o navegador dele
|
|
simplesmente não reflui a largura de <table> desta tela depois do
|
|
primeiro layout (testado de várias formas, inclusive mexendo direto no
|
|
DOM pelo Console, fora do código da aplicação — só uma tabela HTML nova
|
|
e pequena com as mesmas classes refluía normalmente). `grid-template-
|
|
columns` no container é o único lugar que define a largura de cada
|
|
coluna — cada `.ips-grid-row` é `display:contents` (marcação semântica
|
|
de linha, `role="row"`, sem caixa própria) só pra suas células
|
|
participarem direto do grid do `.ips-grid` ancestral; é assim que uma
|
|
única declaração de `grid-template-columns` vale pra cabeçalho e corpo
|
|
ao mesmo tempo, como as colunas de um <table> normal. */
|
|
.ips-grid {
|
|
display: grid;
|
|
width: max-content;
|
|
min-width: 100%;
|
|
}
|
|
|
|
.ips-grid-row {
|
|
display: contents;
|
|
}
|
|
|
|
.ips-grid-cell {
|
|
padding: var(--space-3) var(--space-4);
|
|
border-bottom: 1px solid var(--border-subtle);
|
|
font-size: 0.88rem;
|
|
color: var(--text-primary);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
transition: background var(--transition-fast);
|
|
}
|
|
|
|
/* Colunas de valor (Valor Empresa/Valor, total do rodapé e Valor da
|
|
Auditoria — classe posta pelo JS): algarismos de largura fixa, pra que os
|
|
valores fiquem alinhados entre linhas. */
|
|
.ips-grid-cell--valor,
|
|
.ips-grid-cell--valor .ips-table-input {
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
.ips-grid-row:last-child .ips-grid-cell {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.ips-grid-row:hover .ips-grid-cell {
|
|
background: var(--card-bg-hover);
|
|
}
|
|
|
|
.ips-grid-cell--head {
|
|
position: relative;
|
|
text-align: left;
|
|
font-size: 0.72rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
color: var(--text-muted);
|
|
background: var(--bg-surface-raised);
|
|
}
|
|
|
|
/* Coluna de ações (ícone fixo) fica presa na primeira posição mesmo
|
|
rolando a tabela horizontalmente — mesmo espírito de
|
|
.pa-table th/td.ips-table-actions (ver mais abaixo), só que via grid. */
|
|
.ips-grid-cell.ips-table-actions {
|
|
position: sticky;
|
|
left: 0;
|
|
z-index: 1;
|
|
text-align: center;
|
|
background: var(--bg-surface);
|
|
}
|
|
|
|
.ips-grid-cell--head.ips-table-actions {
|
|
background: var(--bg-surface-raised);
|
|
}
|
|
|
|
.pa-empty-row .ips-grid-cell {
|
|
text-align: center;
|
|
color: var(--text-muted);
|
|
padding: var(--space-6);
|
|
}
|
|
|
|
/* Linha de total (Valor Empresa/Valor) no rodapé de Mensalidade/Coparticipação
|
|
— mesmo fundo do cabeçalho (.ips-grid-cell--head), pra ler como um resumo
|
|
fixo, não mais uma linha de dado igual às demais. `position:sticky;
|
|
bottom:0` (pedido explícito do usuário) gruda a linha no fim da área
|
|
visível de `.ips-table-scroll` (o ancestral com overflow-y:auto/scroll) —
|
|
fica sempre à vista rolando a tabela pra cima/baixo, e continua funcionando
|
|
igual com a tabela expandida (`wireAutoExpandScroll()`, JS), já que sticky
|
|
é recalculado contra o tamanho atual do container, não um valor fixo.
|
|
z-index maior que o da coluna de ações comum (1) garante que a linha de
|
|
total fique por cima das linhas de dado ao rolar por trás dela. */
|
|
.ips-grid-row--totais .ips-grid-cell {
|
|
position: sticky;
|
|
bottom: 0;
|
|
z-index: 2;
|
|
font-weight: 700;
|
|
color: var(--text-primary);
|
|
background: var(--bg-surface-raised);
|
|
border-top: 1px solid var(--border-subtle);
|
|
}
|
|
|
|
.ips-grid-row--totais .ips-grid-cell.ips-table-actions {
|
|
background: var(--bg-surface-raised);
|
|
}
|
|
|
|
/* 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;
|
|
/* Fica encostada na borda interna da própria coluna (não a cavalo da
|
|
borda, "right: -3px" antigo) porque o `th`/`td` desta tabela tem
|
|
`overflow: hidden` (pro text-overflow:ellipsis do cabeçalho) — qualquer
|
|
parte da alça que ultrapassasse a borda do `th` (containing block dela,
|
|
por causa do `position: relative`) era cortada pelo próprio overflow,
|
|
sobrando só ~3px clicáveis de fato e tornando o arraste praticamente
|
|
impossível de acertar. Bug real reportado pelo usuário. */
|
|
right: 0;
|
|
bottom: 0;
|
|
width: 8px;
|
|
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;
|
|
}
|
|
|
|
/* Linha-guia mostrada durante o arrasto (wireColumnResize, JS) — a coluna
|
|
em si só é redimensionada de fato ao soltar (renderPanels() reconstrói a
|
|
tabela com a largura nova), então esta linha é o único feedback visual
|
|
em tempo real do arraste. position:fixed pra acompanhar o cursor
|
|
independente do scroll horizontal da tabela. */
|
|
.ips-col-resize-guide {
|
|
position: fixed;
|
|
width: 2px;
|
|
background: var(--accent);
|
|
z-index: 200;
|
|
pointer-events: 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);
|
|
}
|
|
|
|
/* Vínculo automático de nome (DE/PARA reaplicado — ver "Vínculos de nome
|
|
salvos" no CLAUDE.md): usa --accent, mesmo tom já usado em outras marcas
|
|
de "ajuste reaplicado automaticamente" (ex.: honorário ajustado
|
|
manualmente em Indicador de Desempenho). */
|
|
.ips-alteracao-tipo--vinculo_automatico {
|
|
color: var(--accent);
|
|
background: rgba(var(--accent-rgb), 0.16);
|
|
}
|
|
|
|
.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;
|
|
overscroll-behavior: contain;
|
|
}
|
|
|
|
/* #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;
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
.ips-vincular-resumo {
|
|
font-size: 0.85rem;
|
|
color: var(--text-secondary);
|
|
margin-bottom: var(--space-3);
|
|
}
|
|
|
|
/* Linha do histórico sendo aberta (clique já registrado, Revisão ainda
|
|
carregando) — ver listBody "click" no JS, que ignora novos cliques até
|
|
terminar. */
|
|
#ips-list-body tr.ips-list-row--carregando td {
|
|
opacity: 0.55;
|
|
cursor: progress;
|
|
}
|