/* ---------------------------------------------------------------------
   Estilos próprios do sistema, sobre o AdminLTE.
   Tudo aqui usa as variáveis de tema do Bootstrap para funcionar igual
   no modo claro e no escuro, sem cor fixa que suma no fundo errado.
   --------------------------------------------------------------------- */

/* Marca: faixa preta com os graus, como no kimono. */
.brand-faixa {
  display: inline-block;
  width: 28px;
  height: 12px;
  border-radius: 2px;
  background: #212529;
  border: 1px solid rgba(255, 255, 255, .35);
  position: relative;
  margin-right: .5rem;
  flex: 0 0 auto;
}
.brand-faixa::after {
  content: '';
  position: absolute;
  right: 2px;
  top: 1px;
  bottom: 1px;
  width: 8px;
  background: repeating-linear-gradient(
    to right,
    #fff 0 1.5px,
    transparent 1.5px 3px
  );
}

/* Foto do aluno onde a inicial apareceria. Mesmo tamanho e mesma forma
   da `.avatar-inicial` para a troca não mexer no layout; `object-fit:
   cover` porque o envio preserva a proporção (um 3x4 vira 300x400) e sem
   isto o retrato apareceria achatado dentro do círculo. */
.avatar-foto {
  border-radius: 50%;
  object-fit: cover;
  flex: 0 0 auto;
  background: var(--bs-secondary-bg);
}

.avatar-inicial {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--bs-primary);
  color: #fff;
  font-weight: 600;
  font-size: .85rem;
  text-transform: uppercase;
  flex: 0 0 auto;
}

/* ---------------------------------------------------------------------
   Faixa do aluno. A cor vem do banco (catálogo de faixas) via style
   inline calculado no servidor, com a cor do texto escolhida por
   contraste — faixa branca precisa de texto escuro para ser legível.
   --------------------------------------------------------------------- */
/* A etiqueta usa a TINTA DO TEMA, não a cor da faixa: texto sobre duas
   cores não tem cor legível (ver o comentário em parciais/faixa.php — 4
   das 10 faixas bicolores reprovavam o mínimo WCAG, uma delas em 1,63:1).
   A cor da faixa virou a amostra à esquerda. */
.faixa-tag {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .2rem .55rem .2rem .3rem;
  border-radius: 999px;
  font-size: .78rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--bs-body-color);
  background: var(--bs-tertiary-bg);
  border: 1px solid var(--bs-border-color);
  white-space: nowrap;
}

/* Retângulo achatado, não círculo: a proporção de uma faixa é o que faz a
   amostra ser reconhecida como faixa, e é nela que as duas cores das
   bicolores aparecem lado a lado. */
.faixa-tag-cor {
  flex: 0 0 auto;
  width: 1.3rem;
  height: .7rem;
  border-radius: 2px;
  /* Dois anéis, porque um só não serve nos dois temas: o interno escuro
     delimita a faixa BRANCA no tema claro, e o externo cinza-médio
     delimita a PRETA no tema escuro. Cinza médio funciona sobre fundo
     claro e escuro — é a única cor fixa que funciona nos dois. */
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .25),
              0 0 0 1px rgba(127, 127, 127, .55);
}

.faixa-tag .graus {
  display: inline-flex;
  gap: 2px;
}
.faixa-tag .grau {
  width: 4px;
  height: 10px;
  border-radius: 1px;
  background: currentColor;
  opacity: .85;
}
.faixa-tag .grau.vazio {
  opacity: .22;
}

/* ---------------------------------------------------------------------
   Faixa em 3D (renders em app/public/faixas).
   A moldura é sempre quadrada e o tamanho vem declarado no <img>, então
   o navegador reserva o espaço antes de baixar — tabela não salta.
   --------------------------------------------------------------------- */
.faixa-3d {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  vertical-align: middle;
}
.faixa-3d img {
  display: block;
  object-fit: contain;
  /* Sombra suave dá assentamento sem competir com a arte do render. */
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .22));
}
.faixa-3d-g {
  flex-direction: column;
  gap: .35rem;
}

/* Graus ao lado da imagem — só nas faixas cujo render não varia por grau
   (as infantis). Nas adultas as listras já estão desenhadas na ponteira,
   e repetir aqui seria contar duas vezes. */
.faixa-3d-graus {
  display: inline-flex;
  flex-direction: column;
  gap: 2px;
}
.faixa-3d-graus .grau {
  width: 10px;
  height: 3px;
  border-radius: 1px;
  background: var(--bs-emphasis-color);
  opacity: .85;
}
.faixa-3d-graus .grau.vazio {
  opacity: .18;
}
.faixa-3d-g .faixa-3d-graus {
  flex-direction: row;
}
.faixa-3d-g .faixa-3d-graus .grau {
  width: 16px;
  height: 4px;
}

.faixa-3d-nome {
  font-size: .8125rem;
  font-weight: 600;
  line-height: 1.25;
  white-space: nowrap;
}
.faixa-3d-g .faixa-3d-nome {
  font-size: 1rem;
  text-align: center;
}
.faixa-3d-grau-num {
  font-weight: 400;
  color: var(--bs-secondary-color);
}

/* ---------------------------------------------------------------------
   Seletor de faixa com imagem (seletor-faixa.js).
   O <select> original fica fora da tela mas dentro do formulário — ver o
   comentário em parciais/seletor_faixa.php.
   --------------------------------------------------------------------- */
.fx-original {
  /* Não é `display:none` nem `hidden`: campo oculto com `required` faz o
     navegador barrar o envio com uma mensagem que ninguém vê, porque não
     há onde desenhá-la. Fora da tela, o campo continua "visível" para a
     validação e some para o usuário. */
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.fx-seletor {
  position: relative;
}

.fx-botao {
  display: flex;
  align-items: center;
  gap: .6rem;
  min-height: 3rem;
  cursor: pointer;
}
.fx-botao img {
  width: 34px;
  height: 34px;
  object-fit: contain;
  flex: 0 0 auto;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .2));
}

