/* components.css : botao, card, tabela, filtro, form, SelectBusca, modal,
 * toggle, upload, loading, badge, estado vazio, KPI, abas, selecao em lote.
 *
 * Toda medida, cor e raio vem de token. Valor solto aqui e o comeco do fim:
 * a proxima tela copia o valor solto e ninguem mais sabe qual e o padrao.
 */

/* ---------------------------------------------------------------- botao */

.btn, .btn-primary, .btn-secundario, .btn-perigo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: var(--campo-h);
  padding: 0 var(--sp-4);
  border-radius: var(--raio-sm);
  border: 1px solid var(--borda);
  background: var(--surface);
  color: var(--text);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
}

.btn:hover, .btn-secundario:hover { background: var(--surface-2); text-decoration: none; }

.btn-primary {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--primary-foreground);
  font-weight: 600;
}
.btn-primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); }

.btn-perigo {
  background: var(--danger-text);
  border-color: var(--danger-text);
  color: #FFFFFF;
  font-weight: 600;
}

/* Botao dourado leva letra escura. Dourado com letra branca da 2.29:1 e reprova
   o piso de 4.5:1: o rotulo fica ilegivel. */
.btn-marca {
  background: var(--dourado);
  border-color: var(--dourado-hover);
  color: var(--text);
  font-weight: 600;
}
.btn-marca:hover { background: var(--dourado-hover); }

.btn-sm { height: 32px; padding: 0 var(--sp-3); font-size: 12.5px; }
.btn:disabled, .btn-primary:disabled { opacity: .5; cursor: not-allowed; }

.btn-icone {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px;
  border: 0; background: transparent; border-radius: var(--raio-sm);
  color: var(--text-dim); cursor: pointer;
}
.btn-icone:hover { background: var(--surface-2); color: var(--text); }
.btn-icone.perigo:hover { background: var(--danger-bg); color: var(--danger-text); }

/* Acao sem permissao ESMAECE e continua ocupando o slot. Sumir com o slot
   desalinha a coluna e faz a linha parecer diferente das outras. */
.btn-icone.desabilitado { opacity: .30; cursor: not-allowed; }

/* ---------------------------------------------------------------- card */

.card {
  background: var(--surface);
  border: 1px solid var(--borda);
  border-radius: var(--raio);
  padding: var(--sp-4);
  /* boxes irmaos numa grid tem a MESMA altura */
  height: 100%;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* Hover mexe em borda, sombra e posicao. NUNCA em background: trocar o fundo no
   hover polui a tela inteira quando ha varios cards. */
.card.clicavel:hover {
  border-color: var(--dourado);
  box-shadow: var(--sombra-md);
  transform: translateY(-1px);
}

.card-titulo {
  font-family: var(--font-titulo);
  font-weight: 700;
  font-size: var(--fs-lg);
  margin-bottom: var(--sp-3);
}

.card-sub { font-size: 12.5px; color: var(--text-dim); }
.card-sub-em-bege { font-size: 12.5px; color: var(--text-dim-on-surface2); }

/* ---------------------------------------------------------------- KPI */

.mg-kpi {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--borda);
  border-radius: var(--raio);
  padding: var(--sp-4) var(--sp-3) var(--sp-3);
  overflow: hidden;
  height: 100%;
}

/* A faixa de 3px no topo e a assinatura do padrao de KPI. Nao desenhar outra
   barra na base do card: colide com ela. */
.mg-kpi::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: var(--cor-primaria);
}
/* A cor da faixa vem de TOKEN, e nao de hex solto: era o unico lugar do CSS que
   ainda carregava hex de estado a mao, e hex solto e como a proxima tela copia o
   valor sem saber qual e o padrao. */
.mg-kpi.ac-fat::before { background: linear-gradient(90deg, var(--success), var(--success-text)); }
.mg-kpi.ac-alerta::before { background: linear-gradient(90deg, var(--warning), var(--warning-text)); }
.mg-kpi.ac-risco::before { background: linear-gradient(90deg, var(--danger), var(--danger-text)); }
.mg-kpi.ac-marca::before { background: linear-gradient(90deg, var(--dourado-2), var(--dourado)); }
.mg-kpi.ac-info::before { background: linear-gradient(90deg, var(--info), var(--info-text)); }

/* O icone do KPI: 44x44, fundo pastel, e `flex-shrink: 0` para nao encolher
   quando o valor e longo. */
