/* Sistema JOÃO — estilos base, sobre os tokens oficiais (tokens.css). */

@import url('https://fonts.googleapis.com/css2?family=Sora:wght@600;700&family=Inter:wght@400;500;600;700&display=swap');

* { box-sizing: border-box; }

/*
  O atributo `hidden` tem que ganhar de qualquer classe.
  A folha do navegador declara [hidden]{display:none} com especificidade 0,1,0
  — a mesma de uma classe — e a regra do autor vence por vir depois. Já mordeu
  duas vezes aqui: o estado vazio do Relatório e a barra de seleção do
  repositório apareciam com `hidden` no HTML. Este é o mesmo remédio que o
  Mesmo remédio que o normalize.css usa.
*/
[hidden] { display: none !important; }

/*
  ══════════════════════════════════════════════════════════════════════
  ESCALA DE PONTOS DE QUEBRA — duas larguras, e só
  ══════════════════════════════════════════════════════════════════════
  Antes havia dez (380, 420, 480, 560, 640, 720, 760, 860, 900, 980): cada
  tela inventou a sua, e entre 640 e 900px o sistema mudava de comportamento
  quatro vezes. Agora:

    max-width: 900px  → MODO COMPACTO
                        gaveta no menu · tabelas viram cartões ·
                        formulários em uma coluna
    max-width: 640px  → ajuste fino dentro do compacto
                        empilha o que ainda estava 2-up

  Tablet em retrato (768px) é compacto de propósito: com a rail de 200px
  sobrariam 568px de conteúdo, apertado para qualquer uma das listas. Em
  paisagem (1024px) entra no modo amplo, com rail e tabelas.

  Alvo de toque NÃO usa largura: (pointer: coarse) vale em qualquer tamanho,
  porque um tablet de 1024px com dedo continua precisando de 44px.

  PontosDeQuebraTests reprova qualquer largura fora desta escala.
*/

body {
  margin: 0;
  font-family: var(--joao-font-body);
  background: var(--joao-bg);
  color: var(--joao-text);
  font-size: 15px;
  line-height: 1.5;
}

h1, h2, h3, .titulo {
  font-family: var(--joao-font-display);
  color: var(--joao-primary-900);
  margin: 0 0 .5rem;
}

a { color: var(--joao-ink-action); }

/*
  ── Casca da aplicação: "Registro" ──
  Linguagem de livro-ata/razão paroquial, não dashboard SaaS genérico.
  Rail estreita com abas tipo divisória de fichário (aba ativa ganha uma
  fita marcadora à esquerda, como marcador de página de Bíblia) + filete
  duplo como motivo recorrente de seção (referência a pauta/linha de livro
  contábil). Cores e raios seguem os tokens já aprovados — só a composição
  é nova.
*/
.app-shell { display: flex; min-height: 100vh; }

.rail {
  width: 200px;
  flex-shrink: 0;
  background: var(--joao-bg);
  border-right: 1px solid var(--joao-border);
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: 1rem 0;
}
.rail::after {
  content: '';
  position: absolute;
  top: 0; bottom: 0; right: -4px;
  width: 1px;
  background: color-mix(in srgb, var(--joao-border) 70%, transparent);
}
/*
  Marca do sistema na rail. Antes era só o símbolo de 30px: nada na tela
  dizia o nome do produto. Com a rail em 200px cabe a assinatura inteira.
  A tinta vem de --joao-primary-900, que já inverte entre os temas — por
  isso o SVG é embutido (ver _MarcaCompacta.cshtml), não <img>.
*/
.rail__brand {
  display: block;
  /* Limitada: esticando de ponta a ponta da rail, a marca competia com os
     módulos. Em 152px o "JOÃO" ainda fica com ~22px de altura de caixa. */
  max-width: 152px;
  margin: .35rem .9rem 1rem;
  padding: .3rem .35rem 1rem;
  border-bottom: 1px solid var(--joao-border);
  color: var(--joao-primary-900);
}
.rail__brand:hover { color: var(--joao-ink-action); }
.rail__brand:focus-visible { outline: 2px solid var(--joao-focus-cor); outline-offset: 2px; }
.marca-compacta {
  display: block;
  width: 100%;
  height: auto;
  /* O til do Ã encosta no topo do viewBox; um respiro evita corte visual. */
  overflow: visible;
}

.rail__nav { display: flex; flex-direction: column; width: 100%; }
.rail__item {
  display: flex;
  align-items: center;
  gap: .6rem;
  width: 100%;
  min-height: 42px;
  padding: .5rem .9rem;
  border-left: 3px solid transparent;
  color: var(--joao-text-muted);
  text-decoration: none;
}
.rail__item-monograma { font-family: var(--joao-font-display); font-weight: 700; font-size: .8rem; letter-spacing: .03em; }
.rail__item-rotulo { font-size: .58rem; text-transform: uppercase; letter-spacing: .06em; text-align: center; line-height: 1.1; }
.rail__item:hover { color: var(--joao-primary-900); background: var(--joao-tint-neutro); }
.rail__item.active {
  border-left-color: var(--joao-secondary-500);
  background: var(--joao-surface);
  color: var(--joao-primary-900);
}
.rail__item.disabled { opacity: .35; cursor: default; }
.rail__item.disabled:hover { background: none; color: var(--joao-text-muted); }

.topbar {
  height: 56px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: .75rem;
  padding: 0 1.5rem;
  background: var(--joao-surface);
  border-bottom: 1px solid var(--joao-border);
}
.topbar__user { position: relative; }
.topbar__user-btn {
  display: flex;
  align-items: center;
  gap: .4rem;
  padding: .35rem .8rem;
  border-radius: var(--joao-radius-md);
  border: 1px solid var(--joao-border);
  background: transparent;
  color: var(--joao-text);
  font-size: .85rem;
  font-family: inherit;
  cursor: pointer;
}
.topbar__user-btn:hover { border-color: var(--joao-action); color: var(--joao-ink-action); }
.topbar__user-menu {
  position: absolute;
  right: 0;
  top: calc(100% + .5rem);
  background: var(--joao-surface);
  border-radius: var(--joao-radius-md);
  box-shadow: var(--joao-shadow-card);
  min-width: 170px;
  padding: .4rem;
  display: none;
  z-index: 20;
}
.topbar__user-menu.open { display: block; }
.topbar__user-menu a, .topbar__user-menu button {
  display: block;
  width: 100%;
  text-align: left;
  padding: .5rem .6rem;
  border-radius: var(--joao-radius-sm);
  color: var(--joao-text);
  text-decoration: none;
  background: none;
  border: none;
  font: inherit;
  cursor: pointer;
}
.topbar__user-menu a:hover, .topbar__user-menu button:hover { background: var(--joao-bg); }

.app-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.app-content { padding: 1.75rem 2rem; max-width: 100%; }

/* ── Cabeçalho de página: versalete + filete duplo (motivo de livro-ata) ── */
.page-header { position: relative; padding-bottom: 1rem; margin-bottom: 1.5rem; border-bottom: 1px solid var(--joao-primary-900); }
.page-header::after { content: ''; position: absolute; left: 0; right: 0; bottom: -4px; height: 1px; background: var(--joao-border); }
.page-header__linha { display: flex; justify-content: space-between; align-items: flex-end; gap: 1rem; flex-wrap: wrap; }
.page-header__eyebrow { text-transform: uppercase; letter-spacing: .12em; font-size: .7rem; font-weight: 700; color: var(--joao-ink-action); margin: 0 0 .3rem; }
.page-header h1 { font-size: 1.4rem; margin: 0; }
.page-header .subtitulo { color: var(--joao-text-muted); font-size: .86rem; margin: .2rem 0 0; }
.page-header__acoes { display: flex; align-items: center; gap: .75rem; }
.page-header__busca input { min-width: 260px; }

/* ── Tabela de registro (listagens de cadastro) ── */
.tabela-scroll { overflow-x: auto; }
.tabela-registro { width: 100%; min-width: 640px; border-collapse: collapse; font-size: .88rem; }
.tabela-registro th {
  text-align: left;
  text-transform: uppercase;
  letter-spacing: .06em;
  font-size: .68rem;
  color: var(--joao-text-muted);
  font-weight: 700;
  padding: 0 .5rem .6rem;
  border-bottom: 2px solid var(--joao-primary-900);
}
.tabela-registro td { padding: .7rem .5rem; border-bottom: 1px solid var(--joao-border); vertical-align: middle; }
.tabela-registro__acoes { display: flex; gap: .75rem; white-space: nowrap; }

.tabela-registro__acoes button:hover, .tabela-registro__acoes a:hover { text-decoration: underline; }

.badge { display: inline-block; padding: .1rem .5rem; border-radius: var(--joao-radius-sm); font-size: .72rem; font-weight: 600; margin-left: .4rem; }
.badge-sucesso { background: rgba(47,133,90,.12); color: var(--joao-success); }
.badge-inativo { background: rgba(98,125,152,.15); color: var(--joao-text-muted); }

.paginacao { display: flex; gap: .4rem; margin-top: 1.25rem; }
.paginacao a {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 32px; height: 32px; padding: 0 .4rem;
  border: 1px solid var(--joao-border); border-radius: var(--joao-radius-sm);
  color: var(--joao-text); text-decoration: none; font-size: .85rem;
}
.paginacao a.active { font-weight: 700; }

/* ── Cards (uso pontual — formulários, blocos avulsos) ── */
.card {
  background: var(--joao-surface);
  border-radius: var(--joao-radius-md);
  box-shadow: var(--joao-shadow-card);
  padding: 1.25rem;
}
.card + .card { margin-top: 1rem; }

/* ── Relatórios: cabeçalho institucional + grade de cards ── */
.relatorio-header {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding-bottom: 1.25rem;
  margin-bottom: 1.5rem;
  border-bottom: 2px solid var(--joao-primary-900);
}
.relatorio-header img { height: 48px; width: auto; }
.relatorio-header h1 { margin-bottom: .1rem; }
.relatorio-header .subtitulo { margin: 0; }

.relatorio-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 1rem; }
.relatorio-card__titulo {
  font-family: var(--joao-font-display);
  font-weight: 700;
  font-size: 1rem;
  color: var(--joao-primary-900);
  margin-bottom: .75rem;
  padding-bottom: .5rem;
  border-bottom: 1px solid var(--joao-border);
}
.relatorio-card__linha {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: .5rem;
  padding: .35rem 0;
  font-size: .85rem;
}
.relatorio-card__linha strong { font-family: var(--joao-font-display); color: var(--joao-primary-900); }

/* ── Indicadores em formato de lançamento (não cards soltos) ── */
.ledger { border-top: 2px solid var(--joao-primary-900); max-width: 520px; }
.ledger__linha {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  padding: .9rem .1rem;
  border-bottom: 1px solid var(--joao-border);
}
.ledger__rotulo { font-size: .9rem; color: var(--joao-text); }
.ledger__valor {
  font-family: var(--joao-font-display);
  font-weight: 700;
  font-size: 1.55rem;
  color: var(--joao-primary-900);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/*
  ══════════════════════════════════════════════════════════════════════
  DASHBOARD
  ══════════════════════════════════════════════════════════════════════
  A versão anterior era monocromática e sem escala: seis caixas brancas
  iguais, duas polilinhas sem grade nem valor, e listas de números onde
  cabia comparação visual. Dava pra ler, não dava pra enxergar.

  Agora cada módulo tem uma cor fixa da série (--joao-serie-*), os
  gráficos têm grade, área, ponto e valor, e toda lista que compara
  grandeza virou barra proporcional. A cor identifica; o rótulo e o
  número continuam dizendo o quê e quanto — nada depende só da cor.
*/
.dashboard-header__atualizacao { margin: 0; color: var(--joao-text-muted); font-size: var(--joao-fs-sm); }

/* ── Pulso: a linha de indicadores do topo ── */
/*
  Flex, não grid: o número de indicadores varia de 1 a 6 conforme a permissão
  do usuário. Com grid auto-fit, uma sobra na última fileira ficava estreita
  ao lado de trilhas vazias — parecia defeito. Com flex-grow, o que sobra
  estica e ocupa a linha inteira, então qualquer contagem fecha certo.
*/
.dashboard-pulso {
  display: flex;
  flex-wrap: wrap;
  gap: var(--joao-space-3);
  margin-bottom: var(--joao-space-5);
}
.pulso-item {
  --pulso-cor: var(--joao-serie-1);
  flex: 1 1 165px;
  display: flex;
  flex-direction: column;
  gap: .2rem;
  min-height: 128px;
  min-width: 0;
  padding: .95rem 1rem;
  background: var(--joao-surface);
  border: 1px solid var(--joao-border);
  border-top: 3px solid var(--pulso-cor);
  border-radius: var(--joao-radius-md);
  box-shadow: var(--joao-shadow-sm);
  color: var(--joao-text);
  text-decoration: none;
  transition: box-shadow .16s ease, transform .16s ease, border-color .16s ease;
}
.pulso-item:hover { box-shadow: var(--joao-shadow-card); transform: translateY(-2px); }
.pulso-item:focus-visible { outline: 2px solid var(--joao-focus-cor); outline-offset: 2px; }
.pulso-item__rotulo, .dashboard-secao__sobretitulo {
  color: var(--joao-text-muted);
  font-size: var(--joao-fs-micro);
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
}
.pulso-item strong {
  color: var(--pulso-cor);
  font-family: var(--joao-font-display);
  font-size: 1.75rem;
  font-variant-numeric: tabular-nums;
  line-height: 1.25;
  overflow-wrap: anywhere;
}
.pulso-item__nota { margin-top: auto; color: var(--joao-text-muted); font-size: var(--joao-fs-sm); }

.pulso-item--s1 { --pulso-cor: var(--joao-serie-1); }
.pulso-item--s2 { --pulso-cor: var(--joao-serie-2); }
.pulso-item--s3 { --pulso-cor: var(--joao-serie-3); }
.pulso-item--s4 { --pulso-cor: var(--joao-serie-4); }
.pulso-item--s5 { --pulso-cor: var(--joao-serie-5); }
.pulso-item--s6 { --pulso-cor: var(--joao-serie-6); }
/* Saldo negativo troca de cor E o rótulo já diz "Saldo do mês" com o sinal. */
.pulso-item--negativo { --pulso-cor: var(--joao-fluxo-saida); }

/* ── Grade de seções ── */
.dashboard-grade {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--joao-space-4);
  align-items: start;
}
.dashboard-secao {
  min-width: 0;
  padding: 1.15rem;
  background: var(--joao-surface);
  border: 1px solid var(--joao-border);
  border-radius: var(--joao-radius-md);
  box-shadow: var(--joao-shadow-card);
}
.dashboard-secao--ampla { grid-column: span 2; }
.dashboard-secao__cabecalho {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
  padding-bottom: .75rem;
  border-bottom: 1px solid var(--joao-border);
}
.dashboard-secao__cabecalho h2 { font-size: var(--joao-fs-h2); margin: .15rem 0 0; }
/* 20px de altura reprova o alvo minimo de 24px (WCAG 2.2 2.5.8); o link de
   atalho do cabecalho ganha area propria em vez de ser so texto. */