.fx-lista {
  position: absolute;
  z-index: 1056; /* acima de modal do Bootstrap (1055) */
  top: calc(100% + .25rem);
  left: 0;
  right: 0;
  max-height: 22rem;
  overflow-y: auto;
  background: var(--bs-body-bg);
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-border-radius);
  box-shadow: 0 .5rem 1.25rem rgba(0, 0, 0, .18);
  padding: .25rem;
}

.fx-grupo {
  font-size: .72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--bs-secondary-color);
  padding: .5rem .5rem .25rem;
}

.fx-opcao {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .25rem .5rem;
  border-radius: calc(var(--bs-border-radius) * .75);
  cursor: pointer;
}
.fx-opcao img {
  width: 40px;
  height: 40px;
  object-fit: contain;
  flex: 0 0 auto;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .2));
}
.fx-opcao:hover,
.fx-opcao.focada {
  background: var(--bs-secondary-bg);
}
.fx-opcao.selecionada {
  background: var(--bs-primary);
  color: var(--jj-primaria-texto, #fff);
}
.fx-opcao.selecionada .fx-nome {
  font-weight: 600;
}

.fx-textos {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.3;
}
.fx-nome {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Aviso por opção — hoje só a idade mínima da faixa. Ganha linha própria
   em vez de ficar colado no nome, como precisava ficar no select nativo. */
.fx-aviso {
  font-size: .72rem;
  color: var(--bs-warning-text-emphasis, #997404);
}
.fx-opcao.selecionada .fx-aviso {
  color: inherit;
  opacity: .85;
}

/* Amostra de cor, para faixa sem render 3D. */
.fx-cor {
  width: 34px;
  height: 12px;
  border-radius: 2px;
  border: 1px solid rgba(0, 0, 0, .2);
  flex: 0 0 auto;
}
.fx-vazio {
  width: 34px;
  text-align: center;
  color: var(--bs-secondary-color);
  flex: 0 0 auto;
}

/* Barra vertical com a cor da faixa, para a lista de alunos. */
.faixa-barra {
  display: inline-block;
  width: 5px;
  height: 22px;
  border-radius: 3px;
  border: 1px solid rgba(0, 0, 0, .2);
  vertical-align: middle;
}

/* ---------------------------------------------------------------------
   Totem de check-in. Fica numa TV ou tablet no tatame, então é
   propositalmente grande e de alto contraste — tem que ser legível de
   três metros de distância.
   --------------------------------------------------------------------- */
.totem {
  min-height: 60vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.5rem;
  text-align: center;
}
.totem-codigo {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: clamp(3rem, 14vw, 8rem);
  font-weight: 700;
  letter-spacing: .12em;
  line-height: 1;
  color: var(--bs-emphasis-color);
}
.totem-barra {
  width: min(420px, 80vw);
  height: 10px;
  border-radius: 999px;
  background: var(--bs-secondary-bg);
  overflow: hidden;
}
.totem-barra > span {
  display: block;
  height: 100%;
  background: var(--bs-primary);
  transition: width .95s linear;
}
.totem-qr {
  background: #fff;
  padding: 12px;
  border-radius: 12px;
  line-height: 0;
}
.totem-qr svg {
  width: min(260px, 60vw);
  height: auto;
}

/* ---------------------------------------------------------------------
   Distribuição por faixa no painel.

   Grade que quebra sozinha, com a faixa em imagem, a contagem em
   destaque e o nome pequeno abaixo. O nome fica porque cor sozinha não
   basta: "Cinza e Branca" e "Cinza" são quase iguais em miniatura, e
   quem tem daltonismo não separa laranja de verde.
   --------------------------------------------------------------------- */
.dist-faixa-grupo + .dist-faixa-grupo {
  margin-top: .85rem;
}

.dist-faixa-cab {
  display: flex;
  align-items: baseline;
  gap: .4rem;
  font-size: .72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--bs-secondary-color);
  margin-bottom: .35rem;
}
.dist-faixa-soma {
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
}
.dist-faixa-soma::before {
  content: '· ';
}

/* Duas colunas: cada item na horizontal (faixa, contagem, nome), dois por
   linha. Com 5 faixas por categoria dá 3 linhas em vez de 5, e o cartão
   deixa de esticar a coluna do painel.

   O teto de 210px por coluna existe porque o cartão ocupa a largura toda
   da tela: com `1fr` cada item ficava numa célula de 540px mostrando 140px
   de conteúdo, e a foto da tela mostrou o resultado — nome da faixa e
   faixa seguinte separados por um vão de 400px. */
.dist-faixa {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 210px));
  gap: .2rem .5rem;
}

/* Abaixo de ~360px de cartão não cabem dois — volta a uma coluna em vez
   de comprimir o nome até virar reticência. */
@media (max-width: 400px) {
  .dist-faixa {
    grid-template-columns: minmax(0, 1fr);
  }
}

.dist-faixa-item {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: .45rem;
  padding: .2rem .3rem;
  border-radius: var(--bs-border-radius);
  min-width: 0;
}
.dist-faixa-item:hover {
  background: var(--bs-secondary-bg);
}
.dist-faixa-item .faixa-3d img {
  width: 38px;
  height: 38px;
}