.mg-kpi { display: flex; align-items: center; gap: var(--sp-3); }
.mg-kpi .ico {
  width: 44px; height: 44px;
  border-radius: var(--raio-sm);
  display: grid; place-items: center;
  font-size: 22px;
  flex-shrink: 0;
  background: var(--muted);
  color: var(--text-dim);
}
.mg-kpi.ac-fat .ico { background: var(--success-bg); color: var(--success-text); }
.mg-kpi.ac-alerta .ico { background: var(--warning-bg); color: var(--warning-text); }
.mg-kpi.ac-risco .ico { background: var(--danger-bg); color: var(--danger-text); }
.mg-kpi.ac-info .ico { background: var(--info-bg); color: var(--info-text); }
.mg-kpi.ac-marca .ico { background: var(--dourado-soft); color: var(--dourado-3); }
.mg-kpi .corpo { min-width: 0; flex: 1; display: flex; flex-direction: column; }

@media (max-width: 720px) {
  .mg-kpi .ico { width: 36px; height: 36px; font-size: 18px; }
  .mg-kpi .val { font-size: 22px; }
}

.mg-kpi .lbl {
  min-height: 25px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-dim);
}

.mg-kpi .val {
  font-family: var(--font-titulo);
  font-weight: 700;
  font-size: 28px;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

/* min-height mesmo vazia: sem isso os cards da linha ficam com alturas
   diferentes quando um tem descricao e o outro nao. */
.mg-kpi .disc { min-height: 14px; font-size: 11.5px; color: var(--text-dim); }
.mg-kpi .disc.pos { color: var(--success-text); }
.mg-kpi .disc.neg { color: var(--danger-text); }

/* ---------------------------------------------------------------- tabela */

.tabela-wrap {
  background: var(--surface);
  border: 1px solid var(--borda);
  border-radius: var(--raio);
  /* SEM overflow:hidden. Com ele, o popup do menu sanduiche e cortado e metade
     dos itens fica sem clique. */
}

.tabela-topo {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--borda);
}

.tabela-topo .titulo {
  font-family: var(--font-titulo);
  font-weight: 700;
  font-size: var(--fs-lg);
  grid-column: 1;
}
.tabela-topo .contagem {
  grid-column: 2;
  justify-self: end;
  font-size: 12px;
  color: var(--text-dim);
}
.tabela-topo .menu-area { grid-column: 3; justify-self: end; position: relative; }

.tabela-scroll { overflow-x: auto; border-radius: 0 0 12px 12px; }

.tabela { width: 100%; border-collapse: collapse; }

.tabela th {
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-dim);
  text-align: left;
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--borda);
  white-space: nowrap;
}

.tabela td {
  font-size: 14px;
  padding: 10px var(--sp-3);
  border-bottom: 1px solid var(--border-2);
  color: var(--text-soft);
}

.tabela tbody tr:hover td { background: var(--surface-2); }
.tabela td.num, .tabela th.num { text-align: right; font-variant-numeric: tabular-nums; }

.celula-acoes {
  display: inline-flex;
  gap: 4px;
  align-items: center;
  justify-content: flex-end;
}

.tabela-rodape {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--borda);
  font-size: 12.5px; color: var(--text-dim);
}
.tabela-rodape .paginacao { margin-left: auto; display: flex; gap: 4px; }

/* linha de filtro por coluna, dentro do thead */
.filtro-coluna {
  width: 100%;
  height: 30px;
  padding: 0 8px;
  font-size: 12.5px;
  border: 1px solid var(--border-input);
  border-radius: var(--raio-sm);
  background: var(--surface);
  color: var(--text);
}
.filtro-coluna::placeholder { color: var(--text-placeholder); }

/* menu sanduiche da tabela */
.menu-tabela {
  position: absolute; right: 0; top: 36px; z-index: 30;
  min-width: 210px;
  background: var(--surface);
  border: 1px solid var(--borda);
  border-radius: var(--raio-sm);
  box-shadow: var(--sombra-md);
  padding: 6px;
}
.menu-tabela[hidden] { display: none; }
.menu-tabela button {
  display: flex; align-items: center; gap: var(--sp-2);
  width: 100%; height: 32px; padding: 0 var(--sp-2);
  border: 0; background: transparent; border-radius: var(--raio-sm);
  font-size: 13px; color: var(--text); cursor: pointer; text-align: left;
}
.menu-tabela button:hover { background: var(--surface-2); }
.menu-tabela .separador { height: 1px; background: var(--borda); margin: 4px 0; }

/* ------------------------------------------------------- selecao em lote */