.dashboard-secao__cabecalho > a {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  padding: .25rem .5rem;
  margin: -.25rem -.5rem;
  border-radius: var(--joao-radius-sm);
  color: var(--joao-ink-action);
  font-size: var(--joao-fs-sm);
  font-weight: 600;
}
.dashboard-secao__cabecalho > a:hover { background: var(--joao-tint-action); }
@media (pointer: coarse) { .dashboard-secao__cabecalho > a { min-height: var(--joao-touch-min); } }
.dashboard-secao__numero {
  flex-shrink: 0;
  padding: .15rem .6rem;
  border-radius: var(--joao-radius-pill);
  background: var(--joao-tint-action);
  color: var(--joao-ink-action);
  font-size: var(--joao-fs-sm);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ── Legenda ── */
.dashboard-legenda {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem 1rem;
  margin: 0 0 .75rem;
  color: var(--joao-text-muted);
  font-size: var(--joao-fs-sm);
}
.legenda-item { display: inline-flex; align-items: center; gap: .4rem; }
.legenda { width: 14px; height: 4px; display: inline-block; border-radius: var(--joao-radius-pill); }
.legenda--entrada, .legenda--presente { background: var(--joao-fluxo-entrada); }
.legenda--saida { background: var(--joao-fluxo-saida); }
.legenda--visitante { background: var(--joao-serie-3); }

/* ── Gráficos SVG ── */
/*
  O SVG mantém proporção, então num celular de 375px ele cairia para ~90px de
  altura e os rótulos ficariam ilegíveis. Em vez de distorcer com
  preserveAspectRatio="none", o gráfico rola na própria superfície no modo
  compacto — mesma estratégia já usada nas tabelas. Os valores exatos continuam
  disponíveis sem rolagem, no <details> logo abaixo.
*/
.dashboard-grafico-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.dashboard-grafico { display: block; width: 100%; height: auto; overflow: visible; }
@media (max-width: 900px) {
  .dashboard-grafico { min-width: 520px; }
}
.dashboard-grafico__grade { stroke: var(--joao-grade-grafico); stroke-width: 1; }
.dashboard-grafico__eixo { stroke: var(--joao-border); stroke-width: 1; }
.dashboard-grafico__linha { fill: none; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
.dashboard-grafico__linha--entrada { stroke: var(--joao-fluxo-entrada); }
.dashboard-grafico__linha--saida { stroke: var(--joao-fluxo-saida); }
/* A área dá peso ao gráfico sem esconder a série de baixo. */
.dashboard-grafico__area { stroke: none; }
.dashboard-grafico__area--entrada { fill: color-mix(in srgb, var(--joao-fluxo-entrada) var(--joao-area-opacidade), transparent); }
.dashboard-grafico__area--saida { fill: color-mix(in srgb, var(--joao-fluxo-saida) var(--joao-area-opacidade-fraca), transparent); }
.dashboard-grafico__ponto { stroke: var(--joao-surface); stroke-width: 2; }
.dashboard-grafico__ponto--entrada { fill: var(--joao-fluxo-entrada); }
.dashboard-grafico__ponto--saida { fill: var(--joao-fluxo-saida); }
.dashboard-grafico__barra--presente { fill: var(--joao-fluxo-entrada); }
.dashboard-grafico__barra--visitante { fill: var(--joao-serie-3); }
.dashboard-grafico__rotulo, .dashboard-grafico__escala, .dashboard-grafico__valor {
  fill: var(--joao-text-muted);
  font-family: var(--joao-font-body);
}
.dashboard-grafico__rotulo { font-size: 13px; }
.dashboard-grafico__escala { font-size: 11px; }
.dashboard-grafico__valor { font-size: 12px; font-weight: 700; fill: var(--joao-text); }

/* Tabela de valores exatos sob o gráfico — a forma é do gráfico, o número é dela. */
.dashboard-tabela { margin-top: 1rem; }
.dashboard-tabela > summary {
  cursor: pointer;
  padding: .4rem 0;
  color: var(--joao-ink-action);
  font-size: var(--joao-fs-sm);
  font-weight: 600;
}
.dashboard-tabela > summary:focus-visible { outline: 2px solid var(--joao-focus-cor); outline-offset: 2px; border-radius: var(--joao-radius-sm); }
.tabela-registro--compacta { min-width: 460px; font-size: var(--joao-fs-sm); }
.tabela-registro .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.tabela-registro .num--positivo { color: var(--joao-success-ink); }
.tabela-registro .num--negativo { color: var(--joao-danger-ink); }

/* ── Barras horizontais (composição de entradas) ── */
.dashboard-barras { margin: 0; padding: 0; list-style: none; display: grid; gap: .85rem; }
.dashboard-barra {
  --barra-cor: var(--joao-serie-1);
  display: grid;
  grid-template-columns: 1fr auto;
  gap: .2rem .75rem;
}
.dashboard-barra__rotulo { font-size: var(--joao-fs-base); font-weight: 600; overflow-wrap: anywhere; }
.dashboard-barra__valor {
  color: var(--joao-primary-900);
  font-family: var(--joao-font-display);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.dashboard-barra__trilho {
  grid-column: 1 / -1;
  height: 8px;
  border-radius: var(--joao-radius-pill);
  background: var(--joao-gray-100);
  overflow: hidden;
}
/* A largura vem do dado, via --valor no atributo; a regra mora aqui. */
.dashboard-barra__preenche { display: block; height: 100%; width: var(--valor, 0%); background: var(--barra-cor); border-radius: inherit; }
.dashboard-barra__fatia { grid-column: 1 / -1; color: var(--joao-text-muted); font-size: var(--joao-fs-micro); font-variant-numeric: tabular-nums; }
.dashboard-barra--s1 { --barra-cor: var(--joao-serie-1); }
.dashboard-barra--s2 { --barra-cor: var(--joao-serie-2); }
.dashboard-barra--s3 { --barra-cor: var(--joao-serie-3); }
.dashboard-barra--s4 { --barra-cor: var(--joao-serie-4); }
.dashboard-barra--s5 { --barra-cor: var(--joao-serie-5); }
.dashboard-barra--s6 { --barra-cor: var(--joao-serie-6); }

/* ── Funil de consolidação ── */
.dashboard-funil { margin: 0; padding: 0; list-style: none; counter-reset: funil; display: grid; gap: .7rem; }
.dashboard-funil li {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: .65rem;
}
.dashboard-funil li::before {
  counter-increment: funil;
  content: counter(funil, decimal-leading-zero);
  color: var(--joao-ink-action);
  font-size: var(--joao-fs-micro);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.dashboard-funil__rotulo { grid-column: 2; font-size: var(--joao-fs-base); }
.dashboard-funil strong {
  grid-column: 3;
  grid-row: 1 / span 2;
  color: var(--joao-primary-900);
  font-family: var(--joao-font-display);
  font-size: var(--joao-fs-lg);
  font-variant-numeric: tabular-nums;
}
.dashboard-funil__trilho {
  grid-column: 2;
  height: 7px;
  border-radius: var(--joao-radius-pill);
  background: var(--joao-gray-100);
  overflow: hidden;
}
.dashboard-funil__preenche { display: block; height: 100%; width: var(--valor, 0%); background: var(--joao-serie-2); border-radius: inherit; }

/* ── Listas simples ── */
.dashboard-lista-valor { margin: 0; padding: 0; list-style: none; }
.dashboard-lista-valor li {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: .55rem 0;
  border-bottom: 1px solid var(--joao-border);
  font-size: var(--joao-fs-base);
}
.dashboard-lista-valor li:last-child { border-bottom: 0; }
.dashboard-lista-valor strong { color: var(--joao-primary-900); font-family: var(--joao-font-display); font-variant-numeric: tabular-nums; }

/* ── Agenda ── */
.dashboard-agenda { margin: 0; padding: 0; list-style: none; }
.dashboard-agenda li {
  display: grid;
  grid-template-columns: 42px 1fr auto;
  align-items: center;
  gap: .8rem;
  padding: .7rem 0;
  border-bottom: 1px solid var(--joao-border);
}
.dashboard-agenda li:last-child { border-bottom: 0; }
.dashboard-agenda time {
  display: grid;
  place-items: center;
  padding: .3rem 0;
  border-radius: var(--joao-radius-sm);
  background: var(--joao-tint-action);
  color: var(--joao-ink-action);
  font-family: var(--joao-font-display);
  line-height: 1.1;
}
.dashboard-agenda time b { display: block; font-size: 1.1rem; }
.dashboard-agenda time span { font-size: .64rem; text-transform: uppercase; }
.dashboard-agenda > li > div { min-width: 0; display: flex; flex-direction: column; }
.dashboard-agenda strong { color: var(--joao-primary-900); font-size: var(--joao-fs-base); overflow-wrap: anywhere; }
.dashboard-agenda > li > div span { color: var(--joao-text-muted); font-size: var(--joao-fs-sm); margin-top: .1rem; }
.dashboard-agenda__vagas { display: flex; flex-direction: column; align-items: flex-end; gap: .25rem; width: 76px; flex-shrink: 0; color: var(--joao-text-muted); font-size: var(--joao-fs-micro); font-variant-numeric: tabular-nums; }
.dashboard-agenda__trilho { width: 100%; height: 5px; border-radius: var(--joao-radius-pill); background: var(--joao-gray-100); overflow: hidden; }
.dashboard-agenda__preenche { display: block; height: 100%; width: var(--valor, 0%); background: var(--joao-serie-2); border-radius: inherit; }

/* ── Pendências ── */
.dashboard-secao--atencao { border-top: 3px solid var(--joao-serie-3); }
.dashboard-alertas { margin: 0; padding: 0; list-style: none; }
.dashboard-alertas li { border-bottom: 1px solid var(--joao-border); }
.dashboard-alertas li:last-child { border-bottom: 0; }
.dashboard-alertas a {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: .75rem;
  padding: .7rem 0;
  color: var(--joao-text);
  text-decoration: none;
}
.dashboard-alertas a:hover span:not(.dashboard-alertas__selo) { text-decoration: underline; }
.dashboard-alertas a:focus-visible { outline: 2px solid var(--joao-focus-cor); outline-offset: 2px; border-radius: var(--joao-radius-sm); }
.dashboard-alertas strong {
  min-width: 2ch;
  color: var(--joao-warning-ink);
  font-family: var(--joao-font-display);
  font-size: var(--joao-fs-lg);
  font-variant-numeric: tabular-nums;
}
.dashboard-alertas span { font-size: var(--joao-fs-base); }
/* Selo: a severidade tem palavra, não só cor. */
.dashboard-alertas__selo {
  flex-shrink: 0;
  padding: .12rem .55rem;
  border-radius: var(--joao-radius-pill);
  background: var(--joao-tint-neutro);
  color: var(--joao-text-muted);
  font-size: var(--joao-fs-micro) !important;
  font-weight: 700;
  white-space: nowrap;
}
.dashboard-alertas .is-grave strong { color: var(--joao-danger-ink); }
.dashboard-alertas .is-grave .dashboard-alertas__selo { background: var(--joao-tint-danger); color: var(--joao-danger-ink); }
.dashboard-tudo-em-dia {
  display: flex;
  align-items: center;
  gap: .55rem;
  margin: 0;
  padding: .8rem 1rem;
  border-radius: var(--joao-radius-sm);
  background: var(--joao-tint-success);
  color: var(--joao-success-ink);
  font-size: var(--joao-fs-base);
  font-weight: 600;
}
.dashboard-tudo-em-dia::before {
  content: '\2713';
  display: grid;
  place-items: center;
  width: 1.35rem; height: 1.35rem;
  flex-shrink: 0;
  border: 2px solid currentColor;
  border-radius: 50%;
  font-size: .8rem;
}

.dashboard-texto-vazio { color: var(--joao-text-muted); font-size: var(--joao-fs-base); }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }

@media (max-width: 900px) {
  .dashboard-grade { grid-template-columns: 1fr; }
  .dashboard-secao--ampla { grid-column: span 1; }
}
@media (max-width: 640px) {
  .pulso-item {
    /* EXCEÇÃO ao "empilha o que ainda estava 2-up" do cabeçalho: esta é a
       única regra de 640px que CRIA o 2-up em vez de desfazê-lo. O pulso
       já era 2-up de 380 a 560px antes da consolidação; sem ela, empilhar
       em 640px dobraria a rolagem do Dashboard num celular comum.

       gap entra uma vez entre dois itens, então cada um vale metade dele.
       O piso de 168px reconstrói o antigo ponto de quebra de 380px sem
       criar um: 2×168+12 = 348, então abaixo de 348px de faixa útil
       (= 380px de viewport, com o padding de 1rem do .app-content) não
       cabem dois e o flex-wrap empilha sozinho. Em 375px dá 1-up e em
       414px dá 2-up, que é o que o bloco de 380px fazia. O valor em
       moeda não cabia em ~138px de cartão — foi por isso que o bloco de
       380px existiu (commit 87b0d61). */
    flex-basis: calc(50% - var(--joao-space-3) / 2);
    min-width: 168px;
    min-height: 112px;
    padding: .8rem;
  }
  .pulso-item strong { font-size: 1.45rem; }
  .dashboard-secao__cabecalho { flex-direction: column; gap: .5rem; }
  .dashboard-agenda li { grid-template-columns: 42px 1fr; }
  .dashboard-agenda__vagas { grid-column: 2; align-items: flex-start; width: 100%; }
  .dashboard-alertas a { grid-template-columns: auto 1fr; }
  .dashboard-alertas__selo { grid-column: 2; justify-self: start; }
}

/* ── Formulários ── */
.form-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0 1.5rem; max-width: 860px; }
.configuracao-layout { display:grid; grid-template-columns:minmax(0, 860px) minmax(220px, 280px); gap:1.5rem; align-items:start; }
.configuracao-preview { position:sticky; top:1.25rem; padding:1.15rem; background:var(--joao-surface); border:1px solid var(--joao-border); border-top:3px solid var(--joao-secondary-500); border-radius:var(--joao-radius-md); box-shadow:var(--joao-shadow-card); }
.configuracao-preview h2 { margin:.15rem 0 1rem; font-size:1.05rem; }
.configuracao-preview__canvas { display:flex; align-items:center; justify-content:center; min-height:130px; padding:1rem; margin-bottom:.75rem; background:var(--joao-primary-900); border-radius:var(--joao-radius-sm); }
.configuracao-preview__canvas img { display:block; max-width:100%; max-height:90px; width:auto; height:auto; object-fit:contain; }
.configuracao-preview strong { display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:.85rem; }
@media (max-width: 900px) { .configuracao-layout { grid-template-columns:minmax(0, 1fr); } .configuracao-preview { position:static; order:-1; } .configuracao-preview__canvas { min-height:100px; } }
.sermao-resumo { min-height: 220px; line-height: 1.65; resize: vertical; }
.sermao-painel { padding:1.2rem; margin-top:1.5rem; background:var(--joao-surface); border:1px solid var(--joao-border); border-top:3px solid var(--joao-accent-500); border-radius:var(--joao-radius-md); box-shadow:var(--joao-shadow-card); }
.sermao-biblia { margin-top:1rem; padding:1rem; background:color-mix(in srgb, var(--joao-secondary-500) 8%, transparent); border:1px solid color-mix(in srgb, var(--joao-secondary-500) 35%, var(--joao-border)); border-radius:var(--joao-radius-sm); }
.sermao-biblia__busca { display:grid; grid-template-columns:minmax(0,2fr) minmax(160px,1.25fr) 110px auto auto; gap:.75rem; align-items:end; width:100%; }.sermao-biblia__busca .form-group { min-width:0; margin-bottom:0; }.sermao-biblia__busca input, .sermao-biblia__busca select { min-width:0; box-sizing:border-box; }
.sermao-painel__cabecalho { display:flex; justify-content:space-between; align-items:start; gap:1rem; }.sermao-painel h2 { margin:.1rem 0 .25rem; font-size:1.15rem; }.sermao-contador { color:var(--joao-ink-action); font-family:var(--joao-font-display); font-size:1.4rem; font-weight:800; }
.sermao-referencia-form { display:flex; gap:.75rem; align-items:end; max-width:700px; }.sermao-referencia-form input { flex:1; }.sermao-referencia-lista { display:flex; flex-wrap:wrap; gap:.5rem; margin-top:1rem; }.sermao-referencia { display:flex; align-items:center; gap:.4rem; padding:.45rem .65rem; border:1px solid var(--joao-border); border-radius:99px; color:var(--joao-primary-900); font-weight:600; }.sermao-referencia button { border:0; background:none; color:var(--joao-danger); font-size:1.2rem; cursor:pointer; }
.sermao-topicos-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(300px,1fr)); gap:1rem; }.sermao-topico-card { padding:1rem; background:var(--joao-surface); border:1px solid var(--joao-border); border-radius:var(--joao-radius-md); box-shadow:var(--joao-shadow-card); }.sermao-topico-card__numero { color:var(--joao-ink-action); font-family:var(--joao-font-display); font-weight:800; }.sermao-topico-card__titulo { display:flex; justify-content:space-between; gap:.75rem; align-items:baseline; margin:.25rem 0 1rem; }.sermao-topico-card__titulo h3 { margin:0; font-size:1rem; }.sermao-topico-card__titulo span { color:var(--joao-text-muted); font-size:.75rem; white-space:nowrap; }.sermao-cronometro { padding:.9rem; background:var(--joao-palco); border-radius:var(--joao-radius-sm); color:var(--joao-on-palco); }.sermao-cronometro strong { display:block; font-family:var(--joao-font-display); font-size:2.1rem; letter-spacing:.08em; text-align:center; }.sermao-cronometro__barra { height:6px; margin:.55rem 0 .8rem; background:var(--joao-palco-trilho); border-radius:99px; overflow:hidden; }.sermao-cronometro__barra span { display:block; height:100%; width:0; background:var(--joao-secondary-500); transition:width .3s linear; }.sermao-cronometro__acoes { display:flex; flex-wrap:wrap; gap:.5rem; align-items:center; }.sermao-cronometro__acoes .btn-outline { color:var(--joao-bg); border-color:rgba(255,255,255,.35); }.sermao-cronometro__acoes form { margin-left:auto; }.sermao-topico-form { max-width:860px; }
@media (max-width: 900px) { .sermao-biblia__busca { grid-template-columns:1fr 1fr; }.sermao-biblia__termo { grid-column:span 2; }.sermao-biblia__busca .btn { width:100%; }.sermao-biblia__verso { display:block; }.sermao-biblia__verso .btn { width:100%; margin-top:.55rem; }.sermao-referencia p { max-height:8rem; overflow:auto; } }
@media (max-width: 640px) { .sermao-referencia-form { flex-direction:column; align-items:stretch; }.sermao-cronometro__acoes form { margin-left:0; width:100%; }.sermao-cronometro__acoes form button { width:100%; }.sermao-topico-card__titulo { flex-direction:column; gap:.2rem; }.sermao-biblia__busca { grid-template-columns:1fr; }.sermao-biblia__termo { grid-column:auto; }.sermao-biblia__cabecalho { display:block; }.sermao-biblia__versao { text-align:left; } }
.form-span-2 { grid-column: span 2; }
.form-check label { display: flex; align-items: center; gap: .4rem; font-weight: 400; }
.form-check input[type="checkbox"] { width: auto; }