.dist-faixa-total {
  font-size: 1rem;
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  /* Largura fixa para as contagens alinharem entre as duas colunas. */
  min-width: 1.1rem;
  text-align: right;
  flex: 0 0 auto;
}
.dist-faixa-nome {
  font-size: .78rem;
  line-height: 1.2;
  color: var(--bs-secondary-color);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* =====================================================================
   GRÁFICOS (app/Core/Grafico.php)

   Os passos de cor abaixo saíram do validador da especificação de
   visualização, rodado contra as superfícies REAIS deste sistema — cartão
   branco no claro, #212529 no escuro:

     claro   contexto #86b6ef (2,11:1)   ênfase #2a78d6
     escuro  contexto #256abf (2,86:1)   ênfase #9ec5f4

   Uma matiz só, dois passos. Não há série categórica em nenhum gráfico do
   painel, então não há par de matizes que possa se confundir sob
   daltonismo. Não use a cor da academia aqui: ela é configurável e não
   passa por validação nenhuma.
   ===================================================================== */
.viz {
  --viz-enfase: #2a78d6;
  --viz-contexto: #86b6ef;
  --viz-grade: var(--bs-border-color);
  --viz-ink: var(--bs-body-color);
  --viz-ink-fraca: var(--bs-secondary-color);
}
:root[data-bs-theme="dark"] .viz {
  --viz-enfase: #9ec5f4;
  --viz-contexto: #256abf;
}

.viz-vazio,
.viz-nota {
  font-size: .78rem;
  color: var(--bs-secondary-color);
  margin: .5rem 0 0;
}
.viz-vazio {
  text-align: center;
  padding: 1.5rem 0;
  margin: 0;
}

/* ---- Barras horizontais ---- */
.viz-barras-h {
  display: flex;
  flex-direction: column;
  gap: .55rem;
}
.viz-bh-linha {
  display: grid;
  grid-template-columns: 8.5rem 1fr auto 2.4rem;
  align-items: center;
  gap: .6rem;
  font-size: .8125rem;
}
.viz-bh-rotulo {
  color: var(--viz-ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.viz-bh-trilha {
  height: 12px;
  background: var(--bs-secondary-bg);
  border-radius: 4px;
  overflow: hidden;
}
.viz-bh-barra {
  display: block;
  height: 100%;
  background: var(--viz-enfase);
  /* Ponta arredondada de 4px ancorada na base da trilha. */
  border-radius: 0 4px 4px 0;
}
.viz-bh-valor {
  font-variant-numeric: tabular-nums;
  color: var(--viz-ink);
  white-space: nowrap;
}
.viz-bh-parte {
  font-variant-numeric: tabular-nums;
  color: var(--viz-ink-fraca);
  text-align: right;
  font-size: .75rem;
}

/* Em cartão estreito as quatro colunas fixas comem a trilha: 8,5rem de
   rótulo + "R$ 1.234,00" + o percentual deixavam uns 30px de barra, e
   barra de 30px não compara nada. Abaixo de 576px o rótulo sobe para a
   linha de cima e o percentual sai — o número absoluto fica, que é o que
   se lê. */
@media (max-width: 575.98px) {
  .viz-bh-linha {
    grid-template-columns: 1fr auto;
    grid-template-areas:
      'rotulo valor'
      'trilha trilha';
    gap: .15rem .5rem;
  }
  .viz-bh-rotulo { grid-area: rotulo; }
  .viz-bh-valor  { grid-area: valor; }
  .viz-bh-trilha { grid-area: trilha; }
  .viz-bh-parte  { display: none; }
}

/* ---- Colunas com ênfase ---- */
.viz-colunas {
  --viz-altura: 150px;
  /* 12 meses em 340px de celular dá 28px por coluna, e "out" não caberia.
     Em vez de esconder rótulo (que é o eixo) ou girar o texto, o gráfico
     rola dentro do próprio cartão. Em qualquer largura acima de 420px o
     min-width não tem efeito nenhum. */
  overflow-x: auto;
}
.viz-col-area {
  display: flex;
  align-items: flex-end;
  height: var(--viz-altura);
  min-width: 420px;
  /* Linha de base recessiva; sem moldura em volta do gráfico. */
  border-bottom: 1px solid var(--viz-grade);
}
.viz-col {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  height: 100%;
  /* 2px de folga entre colunas vizinhas, feita com padding para o
     percentual de largura continuar exato. */
  padding: 0 2px;
  position: relative;
  min-width: 0;
}
.viz-col-barra {
  display: block;
  width: 100%;
  background: var(--viz-contexto);
  border-radius: 4px 4px 0 0;
}
.viz-col.destaque .viz-col-barra {
  background: var(--viz-enfase);
}
/* Coluna com parte preenchida: o total é o tom de contexto, o realizado é
   a ênfase por dentro. A parte cresce a partir da BASE, então ela é
   posicionada no rodapé da coluna — não no topo, que é onde um
   `height` sem ancoragem cairia. */
.viz-colunas-parciais .viz-col-barra {
  position: relative;
  overflow: hidden;
}
.viz-col-parte {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: block;
  background: var(--viz-enfase);
  border-radius: 0;
}

/* Legenda. Duas coisas codificadas na mesma coluna exigem dizer qual é
   qual — a especificação de visualização pede legenda sempre que houver
   mais de uma série. */
.viz-legenda {
  display: flex;
  flex-wrap: wrap;
  gap: .25rem 1rem;
  margin-top: .55rem;
  font-size: .75rem;
  color: var(--viz-ink-fraca);
}
.viz-legenda-item {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
}
.viz-amostra {
  width: 11px;
  height: 11px;
  border-radius: 2px;
  flex: 0 0 auto;
}
.viz-amostra.enfase {
  background: var(--viz-enfase);
}
.viz-amostra.contexto {
  background: var(--viz-contexto);
}

.viz-col-valor {
  font-size: .7rem;
  font-weight: 700;
  color: var(--viz-ink);
  margin-bottom: .15rem;
  white-space: nowrap;
}
.viz-col-rotulo {
  font-size: .65rem;
  color: var(--viz-ink-fraca);
  margin-top: .25rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.viz-col.destaque .viz-col-rotulo {
  color: var(--viz-ink);
  font-weight: 600;
}

/* ---- Área ---- */
.viz-area svg {
  display: block;
  width: 100%;
  height: auto;
}
.viz-area-linha {
  fill: none;
  stroke: var(--viz-enfase);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
  /* preserveAspectRatio="none" esticaria o traço junto com o desenho. */
  vector-effect: non-scaling-stroke;
}
.viz-grad-topo {
  stop-color: var(--viz-enfase);
  stop-opacity: .28;
}
.viz-grad-base {
  stop-color: var(--viz-enfase);
  stop-opacity: .02;
}
.viz-grade {
  stroke: var(--viz-grade);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.viz-ponto {
  fill: var(--bs-body-bg);
  stroke: var(--viz-enfase);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
  /* Alvo de toque maior que a marca. */
  r: 4;
}
.viz-ponto-grupo:hover .viz-ponto {
  fill: var(--viz-enfase);
}
.viz-area-eixo {
  display: flex;
  justify-content: space-between;
  margin-top: .2rem;
  font-size: .68rem;
  color: var(--viz-ink-fraca);
}

/* ---- Medidores ---- */
.viz-medidores {
  display: flex;
  flex-direction: column;
  gap: .8rem;
}
.viz-med-topo {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .5rem;
  margin-bottom: .3rem;
}
.viz-med-rotulo {
  font-size: .8125rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.viz-med-num {
  font-size: .875rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.viz-med-num .de {
  font-weight: 400;
  color: var(--viz-ink-fraca);
}
.viz-med-trilha {
  height: 10px;
  background: var(--bs-secondary-bg);
  border-radius: 5px;
  overflow: hidden;
}
.viz-med-barra {
  display: block;
  height: 100%;
  background: var(--viz-enfase);
  border-radius: 5px;
}
/* Status: os passos vêm da paleta de status da especificação, que é fixa
   e nunca tematizada — e sempre acompanhada de ícone e palavra. */
.viz-med.quase .viz-med-barra {
  background: #fab219;
}
.viz-med.lotado .viz-med-barra {
  background: #d03b3b;
}
.viz-med-nota {
  font-size: .72rem;
  color: var(--viz-ink-fraca);
  margin-top: .2rem;
}
.viz-med.quase .viz-med-nota {
  color: var(--bs-warning-text-emphasis);
}
.viz-med.lotado .viz-med-nota {
  color: var(--bs-danger-text-emphasis);
}
.viz-med-nota i {
  font-size: .68rem;
}

/* ---- Tabela de apoio ---- */
.viz-tabela {
  margin-top: .75rem;
  font-size: .8125rem;
}
.viz-tabela > summary {
  cursor: pointer;
  color: var(--bs-secondary-color);
  font-size: .78rem;
  padding: .2rem 0;
}
.viz-tabela > summary:hover {
  color: var(--bs-body-color);
}
.viz-tabela table {
  margin-top: .4rem;
}

/* ---- Indicador com variação ---- */
.kpi-delta {
  /* Bloco, não inline-flex: a variação e o texto da base ocupam linhas
     diferentes, e com flex no pai o filho `display:block` continuaria
     lado a lado. */
  display: block;
  font-size: .78rem;
  font-weight: 600;
  margin-top: .3rem;
}
.kpi-delta-num {
  display: inline-flex;
  align-items: center;
  gap: .15rem;
  white-space: nowrap;
}
.kpi-delta-num i {
  /* As setas do Bootstrap Icons vêm com folga lateral grande; sem isto o
     número parece descolado da seta. */
  margin: 0 -.15rem;
  font-size: 1.05rem;
  line-height: 1;
}
/* Verde/vermelho seguem se a variação é BOA, não se subiu: mais receita é
   bom, mais atraso é ruim. O ícone acompanha o sentido do número. */
.kpi-delta.bom {
  color: var(--bs-success-text-emphasis);
}
.kpi-delta.ruim {
  color: var(--bs-danger-text-emphasis);
}
.kpi-delta.neutro {
  color: var(--bs-secondary-color);
  font-weight: 400;
}
/* O texto da base ("vs. mesmo dia do mês passado") vai numa LINHA PRÓPRIA.
   Na mesma linha da variação ele estourava a borda do cartão — só se viu
   isso fotografando a tela; nenhuma verificação de HTML pegaria. Duas
   linhas quebradas em até três, com o tamanho reduzido, cabem no cartão
   mais estreito (col-6 no celular). */
.kpi-delta-base {
  display: block;
  color: var(--bs-secondary-color);
  font-weight: 400;
  font-size: .72rem;
  line-height: 1.25;
  white-space: normal;
  margin-top: .1rem;
}

/* =====================================================================
   LOGO DA ACADEMIA NA BARRA DE CIMA

   A barra segue o tema da página, então a logo precisa servir aos dois
   fundos. Dois casos:

   1. A academia subiu variante para fundo escuro → as duas imagens vão no
      HTML e aqui só se troca qual aparece. Elemento com `display:none`
      fica fora da árvore de acessibilidade, então o leitor de tela não
      anuncia a marca duas vezes.

   2. Não subiu → é a mesma imagem nos dois temas, e não se sabe nada sobre
      a tinta dela. Aí ela ganha uma pastilha clara no modo escuro. A
      pastilha resolve tinta escura e estragaria tinta branca — por isso ela
      NÃO entra no caso 1, onde a academia já disse qual imagem serve.
   ===================================================================== */
.marca-topo {
  display: inline-block;
  line-height: 0;
  vertical-align: middle;
}
.marca-topo img {
  max-height: 26px;
  width: auto;
  vertical-align: middle;
}
.marca-topo-escura {
  display: none;
}
/* A troca é restrita a `.marca-topo-troca` de propósito. Sem esse escopo,
   o modo escuro escondia a logo clara também quando NÃO havia variante
   para pôr no lugar — e a pastilha aparecia vazia. */
:root[data-bs-theme="dark"] .marca-topo-troca .marca-topo-clara {
  display: none;
}
:root[data-bs-theme="dark"] .marca-topo-troca .marca-topo-escura {
  display: inline;
}
:root[data-bs-theme="dark"] .marca-topo-pastilha {
  /* Cinza claro fixo, não token: o token de superfície clara vira escuro
     dentro do escopo escuro, que é exatamente o que não serve aqui. */
  background: #f1f3f5;
  padding: .2rem .45rem;
  border-radius: var(--bs-border-radius);
  line-height: 0;
}

/* Subtítulo de cartão.
   O AdminLTE declara `.card-title { float: left }`, então qualquer coisa
   depois do título sobe para a MESMA linha e cola nele — foi o que a foto
   da tela mostrou. `clear: both` é o que devolve a segunda linha. */
.card-subtitulo {
  display: block;
  clear: both;
  font-size: .78rem;
  line-height: 1.3;
  color: var(--bs-secondary-color);
  padding-top: .15rem;
}

/* Cartão de indicador do painel. */
.kpi {
  border: 1px solid var(--bs-border-color);
  border-radius: .75rem;
  padding: 1rem 1.15rem;
  background: var(--bs-body-bg);
  height: 100%;
}
.kpi .rotulo {
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--bs-secondary-color);
  margin-bottom: .35rem;
}
.kpi .valor {
  font-size: 1.65rem;
  font-weight: 700;
  line-height: 1.1;
}
.kpi .nota {
  font-size: .8rem;
  color: var(--bs-secondary-color);
  margin-top: .25rem;
}

/* Campos monetários e numéricos alinhados à direita ficam mais fáceis de conferir. */
.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Marca visual de dado sensível na tela, para o operador saber o que está vendo. */
.dado-sensivel {
  border-left: 3px solid var(--bs-warning);
  padding-left: .6rem;
}

/* Aviso de menor de idade no cadastro. */
.bloco-menor {
  border: 1px dashed var(--bs-warning);
  border-radius: .5rem;
  padding: 1rem;
  background: rgba(255, 193, 7, .07);
}

table.tabela-compacta td,
table.tabela-compacta th {
  vertical-align: middle;
}

/* =====================================================================
   TABELA DE DADOS — barra de ferramentas, cartão, seleção
   Adaptado de referência de tabela de dados. Tudo em tokens do Bootstrap
   (--bs-*), nunca hex fixo, para o tema escuro e a cor da academia
   continuarem valendo sem uma segunda tabela de cores.
   ===================================================================== */

.tabela-toolbar {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-bottom: .85rem;
  flex-wrap: wrap;
}

.tabela-busca {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex: 1 1 16rem;
  min-width: 12rem;
  max-width: 30rem;
  padding: 0 .75rem;
  height: 2.5rem;
  background: var(--bs-body-bg);
  border: 1px solid var(--bs-border-color);
  border-radius: 999px;
  color: var(--bs-secondary-color);
}
.tabela-busca:focus-within {
  border-color: var(--jj-primaria, var(--bs-primary));
  box-shadow: 0 0 0 .2rem rgba(var(--bs-primary-rgb), .15);
}
.tabela-busca input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  background: transparent;
  color: var(--bs-body-color);
  font-size: .875rem;
  outline: none;
}
.tabela-busca input::-webkit-search-cancel-button {
  cursor: pointer;
}

/* Botões da barra: hairline, fundo do cartão, altura igual à busca. */
.btn-toolbar {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  height: 2.5rem;
  padding: 0 .85rem;
  font-size: .875rem;
  background: var(--bs-body-bg);
  border: 1px solid var(--bs-border-color);
  border-radius: 999px;
  color: var(--bs-body-color);
  white-space: nowrap;
}
.btn-toolbar:hover {
  background: var(--bs-secondary-bg);
}
.btn-toolbar.dropdown-toggle::after {
  margin-left: .15rem;
  opacity: .55;
}

.badge-contador {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.15rem;
  height: 1.15rem;
  padding: 0 .3rem;
  border-radius: 999px;
  background: var(--bs-primary);
  color: var(--jj-primaria-texto, #fff);
  font-size: .7rem;
  font-weight: 700;
  line-height: 1;
}

.btn-novo {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  height: 2.5rem;
  padding: 0 1.1rem;
  border-radius: 999px;
  font-size: .875rem;
  font-weight: 600;
  white-space: nowrap;
}

/* ---- Cartão da tabela ---- */
.tabela-cartao {
  background: var(--bs-body-bg);
  border: 1px solid var(--bs-border-color);
  border-radius: 1rem;
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .03), 0 8px 24px -12px rgba(0, 0, 0, .12);
}

table.tabela-dados {
  --bs-table-bg: transparent;
  margin: 0;
}
table.tabela-dados > thead > tr > th {
  padding: .8rem 1rem;
  background: var(--bs-body-bg);
  border-bottom: 1px solid var(--bs-border-color);
  font-size: .78rem;
  font-weight: 600;
  color: var(--bs-secondary-color);
  white-space: nowrap;
}
.th-conteudo {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
}
/* SVG embutido ou ícone de fonte, tanto faz: as telas novas usam
   Bootstrap Icons (a fonte já é carregada) em vez de 6 linhas de <svg>
   por cabeçalho de coluna. O tratamento visual é o mesmo. */
.th-conteudo svg,
.th-conteudo .bi {
  opacity: .6;
  flex: 0 0 auto;
}
.th-conteudo .bi {
  font-size: .9rem;
}

table.tabela-dados > tbody > tr > td {
  padding: .6rem 1rem;
  border-bottom: 1px solid var(--bs-border-color);
  vertical-align: middle;
}
table.tabela-dados > tbody > tr:last-child > td {
  border-bottom: 0;
}
table.tabela-dados > tbody > tr:hover > td {
  background: var(--bs-secondary-bg);
}
/* Linha marcada fica evidente mesmo com o mouse longe dela. */
table.tabela-dados > tbody > tr.marcada > td {
  background: rgba(var(--bs-primary-rgb), .07);
}

.col-selecao {
  width: 2.6rem;
  padding-right: 0 !important;
}
.col-acoes {
  width: 3rem;
  text-align: right;
}

/* Item de flex que precisa poder ENCOLHER abaixo do próprio conteúdo.
   Sem isto, `text-overflow: ellipsis` num filho não funciona: a largura
   mínima automática de um item de flex é o tamanho do conteúdo, então o
   nome longo empurra o cartão em vez de virar reticências.

   Não vem do Bootstrap. Escrevi `min-w-0` numa tela achando que vinha, e
   a classe simplesmente não fazia nada — o mesmo tipo de erro silencioso
   de `text-bg-*-subtle`. Existir aqui é o que torna o nome verdadeiro. */
.min-w-0 { min-width: 0; }

/* ---- Colunas de critério (regras de graduação) ----
   Quatro campos numéricos por linha. Sem largura fixa o navegador dá a
   eles a largura do cabeçalho, e a tabela fica com quatro caixas largas
   para números de dois dígitos — a pessoa perde a linha ao ir do nome da
   faixa até o último campo.
   8.5rem é o que faz "Meses na faixa" caber em UMA linha: mais estreito e
   o cabeçalho quebra, ficando mais alto que quatro linhas da tabela. */
.col-criterio {
  width: 8.5rem;
  vertical-align: top;
}

/* Lista de definições do texto de abertura: densa, sem marcador saltando
   à frente do texto — ela é apoio, não conteúdo principal da tela. */
.lista-criterios {
  padding-left: 1.1rem;
  margin-bottom: 0;
  font-size: .8125rem;
  line-height: 1.5;
}
.lista-criterios li::marker {
  color: var(--bs-secondary-color);
}
.entrada-criterio {
  max-width: 5.5rem;
  text-align: center;
}
/* O placeholder aqui não é dica: é o valor que VALE quando o campo está
   vazio. Precisa ser legível, não quase invisível — mas ainda distinto do
   número digitado, senão não se sabe qual dos dois está em vigor. */
.entrada-criterio::placeholder {
  color: var(--bs-secondary-color);
  opacity: 1;
  font-style: italic;
}

/* ---- Célula do aluno ---- */
.celula-aluno {
  display: flex;
  align-items: center;
  gap: .6rem;
  min-width: 0;
}
.celula-aluno-texto {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.3;
}
.nome-aluno {
  font-weight: 600;
  color: var(--bs-body-color);
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.nome-aluno:hover {
  color: var(--jj-primaria, var(--bs-primary));
  text-decoration: underline;
}
.celula-aluno .sub,
.celula-treino .sub {
  font-size: .76rem;
  color: var(--bs-secondary-color);
  white-space: nowrap;
}
.celula-treino {
  display: flex;
  flex-direction: column;
  line-height: 1.3;
  font-size: .875rem;
}

/* ---- Pílulas ---- */
.pill {
  display: inline-flex;
  align-items: center;
  gap: .2rem;
  padding: .05rem .4rem;
  border-radius: 999px;
  font-size: .7rem;
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
  flex: 0 0 auto;
}
.pill-info {
  background: var(--bs-info-bg-subtle);
  color: var(--bs-info-text-emphasis);
  border: 1px solid var(--bs-info-border-subtle);
}
.pill-danger {
  background: var(--bs-danger-bg-subtle);
  color: var(--bs-danger-text-emphasis);
  border: 1px solid var(--bs-danger-border-subtle);
}

/* Situação: tom suave com texto escuro e contorno — o ícone acompanha,
   para a informação não depender só da cor. */
.pill-situacao {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: .2rem .6rem;
  border-radius: 999px;
  font-size: .78rem;
  font-weight: 600;
  white-space: nowrap;
  border: 1px solid currentColor;
}
.pill-situacao i {
  font-size: .7rem;
  opacity: .85;
}

/* ---------------------------------------------------------------------
   Variantes de cor da pílula de situação.

   ATENÇÃO — ESTAS CLASSES SÃO NOSSAS, NÃO DO BOOTSTRAP.

   O Bootstrap 5.3 traz `bg-success-subtle`, `text-success-emphasis` e
   `border-success-subtle` separados, e traz `text-bg-success` (cor cheia).
   Ele NÃO traz `text-bg-success-subtle`. Eu usei esse nome nas views
   assumindo que existia, e o resultado foi silencioso e ruim: a pílula
   não recebia fundo nem cor nenhuma, herdava a cor do corpo e ficava
   idêntica em todos os estados. A situação — que é a informação toda
   daquela coluna — não estava sendo comunicada por cor em NENHUMA tela.
   Só apareceu ao fotografar a tela: no HTML a classe estava lá.

   A lição, e o motivo deste comentário existir: classe de framework que
   não existe não dá erro. Ela simplesmente não faz nada.

   Aqui as três peças do Bootstrap são compostas na variante única que as
   views usam. Os tokens `*-bg-subtle` e `*-text-emphasis` são definidos
   pelo Bootstrap para os DOIS temas, então a pílula continua legível no
   modo escuro sem uma segunda tabela de cores.
   --------------------------------------------------------------------- */
.pill-situacao.text-bg-success-subtle {
  background-color: var(--bs-success-bg-subtle);
  color: var(--bs-success-text-emphasis);
  border-color: var(--bs-success-border-subtle);
}
.pill-situacao.text-bg-warning-subtle {
  background-color: var(--bs-warning-bg-subtle);
  color: var(--bs-warning-text-emphasis);
  border-color: var(--bs-warning-border-subtle);
}
.pill-situacao.text-bg-danger-subtle {
  background-color: var(--bs-danger-bg-subtle);
  color: var(--bs-danger-text-emphasis);
  border-color: var(--bs-danger-border-subtle);
}
.pill-situacao.text-bg-secondary-subtle {
  background-color: var(--bs-secondary-bg-subtle);
  color: var(--bs-secondary-color);
  border-color: var(--bs-border-color);
}
.pill-situacao.text-bg-info-subtle {
  background-color: var(--bs-info-bg-subtle);
  color: var(--bs-info-text-emphasis);
  border-color: var(--bs-info-border-subtle);
}
.pill-situacao.text-bg-dark-subtle {
  background-color: var(--bs-secondary-bg);
  color: var(--bs-emphasis-color);
  border-color: var(--bs-border-color);
}

/* O mesmo vale para os `chip` coloridos da tela de usuários. */
.chip.text-bg-primary-subtle {
  background-color: var(--bs-primary-bg-subtle);
  color: var(--bs-primary-text-emphasis);
  border-color: var(--bs-primary-border-subtle);
}
.chip.text-bg-info-subtle {
  background-color: var(--bs-info-bg-subtle);
  color: var(--bs-info-text-emphasis);
  border-color: var(--bs-info-border-subtle);
}
.chip.text-bg-success-subtle {
  background-color: var(--bs-success-bg-subtle);
  color: var(--bs-success-text-emphasis);
  border-color: var(--bs-success-border-subtle);
}
.chip.text-bg-secondary-subtle {
  background-color: var(--bs-secondary-bg-subtle);
  color: var(--bs-secondary-color);
  border-color: var(--bs-border-color);
}

/* ---- Chips de turma ---- */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: .25rem;
}
.chip {
  display: inline-block;
  max-width: 9rem;
  padding: .1rem .5rem;
  border-radius: .4rem;
  background: var(--bs-secondary-bg);
  border: 1px solid var(--bs-border-color);
  font-size: .75rem;
  color: var(--bs-body-color);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.chip-mais {
  background: transparent;
  color: var(--bs-secondary-color);
  cursor: default;
}

/* ---- Chip de pessoa (professor) ---- */
.chip-pessoa {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  max-width: 11rem;
  padding: .15rem .55rem .15rem .2rem;
  border: 1px solid var(--bs-border-color);
  border-radius: 999px;
  font-size: .8rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.avatar-mini {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.35rem;
  height: 1.35rem;
  border-radius: 50%;
  background: var(--bs-primary);
  color: var(--jj-primaria-texto, #fff);
  font-size: .68rem;
  font-weight: 700;
  text-transform: uppercase;
  flex: 0 0 auto;
}

/* ---- Botão de ações da linha ---- */
.btn-acoes {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 0;
  border-radius: .5rem;
  background: transparent;
  color: var(--bs-secondary-color);
}
.btn-acoes:hover,
.btn-acoes[aria-expanded="true"] {
  background: var(--bs-secondary-bg);
  color: var(--bs-body-color);
}

/* ---- Rodapé e vazio ---- */
.tabela-rodape {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  padding: .7rem 1rem;
  border-top: 1px solid var(--bs-border-color);
  background: var(--bs-body-bg);
}
.tabela-vazia {
  padding: 3rem 1rem;
  text-align: center;
  color: var(--bs-secondary-color);
}
.tabela-contagem {
  font-size: .8125rem;
  color: var(--bs-secondary-color);
}
.tabela-contagem strong {
  color: var(--bs-body-color);
  font-variant-numeric: tabular-nums;
}

/* Ação primária da barra de ferramentas. Fica no fim da barra e é o único
   botão preenchido ali — dois botões preenchidos competindo é o começo do
   "qual eu clico?". */
.btn-toolbar-acao {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  white-space: nowrap;
}

/* ---- Decisão de graduação (exame em lote) ----
   As três opções empilhadas e sempre visíveis: o professor compara "não
   graduar / +1 grau / próxima faixa" de uma vez, por aluno. Num `<select>`
   ele leria uma por vez, e a opção indisponível não teria onde explicar o
   motivo ("último grau da faixa"). */
.decisao {
  display: flex;
  flex-direction: column;
  gap: .15rem;
}
.decisao-opcao {
  display: flex;
  align-items: center;
  gap: .4rem;
  font-size: .8125rem;
  padding: .1rem .25rem;
  border-radius: calc(var(--bs-border-radius) * .6);
  cursor: pointer;
  line-height: 1.3;
}
.decisao-opcao:hover {
  background: var(--bs-secondary-bg);
}
.decisao-opcao:has(input:checked) {
  background: rgba(var(--bs-primary-rgb), .1);
  font-weight: 600;
}
.decisao-opcao:focus-within {
  outline: 2px solid var(--bs-primary);
  outline-offset: 1px;
}
.decisao-opcao .form-check-input {
  margin: 0;
  flex: 0 0 auto;
}
/* Opção indisponível fica legível: o texto dela É a explicação do motivo,
   então apagá-la até quase o branco esconderia justamente a informação. */
.decisao-opcao.desativada {
  cursor: not-allowed;
  color: var(--bs-secondary-color);
}
.decisao-opcao.desativada:hover {
  background: transparent;
}

/* ---- Lista de candidatos à matrícula (tela da turma) ----
   Grade que se adapta em vez de um `<select multiple>`: seleção múltipla
   em select nativo exige Ctrl+clique, perde a seleção a cada rolagem
   errada, e não tem onde mostrar faixa, idade e o aviso de faixa etária. */
.lista-candidatos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: .4rem;
  max-height: 26rem;
  overflow-y: auto;
  padding: .15rem;
}
.candidato {
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .45rem .6rem;
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-border-radius);
  cursor: pointer;
  min-width: 0;
}
.candidato:hover {
  background: var(--bs-secondary-bg);
}
.candidato:has(input:checked) {
  border-color: var(--bs-primary);
  background: rgba(var(--bs-primary-rgb), .07);
}
.candidato:focus-within {
  outline: 2px solid var(--bs-primary);
  outline-offset: 2px;
}
.candidato:has(input:disabled) {
  opacity: .55;
  cursor: not-allowed;
}
.candidato .form-check-input {
  flex: 0 0 auto;
  margin: 0;
}
.candidato .faixa-3d img {
  width: 30px;
  height: 30px;
}
.candidato-texto {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.3;
}
.candidato-nome {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.candidato-nota {
  font-size: .75rem;
  color: var(--bs-secondary-color);
}
/* Fora da faixa de idade: borda de aviso E texto escrito. Cor sozinha não
   informa quem não distingue amarelo, e não sobrevive à impressão. */
.candidato-alerta {
  border-color: var(--bs-warning);
}
.candidato-aviso {
  /* `block` porque um candidato pode ter DOIS avisos (fora da idade e
     abaixo da faixa mínima). Sendo `span`, sem isto os dois sairiam na
     mesma linha, colados, e ninguém leria o segundo. */
  display: block;
  font-size: .72rem;
  color: var(--bs-warning-text-emphasis);
  font-weight: 600;
}

/* Amostra da cor de uma modalidade. Quadrado com borda em vez de círculo
   liso: cor clara sobre fundo claro precisa do contorno para existir. */
.amostra-cor {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: 3px;
  border: 1px solid rgba(0, 0, 0, .25);
  flex: 0 0 auto;
}

/* Editor embutido na linha da tabela (`<details>` nativo).
   Editar um nome e uma cor não justifica abrir outra tela e voltar. */
.editor-linha {
  margin-top: .3rem;
}
.editor-linha > summary {
  cursor: pointer;
  font-size: .78rem;
  color: var(--bs-secondary-color);
  width: fit-content;
}
.editor-linha > summary:hover {
  color: var(--bs-body-color);
}
.editor-linha[open] > summary {
  color: var(--bs-body-color);
  font-weight: 600;
}

/* Texto digitado por uma pessoa, com as quebras de linha dela.
   Justificativa de LGPD e observação de aluno são escritas em parágrafos;
   sem `pre-wrap` viram um bloco corrido e perdem a estrutura. */
.texto-preservado {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Linha de tabela que exige ação hoje (prazo de LGPD vencido).
   Barra na borda esquerda além do fundo: cor de fundo sozinha desaparece
   para quem não distingue vermelho, e some na impressão. */
table.tabela-dados > tbody > tr.linha-alerta > td {
  background: var(--bs-danger-bg-subtle);
}
table.tabela-dados > tbody > tr.linha-alerta > td:first-child {
  box-shadow: inset 3px 0 0 0 var(--bs-danger);
}

/* ---- Escolha de papel (tela de usuários) ----
   Cartões com rádio em vez de `<select>`: dar permissão é decisão que se
   toma comparando o que cada papel abre, e num select o administrador lê
   uma opção por vez e escolhe pelo nome do cargo. */
.escolha-papel {
  display: grid;
  gap: .5rem;
}
.escolha-papel-item {
  display: flex;
  align-items: flex-start;
  gap: .65rem;
  padding: .7rem .85rem;
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-border-radius);
  cursor: pointer;
}
.escolha-papel-item:hover {
  background: var(--bs-secondary-bg);
}
.escolha-papel-item.marcada {
  border-color: var(--bs-primary);
  background: rgba(var(--bs-primary-rgb), .06);
}
/* O contorno de foco vai no cartão, não no rádio de 16px: quem navega por
   teclado precisa ver onde está sem procurar o ponto azul. */
.escolha-papel-item:focus-within {
  outline: 2px solid var(--bs-primary);
  outline-offset: 2px;
}
.escolha-papel-item .form-check-input {
  margin-top: .15rem;
  flex: 0 0 auto;
}
.escolha-papel-texto {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.35;
}
.escolha-papel-nome {
  font-weight: 600;
}
.escolha-papel-resumo {
  font-size: .8125rem;
  color: var(--bs-secondary-color);
}

/* Senha provisória, para ser ditada por telefone sem erro.
   Monoespaçada e espaçada: em fonte de texto, "PQ2S" e "P02S" se
   confundem, e senha digitada errada três vezes acaba anotada em papel
   colado no monitor. */
.senha-provisoria {
  display: inline-block;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 1.35rem;
  font-weight: 700;
  letter-spacing: .12em;
  padding: .4rem .75rem;
  border-radius: var(--bs-border-radius);
  background: var(--bs-body-bg);
  border: 1px dashed var(--bs-border-color);
  user-select: all;
}

/* ---- Lista de ficha (rótulo em cima, valor embaixo) ----
   Substitui o `<dl class="row">` com `col-4`/`col-8` que as fichas usavam:
   com rótulo curto e valor longo (endereço, e-mail), a grade de duas
   colunas quebrava o valor em três linhas dentro de metade do cartão. */
.ficha-lista > dt {
  font-size: .72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--bs-secondary-color);
  margin-bottom: .1rem;
}
.ficha-lista > dd {
  margin: 0 0 .85rem;
  font-size: .9rem;
  line-height: 1.45;
  overflow-wrap: anywhere;
}
.ficha-lista > dd:last-child {
  margin-bottom: 0;
}

/* ---- Estado vazio ----
   Separa "ainda não cadastrou" de "o filtro escondeu tudo": são problemas
   diferentes e a saída de cada um é diferente. Tabela com a frase
   "nenhum registro" e nada mais deixa o operador sem próximo passo. */
.estado-vazio {
  padding: 3rem 1.5rem;
  text-align: center;
}
.estado-vazio > .bi {
  display: block;
  font-size: 2.25rem;
  line-height: 1;
  color: var(--bs-secondary-color);
  opacity: .45;
  margin-bottom: .85rem;
}
.estado-vazio-titulo {
  font-weight: 600;
  margin: 0 0 .3rem;
}
.estado-vazio-detalhe {
  font-size: .875rem;
  color: var(--bs-secondary-color);
  max-width: 32rem;
  margin: 0 auto 1.1rem;
  line-height: 1.5;
}

/* ---- Barra de seleção ---- */
.barra-selecao {
  position: sticky;
  bottom: 1rem;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: .75rem;
  margin-top: 1rem;
  padding: .6rem 1rem;
  background: var(--bs-emphasis-color);
  color: var(--bs-body-bg);
  border-radius: 999px;
  box-shadow: 0 .5rem 1.5rem rgba(0, 0, 0, .25);
}
.barra-selecao .selecao-contador {
  font-size: .875rem;
}
.barra-selecao .btn-link {
  color: var(--bs-body-bg);
  opacity: .75;
  font-size: .8125rem;
  padding: 0;
}
.barra-selecao .btn-link:hover {
  opacity: 1;
}

/* Rodapé fixo do formulário longo, para o botão salvar não fugir da tela. */
.acoes-fixas {
  position: sticky;
  bottom: 0;
  background: var(--bs-body-bg);
  border-top: 1px solid var(--bs-border-color);
  padding: .75rem 0;
  margin-top: 1rem;
  z-index: 5;
}

@media print {
  .app-sidebar, .app-header, .app-footer, .acoes-fixas, .no-print { display: none !important; }
  .app-main { margin-left: 0 !important; }
}