/* Duas semanticas, um visual. `.tsel` marca LINHA para acao em lote; `.chk` e
   caixa de formulario que so grava no Salvar (a matriz de permissoes). Nenhuma
   das duas e toggle: toggle grava na hora, caixa espera o botao. */
.tsel, .chk {
  appearance: none;
  -webkit-appearance: none;
  width: 18px; height: 18px;
  border: 1px solid var(--border-input);
  border-radius: var(--raio-xs);
  background: var(--surface);
  cursor: pointer;
  position: relative;
  vertical-align: middle;
}
.tsel:checked, .chk:checked { background: var(--cor-primaria); border-color: var(--cor-primaria); }
.tsel:checked::after, .chk:checked::after {
  content: ""; position: absolute; left: 5px; top: 2px;
  width: 5px; height: 9px;
  border: solid #FFFFFF; border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.tsel:indeterminate, .chk:indeterminate { background: var(--cor-primaria); border-color: var(--cor-primaria); }
.tsel:indeterminate::after, .chk:indeterminate::after {
  content: ""; position: absolute; left: 3px; top: 7px;
  width: 10px; height: 2px; background: #FFFFFF; transform: none; border: 0;
}
.chk:disabled { opacity: .40; cursor: not-allowed; }

.tsel-bar {
  position: fixed;
  bottom: 0;
  left: var(--sidebar-width);
  right: 0;
  background: var(--barra-lote);
  color: #FFFFFF;
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-5);
  z-index: 40;
}
.tsel-bar[hidden] { display: none; }
.tsel-bar .acoes { margin-left: auto; display: flex; gap: var(--sp-2); }
.tsel-bar .btn { background: transparent; color: #FFFFFF; border-color: rgba(255,255,255,.35); }

/* ------------------------------------------------------- barra de filtros */

.fu-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--borda);
  border-radius: var(--raio);
  padding: var(--sp-3) var(--sp-4);
}

.fu-campo { display: flex; flex-direction: column; gap: 4px; min-width: 0; }

.fu-lbl {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-dim);
}

.fu-bar .input, .fu-bar .sb-control, .fu-bar .btn, .fu-bar .btn-primary {
  height: var(--fu-h);
}
.fu-bar .fu-acao { margin-left: auto; display: flex; align-items: flex-end; gap: var(--sp-2); }

/* Presets de periodo: a fileira de mini-botoes. Sem a altura no WRAPPER ela
   engorda mais que os inputs e desalinha a barra inteira. */
.fu-presets {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: var(--fu-h);
  padding: 3px;
  border: 1px solid var(--borda);
  border-radius: var(--raio-sm);
  background: var(--surface);
}
.fu-presets button {
  height: calc(var(--fu-h) - 8px);
  border: 1px solid transparent;
  background: var(--surface);
  border-radius: var(--raio-xs);
  padding: 0 10px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-dim);
  cursor: pointer;
  white-space: nowrap;
}
.fu-presets button:hover { color: var(--cor-primaria); }
.fu-presets button.on {
  border-color: var(--cor-primaria);
  background: var(--cor-primaria-suave);
  color: var(--cor-primaria-escura);
}
/* Os campos De/Ate so aparecem no customizado: fora dele, o seletor ja resolveu. */
.fu-datas { display: none; gap: var(--sp-3); align-items: flex-end; }
.fu-datas.aberto { display: flex; }

@media (max-width: 720px) {
  .fu-bar .fu-campo { flex: 1 1 100%; }
  .fu-presets { flex-wrap: wrap; height: auto; }
}

/* -------------------------------------------------------------- formulario */

.ra-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  /* flex-end e nao center: o botao alinha pela BASE do input, senao ele flutua
     no meio quando o campo tem label acima. */
  align-items: flex-end;
}

.campo { display: flex; flex-direction: column; gap: 4px; min-width: 0; }

.campo label {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  /* SEM uppercase e SEM letter-spacing: uppercase com peso 800 e cara de
     sistema legado. Uppercase so em cabecalho categorial. */
}

.input, .textarea {
  height: var(--campo-h);
  padding: 0 var(--sp-3);
  font-size: 14px;
  border: 1px solid var(--border-input);
  border-radius: var(--raio-sm);
  background: var(--surface);
  color: var(--text);
  min-width: 0;
}
.textarea { height: auto; min-height: 84px; padding: var(--sp-2) var(--sp-3); resize: vertical; }
.input::placeholder, .textarea::placeholder { color: var(--text-placeholder); }
.input:disabled { background: var(--muted); color: var(--muted-text); }

.ra-bar .input { min-width: 240px; }
.ra-bar .sb-control { min-width: 170px; }