/* ── Abas dentro de um formulário (Configurações) ──
   A aba ativa é marcada por DUAS coisas: a cor da tinta e o filete de 3px
   embaixo. O filete não é enfeite — cor sozinha não distingue estado para
   quem não separa esses dois tons, e a WCAG 2.2 pede o indicador não
   cromático (§1.4.1).

   A tira rola sozinha no eixo X em vez de ganhar um ponto de quebra próprio:
   quatro rótulos longos ("Envio de e-mail (SMTP)") não cabem em 375px, e
   empilhar viraria um menu de quatro linhas ocupando meia tela antes do
   primeiro campo. `overflow-x` mantém o estouro DENTRO da tira, nunca na
   página. */
.abas {
  display: flex;
  gap: .15rem;
  margin: 0 0 1.5rem;
  padding: 0;
  border-bottom: 2px solid var(--joao-border);
  overflow-x: auto;
  scrollbar-width: thin;
}
.abas__item {
  flex: 0 0 auto;
  padding: .7rem 1.05rem;
  background: transparent;
  border: 0;
  border-bottom: 3px solid transparent;
  margin-bottom: -2px;
  color: var(--joao-text-muted);
  font-family: inherit;
  font-size: .9rem;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}
.abas__item:hover { color: var(--joao-text); background: var(--joao-tint-neutro); }
.abas__item[aria-selected="true"] {
  color: var(--joao-ink-action);
  border-bottom-color: var(--joao-action);
}
.abas__item:focus-visible {
  outline: 2px solid var(--joao-focus-cor);
  outline-offset: -2px;
  border-radius: var(--joao-radius-sm) var(--joao-radius-sm) 0 0;
}
/* O painel recebe foco programático na troca de aba; o anel do container
   inteiro seria uma moldura na tela toda, então some sem tirar o foco. */
.aba-painel:focus { outline: none; }
/* Ação secundária colada ao bloco que ela complementa — separada por filete,
   não por cartão novo: é a mesma decisão, não outro assunto. */
.acao-embutida {
  margin-top: var(--joao-space-4);
  padding-top: var(--joao-space-3);
  border-top: 1px solid var(--joao-border);
}
.acao-embutida .form-hint { margin-top: var(--joao-space-2); }

/* ── Painel de depreciação (Patrimônio) ──
   Superfície própria, não `.card`: ele vive DENTRO da grade do formulário e
   um cartão ali competiria com os campos. Fundo levemente tingido separa o
   que é calculado do que é digitado — a pessoa não deve procurar onde
   escrever nesses números. */
.depreciacao-painel {
  margin-top: var(--joao-space-4);
  padding: var(--joao-space-4);
  background: var(--joao-tint-neutro);
  border: 1px solid var(--joao-border);
  border-left: 3px solid var(--joao-action);
  border-radius: var(--joao-radius-md);
}
.depreciacao-painel__cabecalho {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--joao-space-3);
}
.depreciacao-painel__cabecalho h2 { margin: .1rem 0 0; font-size: var(--joao-fs-h2); }
.depreciacao-painel__metodo { color: var(--joao-text-muted); font-size: var(--joao-fs-sm); }
.depreciacao-painel__aviso { margin: var(--joao-space-3) 0 0; color: var(--joao-text-muted); font-size: var(--joao-fs-sm); }
.depreciacao-painel__grade {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr));
  gap: var(--joao-space-3);
  margin: var(--joao-space-4) 0 0;
}
.depreciacao-painel__grade dt { color: var(--joao-text-muted); font-size: .75rem; text-transform: uppercase; letter-spacing: .04em; }
.depreciacao-painel__grade dd { margin: .15rem 0 0; font-family: var(--joao-font-display); font-size: 1.05rem; font-weight: 700; }
.depreciacao-painel__destaque { color: var(--joao-ink-action); }
/* A barra é redundante com o percentual escrito logo abaixo — por isso
   aria-hidden na marcação: quem ouve a tela não precisa dela duas vezes. */
.depreciacao-painel__barra {
  height: 6px;
  margin: var(--joao-space-4) 0 var(--joao-space-2);
  background: var(--joao-gray-200);
  border-radius: var(--joao-radius-pill);
  overflow: hidden;
}
.depreciacao-painel__barra span {
  display: block;
  height: 100%;
  width: 0;
  background: var(--joao-action);
  transition: width .25s ease;
}
@media (prefers-reduced-motion: reduce) { .depreciacao-painel__barra span { transition: none; } }

/* ── Consolidado do patrimônio ──
   Cabeçalho com o total à direita: quem abre a tela quer o número grande
   antes da tabela que o explica. */
.patrimonio-resumo { margin-bottom: var(--joao-space-4); }
.patrimonio-resumo__cabecalho {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--joao-space-4);
  margin-bottom: var(--joao-space-3);
}
.patrimonio-resumo__cabecalho h2 { margin: .1rem 0 .2rem; font-size: var(--joao-fs-h2); }
.patrimonio-resumo__cabecalho .subtitulo { margin-bottom: 0; }
.patrimonio-resumo__total { display: flex; flex-direction: column; gap: .1rem; }
.patrimonio-resumo__total span { color: var(--joao-text-muted); font-size: .75rem; text-transform: uppercase; letter-spacing: .04em; }
.patrimonio-resumo__total strong { color: var(--joao-ink-action); font-family: var(--joao-font-display); font-size: 1.6rem; font-weight: 800; }
.patrimonio-resumo__total small { color: var(--joao-text-muted); font-size: var(--joao-fs-sm); }
/* O total fecha a tabela: filete acima o separa das categorias sem virar
   outra superfície. */
.patrimonio-resumo tfoot td { border-top: 2px solid var(--joao-border); }
/* Nota sob o valor na listagem — a linha de baixo da mesma célula, não outra
   coluna: são o mesmo dado, o número e a leitura dele. */
.patrimonio-lista__depreciado { display: block; color: var(--joao-text-muted); font-size: .75rem; }

/* ── Catálogo de fotos do patrimônio ── */
.catalogo-fotos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr));
  gap: var(--joao-space-4);
  margin: var(--joao-space-4) 0 0;
  padding: 0;
  list-style: none;
}
.catalogo-fotos__item {
  display: flex;
  flex-direction: column;
  gap: var(--joao-space-2);
  padding: var(--joao-space-3);
  background: var(--joao-surface);
  border: 1px solid var(--joao-border);
  border-radius: var(--joao-radius-md);
}
/* `aspect-ratio` + `object-fit` para a grade não pular de altura conforme a
   proporção de cada foto: retrato e paisagem no mesmo catálogo. */
.catalogo-fotos__previa {
  display: block;
  aspect-ratio: 4 / 3;
  background: var(--joao-gray-100);
  border-radius: var(--joao-radius-sm);
  overflow: hidden;
}
.catalogo-fotos__previa img { width: 100%; height: 100%; object-fit: cover; display: block; }
.catalogo-fotos__previa:focus-visible { outline: 2px solid var(--joao-focus-cor); outline-offset: 2px; }
.catalogo-fotos__dados { display: flex; flex-direction: column; gap: .15rem; font-size: var(--joao-fs-sm); }
.catalogo-fotos__meta { color: var(--joao-text-muted); font-size: .75rem; }
.catalogo-fotos__item .btn { align-self: flex-start; }

/* ── Barra de ações em lote ──
   Só aparece com alguém marcado: barra permanente ocupa espaço o tempo todo
   por uma ação ocasional, e oferece "enviar" quando não há a quem enviar. */
.lote-barra {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--joao-space-3);
  margin-bottom: var(--joao-space-3);
  padding: var(--joao-space-3) var(--joao-space-4);
  background: var(--joao-tint-action);
  border: 1px solid var(--joao-border);
  border-radius: var(--joao-radius-md);
}
.lote-barra__contagem { margin: 0; font-weight: 600; font-size: var(--joao-fs-sm); }
.lote-barra__acoes { display: flex; flex-wrap: wrap; gap: var(--joao-space-2); margin-left: auto; }
/* A coluna de seleção não é conteúdo: só precisa caber a caixa. */
.col-selecao { width: 1%; white-space: nowrap; }
.col-selecao input[type="checkbox"] { width: auto; min-height: 0; margin: 0; }
@media (max-width: 900px) {
  /* No cartão, a caixa vai para o topo, sem rótulo próprio — o nome da pessoa
     está logo abaixo e já é o rótulo dela (aria-label do checkbox). */
  .lote-barra__acoes { margin-left: 0; width: 100%; }
  .lote-barra__acoes .btn { flex: 1 1 auto; }
}
.aba-painel__intro { margin: 0 0 .75rem; }
.aba-painel__intro h2 { font-size: var(--joao-fs-h2); margin: .1rem 0 .2rem; }
.aba-painel__intro .subtitulo { margin-bottom: 0; }
/* A grade do formulário não tem ponto de quebra próprio: `.form-grid` mais
   abaixo usa `auto-fit` com `minmax(min(100%, 260px), 1fr)`, que resolve a
   contagem de colunas pela largura disponível. Havia aqui um bloco de 640px
   forçando 1 coluna — morto, porque a regra incondicional vem depois com a
   mesma especificidade. Medido: 1440px = 3 colunas, 901 = 2, 900 = 3 (a rail
   vira gaveta e devolve 200px), 640 = 2, 375 = 1. */

.form-group { margin-bottom: 1rem; }
label { display: block; font-weight: 500; margin-bottom: .35rem; font-size: .88rem; }
label .obrigatorio { color: var(--joao-danger); }
/* ── Campo com ação embutida (CEP, CNPJ, teste de envio) ──
   Antes a ação era um `.btn` ao lado do campo, num flex com `flex-wrap`. Em
   coluna de formulário (a grade tem duas), 112px de botão mais o campo não
   cabiam: o botão descia para a linha de baixo, desalinhado do campo e do
   resto da grade. Colar `nowrap` só trocaria a quebra por um campo espremido.

   A ação passou para DENTRO do campo: ícone à direita, sem largura própria,
   e o campo volta a ter a largura de qualquer outro da grade. O botão continua
   sendo <button> de verdade, com nome acessível no `aria-label` — ícone sem
   nome é botão mudo para leitor de tela.

   O `padding-right` do campo abre a calha do ícone; sem ele o texto digitado
   passa por baixo do botão. */
.campo-acao { position: relative; display: block; }
.campo-acao > input { padding-right: 2.9rem; }
.campo-acao__botao {
  position: absolute;
  top: 1px;
  right: 1px;
  bottom: 1px;
  width: 2.6rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 0 var(--joao-radius-md) var(--joao-radius-md) 0;
  background: transparent;
  color: var(--joao-ink-action);
  cursor: pointer;
}
.campo-acao__botao svg { width: 19px; height: 19px; }
.campo-acao__botao:hover { background: var(--joao-tint-action); }
.campo-acao__botao:focus-visible {
  outline: 2px solid var(--joao-focus-cor);
  outline-offset: -2px;
  border-radius: var(--joao-radius-md);
}
.campo-acao__botao[disabled] { color: var(--joao-text-muted); cursor: progress; }
/* Ação de contato (e-mail, WhatsApp): o ícone é o próprio aviso de validade.
   Apagado enquanto o valor não serve, tinta cheia quando serve — e desabilitado
   junto, porque botão que parece clicável e não faz nada é pior que botão
   visivelmente indisponível. `not-allowed`, não `progress`: aqui não há espera,
   há impedimento. */
.campo-acao__botao--contato { color: var(--joao-text-muted); opacity: .5; }
.campo-acao__botao--contato[disabled] { cursor: not-allowed; }
.campo-acao__botao--contato.is-valido { opacity: 1; color: var(--joao-ink-action); }
.campo-acao__botao--zap.is-valido { color: var(--joao-success-ink); }
/* Enquanto a consulta corre, o ícone gira — é o único aviso de "estou indo à
   rede" num controle que não tem espaço para texto. */
.campo-acao__botao[aria-busy="true"] svg { animation: joao-girar 1s linear infinite; }
@keyframes joao-girar { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .campo-acao__botao[aria-busy="true"] svg { animation: none; opacity: .55; }
}
.form-status { min-height: 1.2em; margin: .3rem 0 0; color: var(--joao-text-muted); font-size: .78rem; }
.form-status.is-error { color: var(--joao-danger); }

/*
  Um seletor só para TODO campo textual. A lista antiga não cobria
  datetime-local, time, month, week, search nem file — e o Razor gera
  datetime-local sozinho para DateTime — então esses campos apareciam com
  o desenho nativo do navegador no meio de formulários estilizados.
  :where() mantém especificidade 0, para qualquer regra de tela vencer sem !important.
*/
:where(
  input:not([type]),
  input[type="text"], input[type="email"], input[type="password"], input[type="search"],
  input[type="url"], input[type="tel"], input[type="number"],
  input[type="date"], input[type="datetime-local"], input[type="time"],
  input[type="month"], input[type="week"], input[type="file"],
  select, textarea
) {
  display: block;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  min-height: var(--joao-field-altura);
  padding: .55rem .75rem;
  border: 1px solid var(--joao-border);
  border-radius: var(--joao-radius-md);
  font-family: var(--joao-font-body);
  font-size: var(--joao-fs-base);
  line-height: 1.4;
  background: var(--joao-surface);
  color: var(--joao-text);
  transition: border-color .15s ease, box-shadow .15s ease;
}
textarea { min-height: 7rem; resize: vertical; }
/* Seta do select desenhada por nós: o triângulo nativo muda de forma e de cor
   entre navegadores e é o que mais denuncia "campo fora do padrão". */
:where(select) {
  appearance: none;
  padding-right: 2.25rem;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 1.05rem) 55%, calc(100% - .7rem) 55%;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
}
:where(select[multiple]) { background-image: none; padding-right: .75rem; }
/* O botão interno de input[type=file] é o único pedaço nativo que sobra;
   ele vira um botão outline em vez de sumir — o usuário precisa dele. */
:where(input[type="file"]) { padding: .35rem .5rem; }
input[type="file"]::file-selector-button {
  margin-right: .75rem;
  padding: .4rem .8rem;
  border: 1px solid var(--joao-border);
  border-radius: var(--joao-radius-sm);
  background: var(--joao-gray-100);
  color: var(--joao-text);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
input[type="file"]::file-selector-button:hover { border-color: var(--joao-action); color: var(--joao-ink-action); }
input[type="checkbox"], input[type="radio"] { accent-color: var(--joao-action); width: 1.05rem; height: 1.05rem; }

input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--joao-focus-cor);
  outline-offset: 1px;
  border-color: var(--joao-action);
  box-shadow: var(--joao-focus-ring);
}
/* Firefox/Safari em campos que não emitem :focus-visible por si */
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--joao-action);
  box-shadow: var(--joao-focus-ring);
}
input:disabled, select:disabled, textarea:disabled,
input[readonly], textarea[readonly] {
  background: var(--joao-gray-100);
  color: var(--joao-text-muted);
  cursor: not-allowed;
}
::placeholder { color: var(--joao-text-muted); opacity: 1; }