/* O botao de acao do form recebe um label vazio para alinhar pela base junto
   com os campos que tem label. */
.campo.ra-acao label { visibility: hidden; }
.ra-bar .ra-acao { margin-left: auto; }

/* O campo PRINCIPAL da barra estica e ocupa o que sobra; os demais ficam no
   min-width. A nota do padrao escreve isso como `style="flex:1"` no elemento, e
   aqui vira classe: este projeto prova por grep que nenhum template carrega
   atributo style, e a regra do sistema de estilos vence o exemplo da nota. */
.ra-bar .campo-principal { flex: 1; }

.campo-erro .input, .campo-erro .sb-control { border-color: var(--danger-text); }
.msg-erro { font-size: 12px; color: var(--danger-text); }

/* Aviso de validacao, DENTRO do modal e no topo do corpo. Nao e popup em cima
   do modal: modal sobre modal perde o foco e a pessoa nao sabe mais onde esta. */
.modal-aviso {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-3);
  border: 1px solid var(--danger-border);
  background: var(--danger-bg);
  color: var(--danger-text);
  border-radius: var(--raio-sm);
  font-size: 13px;
}
.modal-aviso[hidden] { display: none; }
.modal-aviso .titulo { font-weight: 600; }
.modal-aviso ul { margin: 0; padding-left: 18px; }
.modal-aviso li { line-height: 1.5; }
/* A saida vai escrita: a pessoa decide se arruma ou se descarta no Cancelar. */
.modal-aviso .saida { font-size: 12.5px; opacity: .9; }

/* Ressalva nao e erro: o registro entrou, e ficou marcado. Cor de aviso, e nao
   de perigo, senao a pessoa procura o que corrigir num formulario que ja foi
   gravado. */
.modal-aviso.ressalva {
  border-color: var(--warning-border);
  background: var(--warning-bg);
  color: var(--warning-text);
}

.form-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-3); }
.form-grid .col-cheia { grid-column: 1 / -1; }
@media (max-width: 720px) { .form-grid { grid-template-columns: 1fr; } }

/* ------------------------------------------------------------ SelectBusca */

.selectbusca { position: relative; min-width: 0; }