/* Campo com erro: borda + tinta + ícone via ::after do rótulo de erro —
   nunca só cor (WCAG 1.4.1). */
input.input-validation-error, select.input-validation-error, textarea.input-validation-error,
[aria-invalid="true"] {
  border-color: var(--joao-danger);
  box-shadow: inset 3px 0 0 var(--joao-danger);
}

.validation-summary-errors, .field-validation-error {
  color: var(--joao-danger);
  font-size: .82rem;
}
.validation-summary-errors ul { margin: 0; padding-left: 1.1rem; }

/* ── Campo de senha com "olho" ── */
.password-field { position: relative; }
.password-field input { padding-right: 2.6rem; }
.password-toggle {
  position: absolute;
  top: 50%;
  right: .6rem;
  transform: translateY(-50%);
  background: none;
  border: none;
  padding: .2rem;
  color: var(--joao-text-muted);
  cursor: pointer;
  display: flex;
}
.password-toggle:hover { color: var(--joao-text); }
.password-toggle:focus-visible { outline: 2px solid var(--joao-focus-cor); outline-offset: 2px; border-radius: var(--joao-radius-sm); }

/* ── Barra de progresso (modal de bloqueio de login) ── */
.joao-progress {
  height: 8px;
  border-radius: 999px;
  background: var(--joao-border);
  overflow: hidden;
}
.joao-progress__bar {
  height: 100%;
  background: var(--joao-accent-500);
  transition: width 1s linear;
}

/*
  ================================================================
  BOTOES - semantica antes de cor
  ================================================================
  Cada variante tem um significado fixo e um lugar fixo na linha de acoes:

    .btn-primary   salvar, confirmar, criar    (preenchido, primeiro)
    .btn-secondary cancelar, voltar, consultar (contorno)  [.btn-outline = alias]
    .btn-danger    excluir, desativar, remover (preenchido vermelho, por ultimo)
    .btn-warning   acao arriscada porem reversivel
    .btn-info      ajuda e orientacao
    .btn-ghost     acao terciaria dentro de uma superficie

  As tres formas - preenchido / contorno / plano - separam a hierarquia sem
  depender de matiz, entao continuam distinguiveis em daltonismo e em
  monocromatico (WCAG 1.4.1). O verbo do rotulo faz o resto.

  Todo botao tem: normal, :hover, :focus-visible, :active, :disabled e
  [aria-busy="true"] (ocupado). Nenhuma variante existe sem os seis.
*/
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .45rem;
  min-height: var(--joao-field-altura);
  padding: .6rem 1.1rem;
  border: 1px solid transparent;
  border-radius: var(--joao-radius-md);
  font-family: var(--joao-font-body);
  font-size: var(--joao-fs-base);
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  position: relative;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.btn-primary { background: var(--joao-action); border-color: var(--joao-action); color: var(--joao-on-action); }
.btn-primary:hover { background: var(--joao-action-hover); border-color: var(--joao-action-hover); }
.btn-primary:active { background: var(--joao-action-active); border-color: var(--joao-action-active); }

.btn-secondary, .btn-outline { background: transparent; border-color: var(--joao-border); color: var(--joao-text); }
.btn-secondary:hover, .btn-outline:hover { border-color: var(--joao-action); color: var(--joao-ink-action); background: var(--joao-tint-action); }
.btn-secondary:active, .btn-outline:active { background: var(--joao-tint-neutro); }

.btn-danger { background: var(--joao-danger); border-color: var(--joao-danger); color: var(--joao-on-danger); }
.btn-danger:hover { background: var(--joao-danger-ink); border-color: var(--joao-danger-ink); }
.btn-danger:active { filter: brightness(.9); }

.btn-warning { background: transparent; border-color: var(--joao-warning-ink); color: var(--joao-warning-ink); }
.btn-warning:hover { background: var(--joao-tint-warning); }

.btn-info { background: transparent; border-color: var(--joao-info-ink); color: var(--joao-info-ink); }
.btn-info:hover { background: var(--joao-tint-info); }

.btn-ghost { background: transparent; border-color: transparent; color: var(--joao-ink-action); }
.btn-ghost:hover { background: var(--joao-tint-action); }

.btn-block { width: 100%; }
.btn-sm { min-height: 34px; padding: .35rem .7rem; font-size: var(--joao-fs-sm); }

.btn:focus-visible {
  outline: 2px solid var(--joao-focus-cor);
  outline-offset: 2px;
  box-shadow: var(--joao-focus-ring);
}
.btn:disabled, .btn[aria-disabled="true"] {
  opacity: .5;
  cursor: not-allowed;
  pointer-events: none;
  filter: grayscale(.35);
}
/*
  Ocupado: a geometria nao muda (sem "pulo" de layout ao enviar) - o rotulo
  fica oculto no lugar e um anel gira por cima. aria-busy ja anuncia para o
  leitor de tela; o disco e o sinal visual equivalente.
*/
.btn[aria-busy="true"] { pointer-events: none; color: transparent; }
.btn[aria-busy="true"] > * { visibility: hidden; }
.btn[aria-busy="true"]::after {
  content: '';
  position: absolute;
  width: 1.05rem; height: 1.05rem;
  border: 2px solid var(--joao-text);
  border-top-color: transparent;
  border-radius: 50%;
  animation: joao-girar .7s linear infinite;
}
.btn-primary[aria-busy="true"]::after { border-color: var(--joao-on-action); border-top-color: transparent; }
.btn-danger[aria-busy="true"]::after { border-color: var(--joao-on-danger); border-top-color: transparent; }
@keyframes joao-girar { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .btn[aria-busy="true"]::after { animation-duration: 2.4s; }
}

/*
  Linha de acoes: primaria primeiro, destrutiva sempre por ultimo e separada,
  para nao ficar encostada no "Salvar". Em telas estreitas empilha e cada
  botao ocupa a linha inteira (alvo de toque cheio).
*/
.form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .75rem;
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--joao-border);
}
.form-actions .btn-danger, .form-actions__perigo { margin-left: auto; }
@media (max-width: 640px) {
  .form-actions { flex-direction: column-reverse; align-items: stretch; }
  .form-actions .btn { width: 100%; }
  .form-actions .btn-danger, .form-actions__perigo { margin-left: 0; }
}

/*
  ================================================================
  ALERTAS - quatro intencoes, nunca so cor
  ================================================================
  O filete lateral da a intencao, o ::before da o icone e o texto da a
  palavra. A variante nua (.alerta sozinho) continua sendo erro, para nao
  quebrar as telas que ja a usam assim.
*/
.alerta {
  display: flex;
  align-items: flex-start;
  gap: .6rem;
  padding: .8rem 1rem;
  margin-bottom: 1rem;
  border-radius: var(--joao-radius-sm);
  border-left: 4px solid var(--joao-danger);
  background: var(--joao-tint-danger);
  color: var(--joao-danger-ink);
  font-size: var(--joao-fs-base);
}
/*
  O ícone é um ANEL, não um disco preenchido.
  A versão anterior fazia `background: currentColor; color: var(--joao-surface)`
  na mesma regra — e currentColor resolve contra a cor declarada ali mesmo,
  não contra a herdada. Fundo e glifo acabavam na mesma cor: ícone invisível,
  1:1 de contraste. O anel usa só currentColor e herda a tinta do alerta, que
  já é validada em AA, então funciona nos dois temas sem inversão.
*/
.alerta::before {
  content: '!';
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 1.35rem; height: 1.35rem;
  border: 2px solid currentColor;
  border-radius: 50%;
  font-size: .8rem;
  font-weight: 800;
  line-height: 1;
}
.alerta--sucesso { border-left-color: var(--joao-success); background: var(--joao-tint-success); color: var(--joao-success-ink); }
.alerta--sucesso::before { content: '\2713'; }
.alerta--aviso { border-left-color: var(--joao-warning); background: var(--joao-tint-warning); color: var(--joao-warning-ink); }
.alerta--info { border-left-color: var(--joao-info); background: var(--joao-tint-info); color: var(--joao-info-ink); }
.alerta--info::before { content: 'i'; font-style: italic; }
.alerta--perigo { border-left-color: var(--joao-danger); }
.alerta a { color: inherit; font-weight: 700; }

/* ── Tela de login ── */
.auth-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--joao-bg);
  padding: 1rem;
}
.auth-card { width: 100%; max-width: 380px; }
.auth-card .simbolo { display: block; margin: 0 auto 1rem; height: 56px; }
.auth-card h1 { text-align: center; font-size: 1.3rem; }
.auth-card .subtitulo { text-align: center; color: var(--joao-text-muted); font-size: .88rem; margin-bottom: 1.5rem; }

/* Portal do Membro: assinatura visual própria, mantendo os tokens institucionais. */
.portal-body { background: #081b2e; }
.portal-shell { background: radial-gradient(circle at 12% 0%, rgba(34,199,184,.13), transparent 38%), var(--joao-bg); }
.portal-shell .topbar { border-bottom: 3px solid var(--joao-secondary-500); background: var(--joao-primary-900); color: var(--joao-bg); }
.portal-shell .topbar a { color: var(--joao-bg); font-weight: 600; }
.portal-login-page { background: radial-gradient(circle at 50% -10%, rgba(34,199,184,.22), transparent 48%), #081b2e; }
.portal-login-page .auth-card { border-top: 4px solid var(--joao-secondary-500); box-shadow: 0 18px 50px rgba(0,0,0,.28); }
.portal-login-mark { display: flex; align-items: center; gap: .55rem; margin-bottom: 1rem; color: var(--joao-ink-action); font-size: .68rem; font-weight: 800; letter-spacing: .18em; }
.portal-login-mark__line { height: 1px; flex: 1; background: linear-gradient(90deg, var(--joao-secondary-500), transparent); }
.portal-login-alerta { margin-top: 1rem; margin-bottom: 0; }
.portal-brand { display:flex; align-items:center; gap:.6rem; }
.portal-brand img { height:34px; max-width:150px; object-fit:contain; }
.portal-brand__church { font-family:var(--joao-font-display); font-size:.9rem; font-weight:800; letter-spacing:.01em; }
.portal-brand__divider { width:1px; height:24px; background:color-mix(in srgb, currentColor 40%, transparent); }
.topbar__church { display:flex; align-items:center; gap:.6rem; min-width:0; color:var(--joao-primary-900); font-family:var(--joao-font-display); font-weight:800; }
.topbar__church img { height:30px; max-width:150px; object-fit:contain; }
@media (max-width: 640px) { .portal-brand__church, .portal-brand__divider { display:none; } .portal-brand strong { font-size:.82rem; } .topbar__church span { max-width:170px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; } }

/* Bíblia online: leitura calma, busca objetiva e versão sempre visível. */
.portal-biblia { max-width: 1120px; margin: 0 auto; }
.portal-biblia__hero { margin-bottom: 1.5rem; }
.portal-biblia__versao { min-width: 245px; padding: 1rem 1.15rem; border-left: 3px solid var(--joao-secondary-500); background: color-mix(in srgb, var(--joao-secondary-500) 10%, transparent); border-radius: var(--joao-radius-sm); }
.portal-biblia__versao span, .portal-biblia__versao small { display: block; color: var(--joao-text-muted); font-size: .75rem; }
.portal-biblia__versao strong { display: block; margin: .25rem 0; color: var(--joao-primary-900); font-family: var(--joao-font-display); }
.portal-biblia__busca { padding: 1.35rem; margin-bottom: 1.25rem; }
.portal-biblia__section-heading, .portal-biblia__capitulo-card header { display:flex; align-items:flex-start; justify-content:space-between; gap:1rem; }
.portal-biblia__section-heading h2 { margin: .2rem 0 1rem; font-size: 1.2rem; }
.portal-biblia__kicker { color: var(--joao-ink-action); font-size:.7rem; font-weight:800; letter-spacing:.1em; text-transform:uppercase; }
.portal-biblia__resultado-count, .portal-biblia__capitulo-ref { color: var(--joao-text-muted); font-size:.8rem; white-space:nowrap; }
.portal-biblia__form { display:grid; grid-template-columns:minmax(220px,1.5fr) minmax(170px,1fr) 110px auto auto; gap:.75rem; align-items:end; }
.portal-biblia__form .form-group { margin:0; }
.portal-biblia__form .btn { min-height:42px; }
.portal-biblia__resultados { display:grid; gap:1rem; }
.portal-biblia__capitulo-card { padding:1.35rem; border:1px solid var(--joao-border); border-top:3px solid var(--joao-secondary-500); border-radius:var(--joao-radius-md); background:var(--joao-surface); box-shadow:var(--joao-shadow-card); }
.portal-biblia__capitulo-card h2 { margin:.25rem 0 0; font-family:var(--joao-font-display); }
.portal-biblia__capitulo-card h2 span { color:var(--joao-ink-action); }
.portal-biblia__versiculos { margin-top:1rem; border-top:1px solid var(--joao-border); }
.portal-biblia__versiculos p { display:grid; grid-template-columns:2.2rem 1fr; gap:.6rem; margin:0; padding:.7rem 0; border-bottom:1px solid color-mix(in srgb, var(--joao-border) 65%, transparent); line-height:1.7; }
.portal-biblia__versiculos sup { color:var(--joao-ink-action); font-weight:800; font-size:.75rem; padding-top:.2rem; }
.portal-biblia__empty { padding:3rem 1.5rem; text-align:center; }
.portal-biblia__empty h2 { margin:.7rem 0 .35rem; }
.portal-biblia__glyph { display:inline-grid; place-items:center; width:46px; height:46px; border-radius:50%; background:color-mix(in srgb, var(--joao-secondary-500) 15%, transparent); color:var(--joao-ink-action); font-size:1.4rem; }
.portal-biblia__credito { margin:1.25rem 0; color:var(--joao-text-muted); font-size:.75rem; text-align:center; }
@media (max-width: 900px) { .portal-biblia__hero .page-header__linha { display:block; } .portal-biblia__versao { margin-top:1rem; } .portal-biblia__form { grid-template-columns:1fr 1fr; } .portal-biblia__termo { grid-column:span 2; } .portal-biblia__form .btn { width:100%; } }
@media (max-width: 640px) { .portal-biblia__form { grid-template-columns:1fr; } .portal-biblia__termo { grid-column:auto; } .portal-biblia__section-heading, .portal-biblia__capitulo-card header { display:block; } .portal-biblia__resultado-count, .portal-biblia__capitulo-ref { display:block; margin-top:.5rem; } }

/* ── Foco de teclado visível (WCAG 2.2 AA) — nunca remover, só reforçar ── */
a:focus-visible, button:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--joao-focus-cor);
  outline-offset: 2px;
  border-radius: var(--joao-radius-sm);
}

/* ── Alternador de tema (claro/escuro/sistema) — botão no topbar ── */
.tema-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: var(--joao-radius-md);
  border: 1px solid var(--joao-border);
  background: transparent;
  color: var(--joao-text-muted);
  cursor: pointer;
}
.tema-toggle:hover { color: var(--joao-ink-action); border-color: var(--joao-action); background: var(--joao-tint-action); }
.tema-toggle svg { width: 18px; height: 18px; }

/* ── Tema escuro: ajustes de componentes de terceiros (SweetAlert2) e scrollbar ── */
:root[data-theme="dark"] {
  color-scheme: dark;
}
:root[data-theme="dark"] .swal2-popup { background: var(--joao-surface); color: var(--joao-text); }
:root[data-theme="dark"] .swal2-html-container { color: var(--joao-text); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { color-scheme: dark; }
  :root:not([data-theme="light"]) .swal2-popup { background: var(--joao-surface); color: var(--joao-text); }
  :root:not([data-theme="light"]) .swal2-html-container { color: var(--joao-text); }
}
* { scrollbar-color: var(--joao-border) var(--joao-bg); }

/*
  ==========================================================================
  COMPONENTES COMPARTILHADOS
  ==========================================================================
  Tudo abaixo estava sendo usado nas telas SEM regra correspondente no CSS -
  a auditoria encontrou 15 classes orfas (.subtitulo fora do cabecalho,
  .form-hint, .relatorio-card, .configuracao-secao, .badge-success, entre
  outras). Elas renderizavam como texto corrido, o que e a causa real de
  "muitas telas fora do padrao visual": nao era desalinhamento, era ausencia
  de estilo. Definir aqui conserta todas de uma vez, sem tocar em tela.
*/

/* Texto de apoio - antes so existia dentro de .page-header, e ha 113 usos
   soltos (estados vazios, cartoes do Portal, legendas). */
.subtitulo { color: var(--joao-text-muted); font-size: var(--joao-fs-sm); margin: .2rem 0 0; }