.sb-control {
  display: flex; align-items: center; gap: var(--sp-2);
  height: var(--campo-h);
  padding: 0 var(--sp-3);
  border: 1px solid var(--border-input);
  border-radius: var(--raio-sm);
  background: var(--surface);
  cursor: pointer;
  font-size: 14px;
}
.sb-display { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sb-display.vazio { color: var(--text-placeholder); }

.sb-popup {
  /* left:0 sozinho, sem right:0: o popup pode crescer MAIS largo que o campo
     estreito que o abriu. Com left+right presos, a lista herdava a largura do
     controle (que numa .fu-bar nao tem min-width) e o texto da opcao quebrava
     em duas ou tres linhas -- feio, e some com o alinhamento da lista. */
  position: absolute; z-index: 70; left: 0; top: calc(100% + 4px);
  min-width: 100%;
  width: max-content;
  max-width: min(320px, 90vw);
  background: var(--surface);
  border: 1px solid var(--borda);
  border-radius: var(--raio-sm);
  box-shadow: var(--sombra-md);
  padding: 6px;
}
.sb-popup[hidden] { display: none; }
.sb-search {
  width: 100%; height: 32px; padding: 0 var(--sp-2);
  border: 1px solid var(--border-input); border-radius: var(--raio-sm);
  font-size: 13px; margin-bottom: 4px;
}
.sb-panel { max-height: 240px; overflow-y: auto; }
.sb-opt {
  padding: 7px var(--sp-2); border-radius: var(--raio-sm);
  font-size: 13.5px; cursor: pointer;
  /* nunca quebra: opcao longa corta com reticencias em vez de virar 2-3 linhas */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sb-opt:hover, .sb-opt.foco { background: var(--surface-2); }
.sb-opt.marcada { background: var(--cor-primaria-suave); color: var(--cor-primaria-escura); font-weight: 600; }
.sb-vazio { padding: var(--sp-3); font-size: 13px; color: var(--text-dim); text-align: center; }

/* Dentro de dialog, o popup precisa ser absoluto e o dialog precisa deixar
   vazar, senao a lista e cortada pela borda do modal. */
.sb-popup.sb-in-dialog { position: absolute; }

/* ---------------------------------------------------------------- modal */

.modal-bg {
  position: fixed; inset: 0; z-index: 80;
  background: rgba(26, 26, 26, .45);
  /* blur leve tira o foco do que ficou atras, sem apagar o contexto */
  backdrop-filter: blur(2px);
  display: grid; place-items: center;
  padding: var(--sp-4);
}
.modal-bg[hidden] { display: none; }

.modal-caixa {
  background: var(--surface);
  border-radius: var(--raio);
  box-shadow: var(--sombra-md);
  display: flex; flex-direction: column;
  overflow: hidden;
  animation: modalSobe .2s ease;
}
@keyframes modalSobe {
  from { opacity: 0; transform: translateY(-12px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Tamanho em vw e vh, nunca em px: o modal tem que acompanhar a tela. */
.modal-caixa.modal-sm { width: 34vw; max-height: 42vh; }
.modal-caixa.modal-md { width: 55vw; max-height: 70vh; }
.modal-caixa.modal-lg { width: 89vw; max-height: 90vh; }

/* Notebook: o medio abre para 68vw. Sem esta faixa, 55vw num 1366 da 751px de
   modal com formulario de duas colunas dentro, e os campos ficam estreitos
   demais bem na resolucao mais comum do escritorio. */
@media (max-width: 1280px) {
  .modal-caixa.modal-md { width: 68vw; }
}
@media (max-width: 880px) {
  .modal-caixa.modal-sm, .modal-caixa.modal-md, .modal-caixa.modal-lg {
    width: 96vw; max-height: 92vh;
  }
}

/* Fallback: caixa sem tamanho declarado vira media, que e o default seguro. */
.modal-caixa:not(.modal-sm):not(.modal-md):not(.modal-lg) { width: 55vw; max-height: 70vh; }

/* Variante CONFIRM: acao destrutiva. Texto centrado, icone redondo, e o rodape
   centraliza em vez de encostar a direita. */
.modal-caixa.modal-confirm { text-align: center; }
.modal-confirm .modal-corpo { padding: var(--sp-6) var(--sp-5) var(--sp-3); }
.modal-confirm .modal-rodape { justify-content: center; }
.confirm-icone {
  width: 68px; height: 68px;
  border-radius: var(--raio-full);
  display: grid; place-items: center;
  margin: 0 auto var(--sp-4);
}
.confirm-icone .icon { font-size: 36px; }
.confirm-icone.perigo { background: var(--danger-bg); color: var(--danger-text); }
.confirm-icone.aviso  { background: var(--warning-bg); color: var(--warning-text); }
.confirm-titulo { font-family: var(--font-titulo); font-weight: 700; font-size: 18px; margin: 0 0 6px; }
.confirm-texto { font-size: 14px; color: var(--text-dim); line-height: 1.5; margin: 0; }

.modal-topo {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4);
  border-bottom: 1px solid var(--borda);
}
.modal-topo .titulo {
  font-family: var(--font-titulo); font-weight: 700; font-size: var(--fs-lg);
}
.modal-topo .btn-fechar { margin-left: auto; }
.modal-corpo { padding: var(--sp-4); overflow-y: auto; flex: 1; }
.modal-rodape {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--borda);
  justify-content: flex-end;
}
.modal-rodape .msg { margin-right: auto; font-size: 12.5px; }

/* variante com dialog nativo, obrigatoria quando o modal contem SelectBusca */
dialog.popup-centrado {
  border: 0; padding: 0; background: transparent;
  overflow: visible !important;   /* CRITICO: sem isso o SelectBusca corta */
  max-width: 96vw; max-height: 96vh;
}
dialog.popup-centrado::backdrop { background: rgba(0, 0, 0, .4); backdrop-filter: blur(2px); }

/* A nota fala do overflow do <dialog>, e o recorte tem TRES camadas: o dialog,
   a caixa e o corpo rolavel. Liberar so a de fora nao resolve, porque quem
   corta a lista e a caixa logo abaixo. Consequencia assumida: modal com
   SelectBusca nasce CURTO. Se um dia precisar rolar, o campo de escolha sai do
   modal, e nao o overflow volta. */
dialog.popup-centrado .modal-caixa,
dialog.popup-centrado .modal-corpo { overflow: visible; }
dialog.popup-centrado .modal-caixa { max-height: none; }

/* ---------------------------------------------------------------- toggle */

.cv-sw { position: relative; display: inline-block; width: 42px; height: 24px; vertical-align: middle; }

/* ESTA linha e a que impede a caixinha nativa do navegador de aparecer. Sem
   ela, o interruptor desenhado nunca aparece e a tela fica com cara de 1998. */
.cv-sw input { display: none; }

.cv-sw label {
  position: absolute; inset: 0;
  background: var(--muted-border);
  border-radius: var(--raio-full);
  cursor: pointer;
  transition: background .16s ease;
}
.cv-sw label::after {
  content: "";
  position: absolute; left: 2px; top: 2px;
  width: 20px; height: 20px;
  background: #FFFFFF;
  border-radius: var(--raio-full);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .25);
  transition: transform .16s ease;
}
.cv-sw input:checked + label { background: var(--verde); }
.cv-sw input:checked + label::after { transform: translateX(18px); }
.cv-sw input:disabled + label { opacity: .45; cursor: not-allowed; }

/* escolha entre valores: usa a cor da MARCA, nao o verde. Verde e estado ligado. */
.seg { display: inline-flex; border: 1px solid var(--border-input); border-radius: var(--raio-sm); overflow: hidden; }
.seg button {
  height: var(--fu-h); padding: 0 var(--sp-3);
  border: 0; background: var(--surface); color: var(--text-soft);
  font-size: 13px; font-weight: 500; cursor: pointer;
}
.seg button + button { border-left: 1px solid var(--border-input); }
.seg button.ativo { background: var(--cor-primaria); color: #FFFFFF; font-weight: 600; }

/* ---------------------------------------------------------------- abas */

.xx-tabs { display: flex; gap: var(--sp-4); border-bottom: 1px solid var(--borda); }
.xx-tab {
  border: 0; background: transparent; cursor: pointer;
  padding: var(--sp-2) 0;
  font-size: 13.5px; font-weight: 500; color: var(--text-dim);
  border-bottom: 2px solid transparent;
}
.xx-tab.ativo { color: var(--cor-primaria); border-bottom-color: var(--cor-primaria); font-weight: 600; }
.xx-tab .icon { font-size: 16px; }

/* O painel que a aba troca. `display: none` e nao `hidden`, para a aba poder
   alternar sem mexer em atributo. */
.xx-pane { display: none; }
.xx-pane.ativo { display: flex; flex-direction: column; gap: var(--sp-4); }

/* A faixa de lote SOBE do rodape: e um modo temporario do sistema, e o
   movimento e o que avisa que voce entrou nele. */
@keyframes tselSobe { from { transform: translateY(100%); } to { transform: translateY(0); } }
.tsel-bar { animation: tselSobe .18s ease; }
.tsel-bar .btn, .tsel-bar button { height: 36px; }
/* Sem sidebar (visitante, celular) a faixa encosta na borda esquerda. */
@media (max-width: 900px) { .tsel-bar { left: 0; } }

/* ---------------------------------------------------------------- upload */

.im-drop {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-2);
  min-height: 118px;
  padding: var(--sp-4);
  border: 1.5px dashed var(--border-input);
  border-radius: var(--raio);
  background: var(--surface-2);
  cursor: pointer;
  text-align: center;
}
.im-drop:hover, .im-drop.arrastando {
  border-color: var(--cor-primaria);
  background: var(--cor-primaria-suave);
  border-style: solid;
}
/* 36px, e nao 26: o icone central da zona de upload tem tamanho fixo no padrao,
   e ele e o que sinaliza o estado a distancia. */
.im-drop .icone { font-size: 36px; color: var(--text-dim); }
.im-drop .dica { font-size: 12.5px; color: var(--text-dim-on-surface2); }

/* nome do arquivo escolhido, DENTRO da zona: e ali que o olho procura confirmacao */
.im-arq { display: block; margin-top: 6px; font-weight: 600; color: var(--verde-escuro); }
.im-arq:empty { display: none; }

/* input de arquivo fora da tela: o visual nativo do browser e proibido */
.im-inp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }

.im-drop.carregado { border-style: solid; border-color: var(--verde); background: var(--verde-suave); }
.im-drop.carregado .icone { color: var(--verde-escuro); }

.im-acao { display: flex; align-items: center; gap: var(--sp-2); }
/* a mensagem carrega o margin-right:auto E vem antes do botao no HTML */
.im-msg { margin-right: auto; font-size: 12.5px; color: var(--text-dim); }

/* ---------------------------------------------------------------- loading */

.loading-inline { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-4); }
.loading-overlay {
  position: absolute; inset: 0; z-index: 25;
  background: rgba(250, 250, 248, .72);
  display: grid; place-items: center;
}
.loading-overlay[hidden], .loading-inline[hidden] { display: none; }

.spinner-circle {
  width: 44px; height: 44px;
  border: 4px solid var(--border-2);
  border-top-color: var(--cor-primaria);
  border-radius: var(--raio-full);
  animation: girar .8s linear infinite;
}
@keyframes girar { to { transform: rotate(360deg); } }

/* O texto fica AO LADO do spinner. Nunca dentro do botao: trocar o rotulo do
   botao por "Carregando..." apaga a acao e muda a largura da barra. */
.loading-text { font-size: 13px; color: var(--text-dim); }

/* ------------------------------------------------------------ estado vazio */

.vz {
  flex: 1;
  min-height: 300px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  text-align: center;
  padding: var(--sp-5);
}
.vz-inline { flex: none; min-height: 150px; padding: 22px 16px; }
.vz-icone { font-size: 34px; color: var(--text-mute); }
.vz-titulo { font-family: var(--font-titulo); font-weight: 700; font-size: var(--fs-lg); margin: 0; }
.vz-sub { font-size: 13px; color: var(--text-dim); margin: 0; }

/* ---------------------------------------------------------------- badge */

.badge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 9px;
  border-radius: var(--raio-full);
  font-size: 11.5px;
  font-weight: 600;
}
.badge-ok     { background: var(--success-bg); color: var(--success-text); border: 1px solid var(--success-border); }
.badge-risco  { background: var(--danger-bg);  color: var(--danger-text);  border: 1px solid var(--danger-border); }
.badge-alerta { background: var(--warning-bg); color: var(--warning-text); border: 1px solid var(--warning-border); }
.badge-info   { background: var(--info-bg);    color: var(--info-text);    border: 1px solid var(--info-border); }
.badge-neutro { background: var(--muted);      color: var(--muted-text);   border: 1px solid var(--muted-border); }
/* selo dourado: dourado PREENCHE, e a letra e escura */
.badge-marca  { background: var(--dourado-soft); color: var(--dourado-3); border: 1px solid var(--dourado); }