/* Ajuda de campo. .is-error e escrito por JS (CEP, upload de logo) e ate
   agora nao pintava nada - a mensagem de erro saia com cor de texto normal. */
.form-hint {
  display: block;
  margin: .3rem 0 0;
  color: var(--joao-text-muted);
  font-size: var(--joao-fs-sm);
  line-height: 1.45;
}
.form-hint.is-error, .form-status.is-error { color: var(--joao-danger-ink); font-weight: 600; }
.form-hint.is-error::before, .form-status.is-error::before { content: '\26A0\FE0E'; margin-right: .35rem; }

/* Erro de campo e resumo de erro: icone + tinta, nunca so cor. */
.field-validation-error:not(:empty) {
  display: block;
  margin-top: .3rem;
  color: var(--joao-danger-ink);
  font-size: var(--joao-fs-sm);
  font-weight: 600;
}
.field-validation-error:not(:empty)::before { content: '\26A0\FE0E'; margin-right: .35rem; }
.validation-summary-errors:not(.validation-summary-valid) ul:not(:empty) {
  margin: 0 0 1rem;
  padding: .8rem 1rem .8rem 2.2rem;
  border-left: 4px solid var(--joao-danger);
  border-radius: var(--joao-radius-sm);
  background: var(--joao-tint-danger);
  color: var(--joao-danger-ink);
  font-weight: 600;
}

/* Rotulo: o asterisco de obrigatorio ganha texto para leitor de tela via
   aria-label no proprio span (ver views); aqui so a forma. */
label { color: var(--joao-text); }
.obrigatorio { color: var(--joao-danger-ink); font-weight: 700; }

/* Secao dentro de formulario longo (Configuracoes SMTP, Evento). */
.configuracao-secao,
.form-secao {
  margin: 1.75rem 0 .5rem;
  padding-top: 1.25rem;
  border-top: 2px solid var(--joao-primary-900);
}
.configuracao-secao h2, .form-secao h2 { font-size: var(--joao-fs-h2); margin: .1rem 0 .2rem; }
.configuracao-secao .subtitulo, .form-secao .subtitulo { margin-bottom: .5rem; }

/* Cartao de relatorio - a grade existia, o cartao nunca teve superficie. */
.relatorio-card {
  padding: 1.15rem;
  background: var(--joao-surface);
  border: 1px solid var(--joao-border);
  border-top: 3px solid var(--joao-secondary-500);
  border-radius: var(--joao-radius-md);
  box-shadow: var(--joao-shadow-card);
  min-width: 0;
}

.dashboard-header { margin-bottom: 1.5rem; }
.lista-sem-marcador { list-style: none; margin: 0; padding: 0; }
.topbar__brand { display: flex; align-items: center; gap: .6rem; min-width: 0; }

/* Badge: variantes semanticas completas. Fundo tenue + tinta que passa em
   AA + a palavra dentro; a cor sozinha nunca carrega o significado. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  padding: .15rem .55rem;
  border-radius: var(--joao-radius-pill);
  font-size: var(--joao-fs-micro);
  font-weight: 700;
  line-height: 1.5;
  white-space: nowrap;
}
.badge-sucesso, .badge-success { background: var(--joao-tint-success); color: var(--joao-success-ink); }
.badge-inativo, .badge-neutro { background: var(--joao-tint-neutro); color: var(--joao-text-muted); }
.badge-info { background: var(--joao-tint-action); color: var(--joao-ink-action); }
.badge-aviso { background: var(--joao-tint-warning); color: var(--joao-warning-ink); }
.badge-perigo { background: var(--joao-tint-danger); color: var(--joao-danger-ink); }

/*
  Estado vazio: a mesma peca em toda listagem. Antes cada tela escrevia um
  <p class="subtitulo">Nenhum X encontrado.</p> sem estilo e sem saida - o
  usuario lia a frase e nao sabia o que fazer. Agora tem titulo, explicacao
  e, quando cabe, a acao que resolve.
*/
.estado-vazio {
  padding: 2.5rem 1.5rem;
  margin: 1rem 0;
  text-align: center;
  background: var(--joao-surface);
  border: 1px dashed var(--joao-border);
  border-radius: var(--joao-radius-md);
}
.estado-vazio__glyph {
  display: inline-grid;
  place-items: center;
  width: 46px; height: 46px;
  margin-bottom: .75rem;
  border-radius: 50%;
  background: var(--joao-tint-action);
  color: var(--joao-ink-action);
  font-size: 1.3rem;
}
.estado-vazio h2 { font-size: var(--joao-fs-lg); margin: 0 0 .35rem; }
.estado-vazio p { max-width: 46ch; margin: 0 auto 1rem; color: var(--joao-text-muted); font-size: var(--joao-fs-base); }
.estado-vazio .btn { margin-top: .25rem; }

/*
  Acoes na linha da tabela. Antes TODAS saiam como texto teal identico -
  "Editar", "Inativar" e "Cancelar" indistinguiveis. Agora a acao destrutiva
  tem tinta vermelha E um ponto marcador antes do rotulo, entao continua
  identificavel sem cor. Alvo de toque de 44px no celular.
*/
.tabela-registro__acoes { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem .9rem; white-space: nowrap; }
.tabela-registro__acoes a,
.tabela-registro__acoes button {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: .3rem 0;
  background: none;
  border: none;
  font: inherit;
  font-size: var(--joao-fs-sm);
  font-weight: 600;
  color: var(--joao-ink-action);
  text-decoration: none;
  cursor: pointer;
  border-radius: var(--joao-radius-sm);
}
.tabela-registro__acoes a:hover,
.tabela-registro__acoes button:hover { text-decoration: underline; }
.tabela-registro__acoes a:focus-visible,
.tabela-registro__acoes button:focus-visible { outline: 2px solid var(--joao-focus-cor); outline-offset: 2px; }
.tabela-registro__acoes form { display: inline-flex; margin: 0; }
/* Especificidade em vez de !important: precisam vencer
   ".tabela-registro__acoes a/button", que e 0,2,0. */
.acao-perigo,
.tabela-registro__acoes .acao-perigo { color: var(--joao-danger-ink); }
.acao-perigo::before { content: '\2716'; font-size: .7rem; }
.acao-cuidado,
.tabela-registro__acoes .acao-cuidado { color: var(--joao-warning-ink); }
.acao-cuidado::before { content: '\21BA'; font-size: .82rem; }

/*
  ==========================================================================
  NAVEGACAO RESPONSIVA
  ==========================================================================
  O UX-CONTRACT ja prometia "drawer no celular", mas o drawer nunca existiu:
  a rail de 76px ficava fixa em qualquer largura, comendo 24% de uma tela de
  320px e espremendo a tabela ao lado. Aqui ela vira gaveta abaixo de 900px.

  Nomenclatura: o monograma (DSH/SEC/PAS) deixa de ser o texto principal e
  vira apoio visual; o nome do modulo em linguagem de usuario e o rotulo.
*/
.rail__toggle,
.rail__backdrop { display: none; }

.rail__item { position: relative; text-align: center; }
.rail__item-monograma {
  flex-shrink: 0;
  display: inline-grid;
  place-items: center;
  min-width: 2.5rem;
  padding: .2rem .35rem;
  border-radius: var(--joao-radius-sm);
  background: var(--joao-tint-neutro);
  color: var(--joao-text-muted);
  font-family: var(--joao-font-display);
  font-weight: 700;
  font-size: .64rem;
  letter-spacing: .04em;
}
.rail__item-rotulo {
  font-size: .88rem;
  font-weight: 600;
  line-height: 1.2;
  text-align: left;
  letter-spacing: .01em;
  text-transform: none;
}
.rail__item.active .rail__item-monograma { background: var(--joao-tint-action); color: var(--joao-ink-action); }
.rail__item:focus-visible { outline: 2px solid var(--joao-focus-cor); outline-offset: -2px; }

/* Divisor de grupo na rail: administrativo / pastoral / portal. */
.rail__grupo {
  width: 100%;
  margin: .7rem 0 .15rem;
  padding: .5rem .9rem .15rem;
  border-top: 1px solid var(--joao-border);
  color: var(--joao-text-muted);
  font-size: .62rem;
  font-weight: 800;
  letter-spacing: .08em;
  text-align: left;
  text-transform: uppercase;
}
.rail__grupo:first-child { border-top: 0; margin-top: 0; }
/* A marca já fecha com filete; o grupo logo abaixo não repete. */
.rail__brand + .rail__nav .rail__item:first-child { margin-top: -.15rem; }

@media (max-width: 900px) {
  .app-shell { display: block; }
  .rail {
    position: fixed;
    top: 0; bottom: 0; left: 0;
    z-index: 60;
    width: min(78vw, 290px);
    padding: 1rem 0 2rem;
    overflow-y: auto;
    background: var(--joao-surface);
    box-shadow: var(--joao-shadow-pop);
    transform: translateX(-102%);
    transition: transform .22s ease;
  }
  .rail::after { display: none; }
  .app-shell.is-menu-aberto .rail { transform: translateX(0); }
  /* Na gaveta ha largura de sobra: monograma e nome ficam lado a lado e o
     alvo de toque passa a ocupar a linha inteira. */
  .rail__item {
    gap: .7rem;
    min-height: var(--joao-touch-min);
    padding: .7rem 1.1rem;
  }
  .rail__item-rotulo { font-size: .95rem; }
  .rail__item-monograma { min-width: 2.6rem; }
  .rail__grupo { padding-inline: 1.1rem; }
  .rail__brand { margin: .25rem .75rem 1rem; max-width: 190px; }
  .rail__toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--joao-touch-min);
    height: var(--joao-touch-min);
    margin-right: auto;
    border: 1px solid var(--joao-border);
    border-radius: var(--joao-radius-md);
    background: transparent;
    color: var(--joao-text);
    cursor: pointer;
  }
  .rail__toggle svg { width: 22px; height: 22px; }
  .rail__backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 55;
    background: rgba(8, 27, 46, .55);
    opacity: 0;
    pointer-events: none;
    transition: opacity .22s ease;
  }
  .app-shell.is-menu-aberto .rail__backdrop { opacity: 1; pointer-events: auto; }
  .app-shell.is-menu-aberto { overflow: hidden; }
}
@media (prefers-reduced-motion: reduce) {
  .rail, .rail__backdrop { transition: none; }
}

/* Topbar: em telas estreitas o nome da igreja pode encolher, os controles nao. */
.topbar { gap: .5rem; padding-inline: 1rem; }
.topbar__church { flex: 1 1 auto; min-width: 0; }
.topbar__church span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Largura em rem, não em vw: o botão mostra o primeiro nome, que é curto e
   não depende do tamanho da janela. Em vw, "Maria" ficava com 34% da tela num
   celular e "Maria das Graças Sant..." cortada num nome comprido. */