/* ---------------------------------------------------------------- avisos */

.faixa-aviso {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--raio-sm);
  font-size: 13px;
  border: 1px solid var(--warning-border);
  background: var(--warning-bg);
  color: var(--warning-text);
}
.faixa-aviso .icon { font-size: 18px; flex: none; }

.flash-area { display: flex; flex-direction: column; gap: var(--sp-2); }
.flash { padding: var(--sp-3) var(--sp-4); border-radius: var(--raio-sm); font-size: 13px; }
.flash.success { background: var(--success-bg); color: var(--success-text); border: 1px solid var(--success-border); }
.flash.danger  { background: var(--danger-bg);  color: var(--danger-text);  border: 1px solid var(--danger-border); }
.flash.info    { background: var(--info-bg);    color: var(--info-text);    border: 1px solid var(--info-border); }

/* ------------------------------------------------------------ semaforo */

.barra-teto { height: 8px; background: var(--muted); border-radius: var(--raio-full); overflow: hidden; }
.barra-teto span { display: block; height: 100%; background: var(--success); }
.barra-teto.alerta span { background: var(--warning); }
.barra-teto.risco span  { background: var(--danger); }

/* ---------------------------------------------------------------- login */

.tela-login {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: var(--sp-4);
  background: var(--surface-2);
}
.caixa-login {
  width: 100%; max-width: 380px;
  background: var(--surface);
  border: 1px solid var(--borda);
  border-radius: var(--raio);
  box-shadow: var(--sombra);
  padding: var(--sp-6);
}
.caixa-login .marca {
  font-family: var(--font-titulo);
  font-weight: 800;
  font-size: 17px;
  letter-spacing: -.01em;
  margin-bottom: var(--sp-1);
}
.caixa-login .marca-logo { width: 100%; height: auto; display: block; margin-bottom: var(--sp-3); }
.caixa-login .sub { font-size: 12.5px; color: var(--text-dim); margin-bottom: var(--sp-5); }
.caixa-login .campo { margin-bottom: var(--sp-3); }
.caixa-login .input { width: 100%; }
.caixa-login .btn-primary { width: 100%; margin-top: var(--sp-2); }

/* ------------------------------------------- matriz VER / EDITAR (permissoes)

   Esta grade NAO recebe o componente de tabela. Padrao_Tabela e explicito: as
   linhas precisam ser registros comparaveis entre si para virar listagem, e
   aqui elas nao sao. Ordenar por nome de modulo ou esconder a coluna EDITAR
   quebraria o significado da grade, nao apenas a aparencia dela. Por isso ela
   nasce como <table> simples, sem menu sanduiche e sem filtro por coluna. */

.perm-grupo { border-bottom: 1px solid var(--borda); }
.perm-grupo:last-child { border-bottom: 0; }

.perm-grupo-topo {
  display: flex; align-items: center; gap: var(--sp-3);
  flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface-2);
  border-bottom: 1px solid var(--borda);
}
.perm-grupo-topo .nome {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-dim-on-surface2);
}
.perm-grupo-topo .atalhos { display: flex; gap: 4px; margin-left: auto; }
.perm-grupo-topo .auto { display: flex; align-items: center; gap: var(--sp-2); }
.perm-grupo-topo .auto .rot { font-size: 11.5px; color: var(--text-dim-on-surface2); }

.perm-linha {
  display: grid;
  grid-template-columns: 1fr 90px 90px;
  align-items: center;
  gap: var(--sp-2);
  padding: 9px var(--sp-4);
  border-bottom: 1px solid var(--border-2);
}
.perm-linha:last-child { border-bottom: 0; }
.perm-linha:hover { background: var(--surface-2); }
.perm-linha .mod { font-size: 14px; color: var(--text-soft); }
.perm-linha .mod .chave { font-size: 11.5px; color: var(--text-dim); }
.perm-linha .cx { text-align: center; }

.perm-cabecalho {
  display: grid;
  grid-template-columns: 1fr 90px 90px;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4);
  border-bottom: 1px solid var(--borda);
  font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-dim);
}
.perm-cabecalho .cx { text-align: center; }

.perm-barra {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--borda);
}
.perm-barra .rot { font-size: 12.5px; color: var(--text-dim); margin-right: var(--sp-2); }

/* --------------------------------------------------------- convite aberto

   Convite mora em CARD PROPRIO, nunca como linha da tabela de usuarios: convite
   nao e conta, e virar linha ali faz o operador ler como usuario existente com
   a coluna nome vazia. */

.conv-lista { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: var(--sp-3); }
.conv-card { display: flex; flex-direction: column; gap: 6px; }
.conv-card .cracha { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.conv-card .meta { font-size: 12px; color: var(--text-dim); }
.conv-card .link {
  font-size: 12px;
  font-family: ui-monospace, monospace;
  color: var(--text-dim);
  word-break: break-all;
  background: var(--surface-2);
  border-radius: var(--raio-sm);
  padding: var(--sp-2);
}
.conv-card .acoes { display: flex; gap: var(--sp-2); margin-top: auto; padding-top: var(--sp-2); }

/* ---------------------------------------------------- ferramentas da tabela */

/* item do menu aceso enquanto a linha de filtros esta aberta: sem isso a pessoa
   nao sabe de onde vieram os campos que apareceram no cabecalho */
.menu-tabela button.ativo { background: var(--cor-primaria-suave); color: var(--cor-primaria-escura); font-weight: 600; }
.menu-tabela .grupo-tit {
  padding: 6px var(--sp-2) 2px;
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-dim);
}
.menu-tabela label {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 5px var(--sp-2); font-size: 13px; cursor: pointer;
}
.menu-tabela label:hover { background: var(--surface-2); }

/* a linha de filtros mora DENTRO do thead: assim a rolagem horizontal leva o
   campo junto da coluna que ele filtra */
.th-filtro[hidden] { display: none; }
.th-filtro th { padding-top: 0; padding-bottom: var(--sp-2); }

.tabela th.ordenavel { cursor: pointer; user-select: none; }
.tabela th .ord { font-size: 10px; margin-left: 4px; color: var(--cor-primaria); }

/* --------------------------------------------------- item de pendencia

   Cada linha do checklist de fechamento: o codigo do controle, o que falta em
   texto, e o caminho para resolver. Sem o caminho, o checklist informa e para
   ai, e a pessoa tem que descobrir sozinha onde mexer. */

.pend-item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--border-2);
}
.pend-item:last-child { border-bottom: 0; }
.pend-item .texto { flex: 1; font-size: 13.5px; color: var(--text-soft); }
.pend-item .btn { margin-left: auto; }
@media (max-width: 720px) {
  .pend-item { flex-wrap: wrap; }
  .pend-item .texto { flex: 1 1 100%; }
}

/* ------------------------------------------------- bloco do painel

   Uma campanha por bloco: cabecalho com o nome e o farol, a fileira de KPI e a
   barra do teto. O contador que cuida de tres campanhas ve as tres na mesma
   rolagem, sem trocar de tela. */

.painel-campanha {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--borda);
  border-radius: var(--raio);
  padding: var(--sp-4);
}
.painel-campanha .tabela-topo { padding: 0 0 var(--sp-3); }
.painel-campanha .menu-area { grid-column: 3; justify-self: end; }