.topbar__user-btn { min-height: 38px; max-width: 12rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (min-width: 901px) { .topbar { padding-inline: 1.5rem; } }
@media (max-width: 900px) { .app-content { padding: 1.25rem 1rem; } }
/* O nome da igreja NAO some aqui: a elipse incondicional acima mais o
   min-width:0 do .topbar__church degradam o nome truncado, que e melhor
   que ausente. O bloco vale de 0 a 640px — inclusive 320px, onde o
   display:none original tinha alguma razao; ainda assim truncado ganha
   de ausente, e o recorte de 170px do bloco do Portal segura a largura. */
@media (max-width: 640px) { .topbar__user-btn { max-width: 8.5rem; } }

/*
  ==========================================================================
  CONTENCAO DE OVERFLOW
  ==========================================================================
  Sem overflow:hidden no body - isso esconderia o defeito em vez de corrigir.
  A regra e estrutural: todo filho de flex/grid pode encolher (min-width:0),
  midia nunca ultrapassa o contêiner, e conteudo largo rola na propria
  superficie (tabela, bloco de codigo, painel).
*/
.app-main, .app-content, .form-grid > *, .page-header__linha > *,
.configuracao-layout > * { min-width: 0; }
img, svg, video, canvas { max-width: 100%; height: auto; }
/*
  position: relative não é decoração: sem um bloco contentor aqui, um filho
  `position: absolute` (o .sr-only do cabeçalho de ações, por exemplo) toma
  como referência o documento, cai na coordenada da tabela larga — 651px numa
  tela de 375 — e ESTICA a página inteira. Com o contentor no próprio scroller,
  ele fica dentro do conteúdo que rola e a página não cresce.
*/
.tabela-scroll { position: relative; overflow-x: auto; -webkit-overflow-scrolling: touch; }
pre, code { overflow-x: auto; max-width: 100%; }
/* Palavras longas sem espaco (e-mails, URLs, nomes de arquivo) quebravam a
   celula e empurravam a pagina inteira. */
.tabela-registro td, .card p, .subtitulo, .estado-vazio p { overflow-wrap: anywhere; }

/* Cabecalho de pagina: busca e acoes empilham antes de estourar. */
.page-header__acoes { flex-wrap: wrap; }
.page-header__busca { display: flex; min-width: 0; }
.page-header__busca input { min-width: 0; }
@media (max-width: 900px) {
  .page-header__linha { align-items: stretch; }
  .page-header__acoes { width: 100%; }
  .page-header__busca { flex: 1 1 100%; }
  .page-header__busca input { min-width: 0; width: 100%; }
  .page-header h1 { font-size: 1.25rem; }
}

/* Paginacao: alvo de toque adequado e rolagem propria quando ha muitas paginas. */
.paginacao { flex-wrap: wrap; }
.paginacao a { min-width: var(--joao-touch-min); height: var(--joao-touch-min); }
.paginacao a:hover { border-color: var(--joao-action); color: var(--joao-ink-action); }
.paginacao a.active { border-color: var(--joao-action); background: var(--joao-tint-action); color: var(--joao-ink-action); }

/* Link padrao: a tinta de marca reprovava em AA (3.97:1); a tinta de acao passa. */
.tabela-registro__acoes a, .dashboard-secao__cabecalho > a { color: var(--joao-ink-action); }
.rail__item.active { color: var(--joao-primary-900); border-left-color: var(--joao-action); }

/*
  ==========================================================================
  PORTAL DO MEMBRO - navegacao propria, celular primeiro
  ==========================================================================
  A nav do Portal era um <nav style="display:flex;gap:1rem"> com quatro links
  + tema + usuario. Em 375px isso passa de 480px de largura e empurrava a
  pagina para fora da tela. Agora e um menu de verdade: barra no desktop,
  gaveta acionavel no celular, item atual identificado por marca e por
  aria-current (nao so por cor).

  A identidade continua diferenciada do administrativo - topbar em tinta
  institucional, filete teal, logo e nome da igreja em destaque - mas os
  botoes, campos e cartoes sao os mesmos do sistema, entao os dois lados
  leem como um produto so.
*/
.portal-nav { display: flex; align-items: center; gap: .35rem; margin-left: auto; }
.portal-nav__links { display: flex; align-items: center; gap: .15rem; }
.portal-nav__link {
  display: inline-flex;
  align-items: center;
  min-height: 38px;
  padding: .4rem .7rem;
  border-radius: var(--joao-radius-md);
  color: var(--joao-bg);
  font-size: var(--joao-fs-sm);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
.portal-nav__link:hover { background: color-mix(in srgb, currentColor 14%, transparent); }
.portal-nav__link[aria-current="page"] { background: color-mix(in srgb, currentColor 18%, transparent); box-shadow: inset 0 -3px 0 var(--joao-secondary-500); }
.portal-nav__link:focus-visible { outline: 2px solid var(--joao-secondary-500); outline-offset: 2px; }
/* Conta + Sair dentro da gaveta. Acima de 900px não existe gaveta e o menu
   suspenso do canto já dá os dois caminhos — dois "Sair" na mesma tela é uma
   pergunta a mais para quem só quer sair. */
.portal-nav__conta { display: none; }
.portal-nav__conta-nome {
  margin: 0;
  padding: .4rem .7rem 0;
  color: var(--joao-bg);
  font-size: var(--joao-fs-sm);
  font-weight: 700;
  opacity: .75;
  overflow-wrap: anywhere;
}
.portal-nav__sair {
  width: 100%;
  border: 0;
  background: transparent;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}
.portal-shell .tema-toggle { border-color: color-mix(in srgb, currentColor 35%, transparent); color: var(--joao-bg); }
.portal-shell .tema-toggle:hover { border-color: var(--joao-secondary-500); color: var(--joao-bg); }
.portal-shell .topbar__user-btn { border-color: color-mix(in srgb, currentColor 35%, transparent); color: var(--joao-bg); }
.portal-shell .topbar__user-menu a, .portal-shell .topbar__user-menu button { color: var(--joao-text); }

.portal-nav__toggle { display: none; }
@media (max-width: 900px) {
  .portal-shell .topbar { flex-wrap: wrap; height: auto; min-height: 56px; padding-block: .5rem; }
  .portal-nav__toggle {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    min-height: var(--joao-touch-min);
    padding: .45rem .8rem;
    border: 1px solid color-mix(in srgb, currentColor 35%, transparent);
    border-radius: var(--joao-radius-md);
    background: transparent;
    color: var(--joao-bg);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
  }
  .portal-nav__toggle svg { width: 20px; height: 20px; }
  .portal-nav { flex-wrap: wrap; width: 100%; justify-content: flex-end; }
  /* A gaveta ocupa a largura toda abaixo da barra: nada e cortado, cada item
     tem 44px de altura e a ordem logica do menu e preservada. */
  .portal-nav__links {
    display: none;
    flex-direction: column;
    align-items: stretch;
    gap: .2rem;
    order: 3;
    width: 100%;
    margin-top: .5rem;
    padding-top: .5rem;
    border-top: 1px solid color-mix(in srgb, currentColor 25%, transparent);
  }
  .portal-nav__links.is-aberto { display: flex; }
  .portal-nav__link { min-height: var(--joao-touch-min); font-size: var(--joao-fs-base); }
  .portal-nav__link[aria-current="page"] { box-shadow: inset 3px 0 0 var(--joao-secondary-500); }

  /* Aqui a gaveta É o menu: conta e Sair entram nela como itens de verdade.
     Sem isto, sair custava um segundo toque num botão do canto que mostrava
     um nome cortado — e ninguém achava. */
  .portal-nav__conta {
    display: flex;
    flex-direction: column;
    gap: .2rem;
    margin-top: .4rem;
    padding-top: .4rem;
    border-top: 1px solid color-mix(in srgb, currentColor 25%, transparent);
  }
  /* O botão do canto vira redundante quando a gaveta já tem conta e Sair. */
  .portal-nav .topbar__user { display: none; }
}

/*
  ==========================================================================
  BIBLIA ONLINE - leitura confortavel no celular
  ==========================================================================
  O texto biblico e lido em pe, segurando o telefone, as vezes durante a
  pregacao. Entao ele NAO segue o corpo de 15px do resto do sistema: ganha
  corpo maior, entrelinha larga e medida limitada, e o numero do versiculo
  fica fora da coluna de leitura para nao interromper a linha.
*/
.portal-biblia__versiculos p {
  font-size: 1.02rem;
  line-height: 1.8;
  max-width: var(--joao-medida-leitura);
}
.portal-biblia__versiculos span { display: block; }
/* Ação de compartilhar, no pé do cartão do capítulo: depois do texto, porque
   quem chega ali já leu e decidiu mandar. */
.portal-biblia__acoes {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--joao-space-3);
  margin-top: var(--joao-space-4);
  padding-top: var(--joao-space-3);
  border-top: 1px solid var(--joao-border);
}
.portal-biblia__acoes .btn { display: inline-flex; align-items: center; gap: .45rem; }
.portal-biblia__acoes .btn svg { width: 17px; height: 17px; }
.portal-biblia__acoes .form-status { margin: 0; }
.portal-biblia__capitulo { min-width: 0; }
.portal-biblia__capitulo-card { min-width: 0; }
.portal-biblia__form .form-group { min-width: 0; }
.portal-biblia__form input, .portal-biblia__form select { min-width: 0; }
.portal-biblia__credito a { font-weight: 600; }
@media (max-width: 640px) {
  .portal-biblia__versiculos p {
    grid-template-columns: 1.9rem 1fr;
    gap: .5rem;
    font-size: 1.06rem;
    line-height: 1.85;
  }
  .portal-biblia__capitulo-card { padding: 1rem; }
  .portal-biblia__busca { padding: 1rem; }
}

/*
  ==========================================================================
  SERMAO - preparo na mesa, cronometro no pulpito
  ==========================================================================
*/
/* Blocos da pesquisa biblica dentro do sermao (as tres classes abaixo eram
   usadas na view e nao existiam no CSS). */
.sermao-biblia__kicker {
  color: var(--joao-ink-action);
  font-size: var(--joao-fs-micro);
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.sermao-biblia__cabecalho { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; margin-bottom: .9rem; }
.sermao-biblia__cabecalho h3 { margin: .15rem 0 0; font-size: var(--joao-fs-lg); }
.sermao-biblia__versao {
  flex-shrink: 0;
  padding: .2rem .6rem;
  border-radius: var(--joao-radius-pill);
  background: var(--joao-tint-action);
  color: var(--joao-ink-action);
  font-size: var(--joao-fs-micro);
  font-weight: 700;
}
.sermao-biblia__resultados { display: grid; gap: 1rem; margin-top: 1.15rem; max-height: 30rem; overflow-y: auto; }
.sermao-biblia__grupo {
  padding: .85rem 1rem;
  background: var(--joao-surface);
  border: 1px solid var(--joao-border);
  border-left: 3px solid var(--joao-secondary-500);
  border-radius: var(--joao-radius-sm);
}
.sermao-biblia__grupo > strong {
  display: block;
  margin-bottom: .5rem;
  color: var(--joao-primary-900);
  font-family: var(--joao-font-display);
  font-size: var(--joao-fs-base);
}
.sermao-biblia__verso {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: .85rem;
  padding: .55rem 0;
  border-top: 1px solid var(--joao-border);
}
.sermao-biblia__verso > span { min-width: 0; font-size: var(--joao-fs-base); line-height: 1.65; }
.sermao-biblia__verso > span b { color: var(--joao-ink-action); margin-right: .25rem; }
.sermao-biblia__verso .btn { flex-shrink: 0; }

/* Referencia adicionada: cartao legivel, nao pilula apertada - o texto do
   versiculo precisa caber. O "x" de remover vira um alvo de 44px com tinta
   de perigo, nao um simbolo solto de 1.2rem. */
.sermao-referencia-lista { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: .75rem; margin-top: 1rem; }
.sermao-referencia {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: .6rem;
  padding: .75rem .9rem;
  min-width: 0;
  border: 1px solid var(--joao-border);
  border-left: 3px solid var(--joao-accent-500);
  border-radius: var(--joao-radius-sm);
  background: var(--joao-surface);
}
.sermao-referencia > div { min-width: 0; }
.sermao-referencia strong { display: block; color: var(--joao-primary-900); font-family: var(--joao-font-display); font-size: var(--joao-fs-base); }
.sermao-referencia p { margin: .3rem 0 0; color: var(--joao-text); font-size: var(--joao-fs-sm); line-height: 1.6; max-height: 7.5rem; overflow-y: auto; }
.sermao-referencia button {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 32px; height: 32px;
  border: 1px solid transparent;
  border-radius: var(--joao-radius-sm);
  background: none;
  color: var(--joao-danger-ink);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}
.sermao-referencia button:hover { background: var(--joao-tint-danger); border-color: var(--joao-danger); }
.sermao-referencia button:focus-visible { outline: 2px solid var(--joao-focus-cor); outline-offset: 2px; }

/*
  Cronometro: e o unico elemento da tela que precisa ser lido de relance, de
  longe, com o celular na mao. Por isso o digito e enorme, tabular (nao
  "dança" a cada segundo) e a barra compara com o tempo PLANEJADO do topico -
  antes ela dividia por 3600s fixos, o que nao significava nada.
  Passar do planejado acende ambar e depois vermelho, com texto junto.
*/
.sermao-cronometro { padding: 1rem; }
.sermao-cronometro strong {
  font-size: clamp(2.4rem, 12vw, 3.2rem);
  font-variant-numeric: tabular-nums;
  letter-spacing: .04em;
  line-height: 1.05;
}
.sermao-cronometro__meta {
  display: flex;
  justify-content: space-between;
  gap: .75rem;
  margin-top: .35rem;
  color: var(--joao-on-palco-suave);
  font-size: var(--joao-fs-sm);
  font-variant-numeric: tabular-nums;
}
.sermao-cronometro__barra span { background: var(--joao-secondary-500); }
.sermao-cronometro.is-atencao .sermao-cronometro__barra span { background: var(--joao-accent-500); }
.sermao-cronometro.is-estourado .sermao-cronometro__barra span { background: var(--joao-danger); }
.sermao-cronometro.is-estourado strong { color: var(--joao-on-palco-alerta); }
.sermao-cronometro__estado { font-weight: 700; }
.sermao-cronometro.is-atencao .sermao-cronometro__estado { color: var(--joao-on-palco-atencao); }
.sermao-cronometro.is-estourado .sermao-cronometro__estado { color: var(--joao-on-palco-alerta); }
.sermao-cronometro__acoes .btn { min-height: var(--joao-touch-min); flex: 1 1 auto; }
.sermao-cronometro__acoes .btn-outline { color: var(--joao-on-palco); border-color: color-mix(in srgb, var(--joao-on-palco) 45%, transparent); }
.sermao-cronometro__acoes .btn-outline:hover { background: color-mix(in srgb, var(--joao-on-palco) 15%, transparent); color: var(--joao-on-palco); border-color: var(--joao-on-palco); }
.sermao-cronometro__acoes .btn-outline:disabled { color: var(--joao-on-palco-suave); }
.sermao-cronometro__acoes .btn-primary { background: var(--joao-secondary-500); border-color: var(--joao-secondary-500); color: #062033; }
.sermao-cronometro__acoes .btn-primary:hover { background: #40DAC9; border-color: #40DAC9; }
.sermao-cronometro__acoes .btn:focus-visible { outline-color: var(--joao-on-palco); box-shadow: 0 0 0 3px color-mix(in srgb, var(--joao-on-palco) 45%, transparent); }

/* Resumo do sermao: e texto de leitura, entao ganha medida e entrelinha. */
.sermao-resumo { max-width: var(--joao-medida-leitura); }

@media (max-width: 640px) {
  .sermao-cronometro__acoes { flex-direction: column; align-items: stretch; }
  .sermao-cronometro__acoes .btn { width: 100%; }
  .sermao-biblia__verso { flex-direction: column; align-items: stretch; }
  .sermao-biblia__verso .btn { width: 100%; }
  .sermao-referencia-lista { grid-template-columns: 1fr; }
}

/* Botao de inscricao em evento (Portal) - a classe existia sem regra. */
.btn-checkout { display: inline-flex; align-items: center; justify-content: center; }

/*
  ==========================================================================
  ZOOM 200% E TOQUE
  ==========================================================================
  Em 200% de zoom uma tela de 1280px vira 640px logicos: tudo que dependia
  de largura fixa precisa ceder. Nenhuma grade abaixo usa px fixo.
*/
.form-grid { grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); max-width: 860px; }
.form-span-2 { grid-column: 1 / -1; }
.relatorio-grid { grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr)); }
.sermao-topicos-grid { grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); }
.dashboard-pulso { grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr)); }
/* O campo tem 42px e o alvo de toque pede 44px: com o dedo, o campo cresce
   para 44 e o botão embutido acompanha. Não dá para o botão passar da altura
   do campo que o contém. */
@media (pointer: coarse) {
  .campo-acao > input { min-height: var(--joao-touch-min); }
  .campo-acao__botao { width: var(--joao-touch-min); }
}

/* Ponteiro grosso (dedo): todo controle interativo atinge o alvo minimo. */
@media (pointer: coarse) {
  .btn, .paginacao a, .tema-toggle, .topbar__user-btn,
  .topbar__user-menu a, .topbar__user-menu button { min-height: var(--joao-touch-min); }
  .tema-toggle { width: var(--joao-touch-min); }
  .tabela-registro__acoes a, .tabela-registro__acoes button { min-height: var(--joao-touch-min); }
  .abas__item { min-height: var(--joao-touch-min); }
  .convite-instalar__acao, .convite-instalar__fechar { min-height: var(--joao-touch-min); }
  .convite-instalar__fechar { width: var(--joao-touch-min); }
}

/*
  Rail: no desktop a coluna tem 76px, então só cabem monograma + nome curto —
  a descrição vai no title (tooltip). Na gaveta do celular há largura de
  sobra, e aí a descrição aparece como segunda linha, que é onde ela
  realmente ajuda quem não conhece o sistema.
*/
.rail__item-texto { display: flex; flex-direction: column; gap: .1rem; min-width: 0; text-align: left; }
.rail__item-descricao { display: none; }
@media (max-width: 900px) {
  .rail__item-texto { align-items: flex-start; }
  .rail__item-descricao {
    display: block;
    color: var(--joao-text-muted);
    font-size: .74rem;
    font-weight: 400;
    line-height: 1.3;
    text-align: left;
  }
  .rail__item.active .rail__item-descricao { color: var(--joao-text); }
}

/* Atalho de teclado: primeiro Tab da página pula a navegação inteira. */
.pular-para-conteudo {
  position: absolute;
  left: -9999px;
  z-index: 100;
  padding: .7rem 1.1rem;
  border-radius: var(--joao-radius-md);
  background: var(--joao-action);
  color: var(--joao-on-action);
  font-weight: 700;
  text-decoration: none;
}
.pular-para-conteudo:focus {
  left: .75rem;
  top: .75rem;
  outline: 2px solid var(--joao-primary-900);
  outline-offset: 2px;
}
#conteudo-principal:focus { outline: none; }

/* Formulário de tópico e de referência manual dentro do painel do sermão. */
.sermao-topico-form { margin-bottom: 1.5rem; }
.sermao-topico-form__acao { display: flex; align-items: flex-end; margin-bottom: 1rem; }
.sermao-topico-form__acao .btn { width: 100%; }
.sermao-referencia-form { display: flex; align-items: flex-end; gap: .75rem; max-width: 700px; margin-top: 1.25rem; }
.sermao-referencia-form .form-group { flex: 1 1 auto; min-width: 0; margin-bottom: 0; }
.sermao-referencia-form .btn { flex-shrink: 0; }
.sermao-painel--topicos { border-top-color: var(--joao-secondary-500); }
@media (max-width: 640px) {
  .sermao-referencia-form { flex-direction: column; align-items: stretch; }
  .sermao-referencia-form .btn { width: 100%; }
  .sermao-topico-form__acao { margin-bottom: 0; }
}

/*
  ==========================================================================
  UTILITÁRIOS DE COMPOSIÇÃO
  ==========================================================================
  Substituem os 86 atributos style= que estavam espalhados por 40 views.
  Cada um representava uma decisão de espaçamento tomada isoladamente — é a
  razão de nada bater entre telas. Agora o ritmo vem do mesmo lugar.
*/

/* Seção seguinte dentro de uma tela de edição. */
.page-header--secao { margin-top: var(--joao-space-6); }

/* Formulário curto acima de uma lista (matricular, convocar, movimentar). */
.form-grid--bloco { margin-bottom: var(--joao-space-5); }

/* Botão que fecha a linha do grid: alinha com a base dos campos e ocupa a
   coluna inteira no celular. */
.form-group--acao { display: flex; align-items: flex-end; }
.form-group--acao .btn { width: 100%; }
@media (max-width: 640px) { .form-group--acao { margin-bottom: 0; } }
.form-group--bloco { margin-bottom: var(--joao-space-5); }
.label--espacado { margin-top: var(--joao-space-3); }

/* Título de seção interna — o antigo <h2 style="font-size:1rem"> repetido. */
.secao-titulo {
  font-size: var(--joao-fs-lg);
  margin: 0 0 var(--joao-space-3);
  padding-bottom: var(--joao-space-2);
  border-bottom: 1px solid var(--joao-border);
}
.secao-titulo--espacada { margin-top: var(--joao-space-5); }
.subtitulo--espacado { margin-top: var(--joao-space-4); }

/* Pilha de cartões de leitura (avisos, eventos e pedidos no Portal). */
.lista-cards { display: grid; gap: var(--joao-space-4); }
.lista-cards--densa { gap: var(--joao-space-3); }

.card--compacto { padding: var(--joao-space-4); }
.card--empilhado { margin-bottom: var(--joao-space-4); }
.card--espacado { margin-top: var(--joao-space-5); }
.card h3 { margin: 0 0 var(--joao-space-2); font-size: var(--joao-fs-lg); }
.card .subtitulo { margin: 0 0 var(--joao-space-1); }
.card p:last-child { margin-bottom: 0; }
/* Conteúdo digitado pelo usuário: as quebras de linha são informação. */
.texto-preservado { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; max-width: var(--joao-medida-leitura); line-height: 1.65; }

.auth-card--centro { text-align: center; }
.ledger--bloco { margin-bottom: var(--joao-space-6); }
/* Entrada e saída no razão: a cor diferencia, mas o rótulo ao lado é quem
   informa — o valor nunca depende só do verde ou do vermelho. */
.ledger__valor--entrada { color: var(--joao-success-ink); }
.ledger__valor--saida { color: var(--joao-danger-ink); }

/* Sozinho no próprio bloco, é um alvo por si — precisa da altura mínima da
   2.5.8. A isenção de link em meio a frase não se aplica aqui. O piso é os
   24px da AA; o dedo ganha os 44px do token, como as demais regras de toque
   deste arquivo. Sem esse degrau, cada linha da lista Kids crescia 28px também
   no mouse, sem ninguém ganhar nada. */
.link-apoio {
  font-size: var(--joao-fs-sm);
  display: inline-flex;
  align-items: center;
  min-height: 24px;
}
@media (pointer: coarse) { .link-apoio { min-height: var(--joao-touch-min); } }
.codigo-destaque { font-family: var(--joao-font-display); font-size: 1.6rem; letter-spacing: .12em; }
.logo-miniatura { height: 40px; width: auto; margin-top: var(--joao-space-2); }
.campo-codigo { font-family: ui-monospace, "Cascadia Code", Consolas, monospace; font-size: .86rem; line-height: 1.6; }
.video-embed { display: block; width: 100%; aspect-ratio: 16 / 9; border: 0; border-radius: var(--joao-radius-md); }
.relatorio-card__acao { margin-top: var(--joao-space-3); }
.topbar--publica { justify-content: space-between; }
.swal2-select { width: 100%; }

/* ── Modal de composição de mensagem (e-mail / WhatsApp) ──
   O SweetAlert entra só como JANELA; o conteúdo é marcação do sistema.

   O modal antigo usava `swal2-input`/`swal2-textarea`: campos com altura,
   raio e anel de foco próprios, ao lado dos campos do projeto na mesma tela.
   E o Swal centraliza o conteúdo por padrão — texto centralizado sobre campos
   de largura total é o que dava a sensação de desalinho. Aqui tudo volta à
   esquerda e aos tokens. */
.modal-mensagem { text-align: left; }
/* O respiro lateral vive no POPUP, não no container do HTML: zerar o padding
   do container (para matar a margem própria do Swal) tirava junto a folga das
   laterais, e os campos encostavam na borda do modal. */
.modal-mensagem__popup {
  border-radius: var(--joao-radius-lg);
  padding: var(--joao-space-5, 1.5rem) !important;
}
.modal-mensagem__container { margin: 0 !important; padding: 0 !important; text-align: left !important; }

.modal-mensagem__cabecalho {
  display: flex;
  align-items: flex-start;
  gap: var(--joao-space-3);
  padding-bottom: var(--joao-space-3);
  border-bottom: 1px solid var(--joao-border);
}
.modal-mensagem__canal {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--joao-radius-md);
  background: var(--joao-tint-action);
  color: var(--joao-ink-action);
}
/* Verde só no WhatsApp: o acento identifica o canal antes de ler o título. */
.modal-mensagem__canal--whatsapp { background: var(--joao-tint-success); color: var(--joao-success-ink); }
.modal-mensagem__canal svg { width: 20px; height: 20px; }
.modal-mensagem__titulo {
  margin: 0;
  font-family: var(--joao-font-display);
  font-size: var(--joao-fs-h2);
  font-weight: 700;
  line-height: 1.25;
}
.modal-mensagem__destino {
  margin: .15rem 0 0;
  color: var(--joao-text-muted);
  font-size: var(--joao-fs-sm);
  /* Endereço de e-mail longo não tem espaço para quebrar e estouraria a
     largura do modal. */
  overflow-wrap: anywhere;
}
.modal-mensagem__nota {
  margin: var(--joao-space-3) 0 0;
  padding: var(--joao-space-3);
  background: var(--joao-tint-neutro);
  border-radius: var(--joao-radius-sm);
  color: var(--joao-text-muted);
  font-size: var(--joao-fs-sm);
  line-height: 1.5;
}
.modal-mensagem__campos { margin-top: var(--joao-space-4); }
.modal-mensagem__campos .form-group:last-child { margin-bottom: 0; }
.modal-mensagem textarea { resize: vertical; min-height: 8rem; }

/* Contador alinhado à direita, sob o campo. Tabular para o número não
   "pular" de largura a cada dígito enquanto se digita. */
.modal-mensagem__conta {
  margin: .25rem 0 0;
  color: var(--joao-text-muted);
  font-size: .72rem;
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.modal-mensagem__conta.is-limite { color: var(--joao-warning-ink); font-weight: 600; }

/* Erro junto do campo, não na barra do rodapé do Swal: lá embaixo obriga a
   procurar qual campo falhou. */
/* Colado ao campo que falhou, não num bloco no fim do modal: a mensagem lá
   embaixo obriga a ler o erro e procurar em cima a qual campo ele se refere. */
.modal-mensagem__erro {
  display: flex;
  align-items: baseline;
  gap: .4rem;
  margin: .3rem 0 0;
  color: var(--joao-danger-ink);
  font-size: var(--joao-fs-sm);
  font-weight: 600;
}
/* Símbolo além da cor: erro sinalizado só por vermelho não chega a quem não
   distingue esse tom (WCAG 1.4.1). */
.modal-mensagem__erro::before { content: "!"; flex: 0 0 auto; font-weight: 800; }
.modal-mensagem .is-invalido { border-color: var(--joao-danger); }
/* O anel de foco tem de sobreviver ao estado inválido: `.modal-mensagem
   .is-invalido` tem especificidade maior que `input:focus-visible` e apagava
   o anel — o campo ficava vermelho, mas sem indicação de onde está o cursor
   para quem navega por teclado. */
/* `:focus`, não `:focus-visible`. O foco aqui é movido por script quando a
   validação reprova, e foco programático NÃO ativa :focus-visible — medido no
   navegador. Sem isto o campo ficava só com a borda vermelha, sem indicar
   onde o cursor parou: quem enviou pelo teclado perde a posição. */
.modal-mensagem .is-invalido:focus {
  outline: 2px solid var(--joao-danger);
  outline-offset: 2px;
  box-shadow: 0 0 0 3px var(--joao-tint-danger);
}
/* A barra de validação nativa do Swal fica escondida: a mensagem já aparece
   junto do campo, e as duas juntas diriam a mesma coisa em dois lugares. */
.modal-mensagem__validacao { display: none !important; }

/* Dica à esquerda, contador à direita, na mesma linha: em linhas separadas
   sobrava uma faixa vazia entre o campo e a dica. */
.modal-mensagem__rodape-campo {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--joao-space-2);
  margin-top: .25rem;
}
.modal-mensagem__rodape-campo .form-hint { margin: 0; }
.modal-mensagem__rodape-campo .modal-mensagem__conta { margin: 0; }

.modal-mensagem__acoes {
  gap: var(--joao-space-3);
  /* `width` e `margin-inline` explícitos: o `.swal2-actions` do SweetAlert usa
     `margin: 1.25em auto` e `width: auto`, e as margens automáticas
     centralizavam o bloco de botões — que ficava desalinhado dos campos, mais
     estreito e no meio do modal. */
  width: 100% !important;
  margin: var(--joao-space-4) 0 0 !important;
  padding-top: var(--joao-space-4);
  border-top: 1px solid var(--joao-border);
  /* Ação principal à direita, como no resto do sistema (form-actions). */
  justify-content: flex-end !important;
}
@media (max-width: 640px) {
  /* Em coluna, o primário vai por cima: é o alvo mais provável e fica mais
     perto do polegar. `reverseButtons` do Swal já põe o confirmar por último
     no DOM, então a ordem visual é invertida aqui. */
  .modal-mensagem__acoes { flex-direction: column-reverse; align-items: stretch; }
  .modal-mensagem__acoes .btn { width: 100%; }
}

/* Título de um grupo de caixas de seleção (permissões, perfis). Era um
   <label> solto, que anuncia ao leitor de tela um campo inexistente. */
.form-grupo-titulo {
  margin: 0 0 var(--joao-space-2);
  color: var(--joao-text);
  font-size: var(--joao-fs-sm);
  font-weight: 700;
}
.form-check { margin-bottom: .35rem; }
.form-check label { min-height: 28px; cursor: pointer; }
@media (pointer: coarse) { .form-check label { min-height: var(--joao-touch-min); } }

/* Busca no cabeçalho: campo + ação + saída. */
.page-header__busca { gap: .5rem; align-items: center; }
.page-header__busca input { min-width: 15rem; }
@media (max-width: 900px) { .page-header__busca input { min-width: 0; flex: 1 1 100%; } }

/* Caixa de seleção: 17px é menor que o alvo mínimo de 24px (WCAG 2.2 2.5.8).
   O rótulo que a envolve é o alvo real, então ele ganha altura e área. */
/* min-width tambem: o radio nativo ignora width sozinho em alguns motores
   e ficava com 13px de largura contra 24px de altura. */
input[type="checkbox"], input[type="radio"] {
  width: 1.5rem;
  min-width: 1.5rem;
  height: 1.5rem;
  margin: 0;
  flex-shrink: 0;
}
.form-check label, label:has(> input[type="checkbox"]), label:has(> input[type="radio"]) {
  display: flex;
  align-items: center;
  gap: .5rem;
  min-height: 28px;
  padding: .25rem 0;
  font-weight: 400;
}

.auth-card__apoio { margin: .75rem 0 0; text-align: center; }

/*
  ── Marca nas telas de entrada ──
  No login do staff a assinatura é o assunto: é a primeira tela do produto e
  o nome só aparecia no título da aba. No Portal é o contrário — quem manda
  ali é a identidade da igreja, e o produto assina discreto no rodapé.
*/
.auth-card__marca { margin-bottom: 1.25rem; text-align: center; }
.auth-card__marca .marca-compacta {
  display: block;
  width: 100%;
  max-width: 178px;
  height: auto;
  margin: 0 auto;
  color: var(--joao-primary-900);
}
.auth-card__descritor {
  margin: .55rem 0 0;
  color: var(--joao-text-muted);
  font-size: var(--joao-fs-micro);
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.auth-card h1 { text-align: center; font-size: var(--joao-fs-h2); margin: 0 0 1.25rem; }

.auth-card__assinatura {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  margin: 1.5rem 0 0;
  padding-top: 1rem;
  border-top: 1px solid var(--joao-border);
}
.auth-card__assinatura span {
  color: var(--joao-text-muted);
  font-size: var(--joao-fs-micro);
  letter-spacing: .04em;
}
.auth-card__assinatura .marca-compacta {
  width: 84px;
  height: auto;
  color: var(--joao-text-muted);
  opacity: .9;
}

/*
  Campo preenchido por consulta externa (CNPJ, CEP). O realce dura poucos
  segundos: serve para o operador ver o que a busca escreveu sem ter que
  caçar campo por campo. Não é estado permanente, então não vira badge.
*/
.is-preenchido {
  border-color: var(--joao-action);
  background: var(--joao-tint-action);
  transition: background-color .4s ease, border-color .4s ease;
}
@media (prefers-reduced-motion: reduce) { .is-preenchido { transition: none; } }

/*
  ══════════════════════════════════════════════════════════════════════
  REPOSITÓRIO DE ARQUIVOS
  ══════════════════════════════════════════════════════════════════════
*/

/* Cartão do arquivo já anexado (logotipo em Configurações). Substitui o
   caminho interno cru num campo de texto: nome ilegível e editável, onde
   uma alteração errada apagava o logo sem aviso. */
.arquivo-atual {
  display: flex;
  align-items: center;
  gap: var(--joao-space-3);
  padding: var(--joao-space-3);
  margin-bottom: var(--joao-space-2);
  background: var(--joao-surface);
  border: 1px solid var(--joao-border);
  border-radius: var(--joao-radius-md);
}
.arquivo-atual__previa {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 76px;
  height: 48px;
  padding: .25rem;
  border-radius: var(--joao-radius-sm);
  /* Fundo institucional: o logo costuma ser claro e sumiria no branco. */
  background: var(--joao-palco);
}
.arquivo-atual__previa img { max-width: 100%; max-height: 100%; object-fit: contain; }
.arquivo-atual__dados { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.arquivo-atual__dados strong { font-size: var(--joao-fs-sm); overflow-wrap: anywhere; }
.arquivo-atual__dados span { color: var(--joao-text-muted); font-size: var(--joao-fs-micro); }
.arquivo-atual .btn { margin-left: auto; flex-shrink: 0; }

.form-rotulo { display: block; margin-bottom: .35rem; font-weight: 500; font-size: .88rem; }
.detalhe-avancado { margin-top: var(--joao-space-3); }
.detalhe-avancado > summary {
  cursor: pointer;
  padding: .35rem 0;
  color: var(--joao-ink-action);
  font-size: var(--joao-fs-sm);
  font-weight: 600;
}
.detalhe-avancado > summary:focus-visible { outline: 2px solid var(--joao-focus-cor); outline-offset: 2px; border-radius: var(--joao-radius-sm); }

/* Ocupação do banco. Fica no topo da tela porque é a restrição que o usuário
   precisa conhecer ANTES de escolher o arquivo. */
.cota {
  padding: var(--joao-space-4);
  margin-bottom: var(--joao-space-5);
  background: var(--joao-surface);
  border: 1px solid var(--joao-border);
  border-top: 3px solid var(--joao-action);
  border-radius: var(--joao-radius-md);
  box-shadow: var(--joao-shadow-sm);
}
.cota__cabecalho {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--joao-space-4);
  flex-wrap: wrap;
  margin-bottom: var(--joao-space-3);
}
.cota__cabecalho h2 { margin: .15rem 0 0; font-size: var(--joao-fs-h2); font-variant-numeric: tabular-nums; }
.cota__livre { color: var(--joao-text-muted); font-size: var(--joao-fs-sm); white-space: nowrap; }
.cota__livre strong { color: var(--joao-primary-900); font-variant-numeric: tabular-nums; }
.cota__trilho {
  height: 12px;
  border-radius: var(--joao-radius-pill);
  background: var(--joao-gray-100);
  overflow: hidden;
}
.cota__trilho > span {
  display: block;
  height: 100%;
  width: var(--valor, 0%);
  border-radius: inherit;
  background: var(--joao-action);
  transition: width .3s ease, background-color .3s ease;
}
/* Estado por cor E por texto: a nota abaixo muda junto, então quem não
   distingue as cores continua sabendo que o espaço está acabando. */
.cota__trilho.is-atencao > span { background: var(--joao-serie-3); }
.cota__trilho.is-critico > span { background: var(--joao-danger); }
.cota__nota { margin: var(--joao-space-2) 0 0; color: var(--joao-text-muted); font-size: var(--joao-fs-sm); }
.cota__trilho.is-critico ~ .cota__nota { color: var(--joao-danger-ink); font-weight: 600; }
@media (prefers-reduced-motion: reduce) { .cota__trilho > span { transition: none; } }

/* Lista de documentos */
.col-selecao { width: 2.75rem; }
.arquivo-descritivo {
  display: block;
  margin-top: .2rem;
  color: var(--joao-text-muted);
  font-size: var(--joao-fs-sm);
  overflow-wrap: anywhere;
}

/* Barra de envio dos marcados */
.envio-selecionados {
  padding: var(--joao-space-4);
  margin-top: var(--joao-space-4);
  background: var(--joao-surface);
  border: 1px solid var(--joao-border);
  border-left: 3px solid var(--joao-action);
  border-radius: var(--joao-radius-md);
  box-shadow: var(--joao-shadow-card);
}
.envio-selecionados__contagem { margin: 0 0 var(--joao-space-3); font-size: var(--joao-fs-base); }
.envio-selecionados__contagem strong { color: var(--joao-ink-action); font-variant-numeric: tabular-nums; }
.envio-selecionados .form-actions { margin-top: var(--joao-space-3); }

/*
  ── Distribuição de largura em tabela ──
  As .col-compacta encolhem ao conteúdo e devolvem a sobra às demais, que a
  repartem pelo algoritmo natural da tabela.

  A .col-flex NÃO pede largura. Ela já pediu: tinha `width: 100%`, que em
  `table-layout: auto` significa "quero a tabela inteira" — a sobra ia toda
  para ela e as colunas sem classe caíam no próprio min-content, que com o
  `overflow-wrap: anywhere` desta folha é um punhado de caracteres. Medido em
  Pessoa/Index a 1440px: nome 747px, e-mail 46px, linha de 235px de altura
  contra 54px sem marcação nenhuma — o e-mail virava uma fita vertical.
  Sem o `width`, a mesma tabela dá nome 345, congregação 268, e-mail 289 e
  linha de 88px, e o nome continua sendo a coluna mais larga, porque é o que
  o algoritmo natural já fazia. A .col-flex segue valendo: é ela que nomeia o
  título do cartão abaixo de 900px.
*/
.tabela-registro .col-compacta { width: 1%; white-space: nowrap; }
.tabela-registro th.num, .tabela-registro td.num { text-align: right; }
/* `width: 1%` só funciona em célula de tabela de verdade. Quando o próprio
   <td> é o contêiner flex das ações, ele sai do contexto de formatação de
   tabela e o 1% passa a valer ao pé da letra: medido, a célula ficava com
   16px e os links transbordavam para fora dela. Nesse padrão a largura fica
   automática — quem alinha é o flex. */
/* O `width` fica só no <td>, e só no padrão em que ele é célula de verdade.
   No <th> ele governava a coluna inteira em `table-layout: auto` — inclusive
   a das views cujo <td> é flex, que a exclusão acima já tinha liberado. Media
   77,5px para um conteúdo que pede 131,5px, e "Editar"/"Inativar" quebravam
   em duas linhas: a linha de Pessoa/Index ia a 88,5px contra 53,7px sem
   marcação nenhuma. */
.tabela-registro th.col-acoes { white-space: nowrap; text-align: right; }
.tabela-registro td.col-acoes:not(.tabela-registro__acoes) { width: 1%; white-space: nowrap; text-align: right; }
/* A coluna encolhe ao conteúdo, então as ações não podem quebrar linha:
   sem nowrap, "Baixar" e "Excluir" empilhavam uma sobre a outra. */
.tabela-registro td.col-acoes .tabela-registro__acoes { justify-content: flex-end; flex-wrap: nowrap; }

/*
  ── Janela modal (dialog nativo) ──
  Usado no envio de documentos. `<dialog>` já traz prisão de foco, Esc para
  fechar e backdrop pelo navegador — não precisa reimplementar nada disso, e
  o comportamento fica igual ao que o sistema operacional entrega.
*/
.modal-joao {
  width: min(560px, calc(100vw - 2rem));
  max-height: calc(100vh - 4rem);
  padding: 0;
  border: 1px solid var(--joao-border);
  border-radius: var(--joao-radius-lg);
  background: var(--joao-surface);
  color: var(--joao-text);
  box-shadow: var(--joao-shadow-pop);
}
.modal-joao::backdrop { background: rgba(8, 27, 46, .55); }
.modal-joao__cabecalho {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--joao-space-4);
  padding: var(--joao-space-4) var(--joao-space-5);
  border-bottom: 1px solid var(--joao-border);
}
.modal-joao__cabecalho h2 { margin: .1rem 0 0; font-size: var(--joao-fs-h2); }
.modal-joao__fechar {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 36px; height: 36px;
  border: 1px solid transparent;
  border-radius: var(--joao-radius-sm);
  background: none;
  color: var(--joao-text-muted);
  font-size: 1.3rem;
  line-height: 1;
  cursor: pointer;
}
.modal-joao__fechar:hover { background: var(--joao-tint-neutro); color: var(--joao-text); }
.modal-joao__fechar:focus-visible { outline: 2px solid var(--joao-focus-cor); outline-offset: 2px; }
.modal-joao__corpo { padding: var(--joao-space-5); overflow-y: auto; }
.modal-joao__corpo .form-grid { max-width: none; }
.modal-joao__rodape {
  display: flex;
  flex-wrap: wrap;
  gap: var(--joao-space-3);
  padding: var(--joao-space-4) var(--joao-space-5);
  border-top: 1px solid var(--joao-border);
  background: var(--joao-bg);
  border-radius: 0 0 var(--joao-radius-lg) var(--joao-radius-lg);
}
.modal-joao__rodape .btn { flex: 1 1 auto; }
@media (pointer: coarse) { .modal-joao__fechar { width: var(--joao-touch-min); height: var(--joao-touch-min); } }

/* Lista dos documentos que vão no envio — confirma o que foi marcado. */
.modal-joao__itens { margin: 0 0 var(--joao-space-4); padding: 0; list-style: none; display: grid; gap: .3rem; max-height: 9rem; overflow-y: auto; }
.modal-joao__itens li {
  display: flex;
  justify-content: space-between;
  gap: var(--joao-space-3);
  padding: .35rem .6rem;
  border-radius: var(--joao-radius-sm);
  background: var(--joao-tint-action);
  font-size: var(--joao-fs-sm);
}
.modal-joao__itens span:last-child { color: var(--joao-text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }

/*
  Barra de seleção fixa no rodapé: substitui o bloco de formulário que ficava
  embaixo da lista empurrando a página. Aparece só quando há algo marcado.
*/
.selecao-barra {
  position: sticky;
  bottom: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: var(--joao-space-3);
  flex-wrap: wrap;
  padding: var(--joao-space-3) var(--joao-space-4);
  margin-top: var(--joao-space-4);
  background: var(--joao-surface);
  border: 1px solid var(--joao-border);
  border-left: 3px solid var(--joao-action);
  border-radius: var(--joao-radius-md);
  box-shadow: var(--joao-shadow-pop);
}
.selecao-barra__contagem { margin: 0; margin-right: auto; font-size: var(--joao-fs-base); }
.selecao-barra__contagem strong { color: var(--joao-ink-action); font-variant-numeric: tabular-nums; }
@media (max-width: 640px) {
  .selecao-barra { flex-direction: column; align-items: stretch; }
  .selecao-barra .btn { width: 100%; }
  .selecao-barra__contagem { margin-right: 0; text-align: center; }
}

/*
  ══════════════════════════════════════════════════════════════════════
  LISTAS EM MODO COMPACTO — a tabela vira cartão
  ══════════════════════════════════════════════════════════════════════
  A maior tabela do sistema tem 7 colunas. Num celular de 375px elas
  rolavam de lado dentro do contêiner: não quebravam a página, mas ninguém
  operava assim.

  O `display: block` que faz o cartão APAGA a semântica de tabela para
  leitor de tela. Por isso a marcação declara role="table"/"row"/"cell" —
  sem isso, isto aqui consertaria o visual e quebraria a leitura assistiva.
  TabelaResponsivaTests reprova célula sem role e sem data-rotulo.
*/
@media (max-width: 900px) {
  /*
    Tudo aqui é escopado por [role="table"], que o script só grava nas tabelas
    convertidas. Sem esse escopo, a tabela de valores do Dashboard — que é
    isenta da conversão — receberia as regras de cartão e perderia a rolagem,
    estourando a página em 375px. O CSS não conhece a lista de isenções; o
    atributo é o que faz a ponte entre a decisão do script e a folha de estilo.
  */

  /* O contêiner de rolagem perde a razão de existir quando o que está dentro
     virou cartão. Quando não virou (Dashboard), a rolagem continua.
     Os gráficos do Dashboard usam .dashboard-grafico-scroll, classe própria
     e intocada por esta entrega — eles continuam rolando de lado, como a
     spec determina: gráfico não vira cartão. */
  .tabela-scroll:has(.tabela-registro[role="table"]) { overflow-x: visible; }

  .tabela-registro[role="table"] {
    /* Cai junto com a conversão: se sobreviver, o cartão herda um piso de
       640px e a página estoura — mesma classe de bug que já apareceu duas
       vezes neste projeto. */
    min-width: 0;
    border-collapse: separate;
    border-spacing: 0;
    display: block;
  }

  /* O cabeçalho some: cada valor passa a carregar o próprio rótulo. */
  .tabela-registro[role="table"] thead { display: none; }
  .tabela-registro[role="table"] tbody { display: block; }

  .tabela-registro[role="table"] tbody tr {
    display: block;
    padding: var(--joao-space-3) var(--joao-space-4);
    margin-bottom: var(--joao-space-3);
    background: var(--joao-surface);
    border: 1px solid var(--joao-border);
    border-left: 3px solid var(--joao-action);
    border-radius: var(--joao-radius-md);
    box-shadow: var(--joao-shadow-sm);
  }
  .tabela-registro[role="table"] tbody tr:last-child { margin-bottom: 0; }

  .tabela-registro[role="table"] td {
    display: grid;
    /* O teto importa tanto quanto o piso: com `34%` puro a coluna do rótulo
       escalava com o cartão e chegava a 277px a 899px — a palavra "DATA" em
       fs-micro segurando um terço da largura, e o valor começando no meio da
       linha. O `min()` fecha em 11rem. */
    grid-template-columns: minmax(6.5rem, min(34%, 11rem)) 1fr;
    gap: var(--joao-space-3);
    align-items: baseline;
    padding: .35rem 0;
    border-bottom: 0;
  }
  .tabela-registro[role="table"] td::before {
    content: attr(data-rotulo);
    color: var(--joao-text-muted);
    font-size: var(--joao-fs-micro);
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
  }

  /*
    As colunas estreitas da tabela (`width: 1%` + `nowrap`, regra da lista
    ampla) não sobrevivem ao cartão: espremiam a célula a ~3px e o nowrap
    empurrava valor longo para fora, fazendo a PÁGINA inteira rolar de lado —
    exatamente o que este bloco existe para impedir.
  */
  .tabela-registro[role="table"] td.col-compacta {
    width: auto;
    white-space: normal;
  }

  /*
    Todo filho do valor vai para a coluna 2 e encosta no início dela.
    Sem isto, dois defeitos que o teste não pega:
    (a) o segundo filho caía na coluna do RÓTULO por auto-placement — o badge
        ficava alinhado sob o rótulo, lido como se fosse outro campo;
    (b) o badge, blockificado como item da grade, esticava na largura inteira
        da coluna em vez de ficar do tamanho do conteúdo.
    Nos td que são block ou flex (título, seleção, ações) as duas
    declarações não se aplicam e são inertes.
  */
  .tabela-registro[role="table"] td > * {
    grid-column: 2;
    justify-self: start;
  }

  /* A coluna-título vira o cabeçalho do cartão: é o nome da pessoa, o título
     do documento. Já é o assunto — repetir o rótulo seria ruído.

     Quem manda é a `col-flex`. A primeira célula só assume o papel quando a
     linha NÃO tem `col-flex` — é o fallback das listas que nunca receberam
     marcação de coluna. Sem o `:not(:has(...))` as duas regras valem juntas
     onde a coluna-título não é a primeira (Lançamento abre por Pessoa, mas a
     primeira coluna é Data) e o cartão ganha dois títulos, ambos sem rótulo. */
  .tabela-registro[role="table"] td.col-flex,
  .tabela-registro[role="table"] tr:not(:has(td.col-flex)) > td:first-child:not(.col-compacta):not(.col-acoes):not(.tabela-registro__acoes) {
    display: block;
    padding-top: 0;
    padding-bottom: var(--joao-space-2);
    font-size: var(--joao-fs-lg);
  }
  .tabela-registro[role="table"] td.col-flex::before,
  .tabela-registro[role="table"] tr:not(:has(td.col-flex)) > td:first-child:not(.col-compacta):not(.col-acoes):not(.tabela-registro__acoes)::before {
    content: none;
  }

  /* Célula de seleção fica no topo, sem rótulo — a caixa se explica. */
  .tabela-registro[role="table"] td.col-compacta:has(input[type="checkbox"]) {
    display: block;
    padding-bottom: var(--joao-space-2);
  }
  .tabela-registro[role="table"] td.col-compacta:has(input[type="checkbox"])::before { content: none; }

  /*
    Ações viram faixa no rodapé do cartão, com alvo de toque cheio.

    Há duas formas legítimas na marcação e as duas precisam ser atendidas:
    26 views põem a classe no próprio <td> (`td.tabela-registro__acoes`, o td
    É o contêiner flex) e uma usa `td.col-acoes` com um <span> flex dentro.
    Uniformizar as 26 seria churn sem ganho — quem cobre os dois casos é aqui.

    O `width: auto` derruba o `width: 1%` da regra de coluna estreita da
    tabela: ele sobrevive ao display:block e espremia a faixa a ~3px, com as
    ações empilhando uma por linha.
  */
  .tabela-registro[role="table"] td.col-acoes,
  .tabela-registro[role="table"] td.tabela-registro__acoes {
    display: block;
    width: auto;
    margin-top: var(--joao-space-2);
    padding-top: var(--joao-space-3);
    border-top: 1px solid var(--joao-border);
    text-align: left;
  }
  .tabela-registro[role="table"] td.col-acoes::before,
  .tabela-registro[role="table"] td.tabela-registro__acoes::before { content: none; }

  /* Quando o próprio td é o contêiner flex ele precisa voltar a ser flex: a
     regra genérica de td o tinha transformado em grid de duas colunas, e o
     ::before vazio ficava com a primeira. Tem de vir DEPOIS do display:block
     acima, senão perde. */
  .tabela-registro[role="table"] td.tabela-registro__acoes {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: var(--joao-space-4);
  }
  .tabela-registro[role="table"] td.col-acoes .tabela-registro__acoes {
    justify-content: flex-start;
    flex-wrap: wrap;
    gap: var(--joao-space-4);
  }

  /* Valor numérico volta a alinhar à esquerda: em cartão não há coluna com
     que alinhar, e à direita ele descolava do próprio rótulo. */
  .tabela-registro[role="table"] td.num { text-align: left; }
}

/*
  ── Convite de instalacao ──
  Fica no pe da gaveta e no pe do Portal, nunca por cima do conteudo. E o
  unico elemento que aparece por iniciativa propria, entao pesa pouco: sem
  fundo forte, sem icone, separado so por um filete.
*/
/* ── Convite de instalação (botão flutuante) ──
   Ancorado ao canto da janela, não ao fim do documento: dentro da rail ele só
   existia com a gaveta aberta, e abaixo de 900px a gaveta começa fechada — o
   convite não aparecia justamente no aparelho onde instalar faz sentido.

   `env(safe-area-inset-*)` porque o Portal roda em celular: sem isso o botão
   fica sob a barra de gestos do iPhone e vira alvo intocável. */
.convite-instalar {
  position: fixed;
  right: max(var(--joao-space-4), env(safe-area-inset-right));
  bottom: max(var(--joao-space-4), env(safe-area-inset-bottom));
  z-index: 60;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--joao-space-2);
  max-width: min(20rem, calc(100vw - 2 * var(--joao-space-4)));
}
.convite-instalar__pilula {
  display: flex;
  align-items: stretch;
  border-radius: var(--joao-radius-pill, 99px);
  background: var(--joao-surface);
  border: 1px solid var(--joao-border);
  box-shadow: var(--joao-shadow-card);
  overflow: hidden;
}
.convite-instalar__acao {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  padding: .6rem .5rem .6rem .7rem;
  border: 0;
  background: transparent;
  color: var(--joao-text);
  font-family: var(--joao-font-display);
  font-size: var(--joao-fs-sm);
  font-weight: 700;
  cursor: pointer;
}
.convite-instalar__acao:hover { background: var(--joao-tint-action); color: var(--joao-ink-action); }
.convite-instalar__marca {
  display: inline-flex;
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  color: var(--joao-ink-action);
}
.convite-instalar__marca svg { width: 100%; height: 100%; }
.convite-instalar__rotulo { white-space: nowrap; }
.convite-instalar__fechar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.2rem;
  padding: 0;
  border: 0;
  border-left: 1px solid var(--joao-border);
  background: transparent;
  color: var(--joao-text-muted);
  cursor: pointer;
}
.convite-instalar__fechar svg { width: 15px; height: 15px; }
.convite-instalar__fechar:hover { background: var(--joao-tint-neutro); color: var(--joao-text); }
.convite-instalar__acao:focus-visible, .convite-instalar__fechar:focus-visible {
  outline: 2px solid var(--joao-focus-cor);
  outline-offset: -2px;
}
/* Balão de instrução — só o iOS o usa, onde não há API de instalação. */
.convite-instalar__balao {
  margin: 0;
  padding: var(--joao-space-3) var(--joao-space-4);
  border-radius: var(--joao-radius-md);
  background: var(--joao-surface);
  border: 1px solid var(--joao-border);
  box-shadow: var(--joao-shadow-card);
  color: var(--joao-text);
  font-size: var(--joao-fs-sm);
  line-height: 1.5;
}
