/*
 * app.css — Estilos customizados do projeto, partilhados por todas as páginas
 * Carregado uma vez em partials/head.php
 */

:root {
  --accent: #206bc4;
  --accent-light: #e8f0fb;
  /* Itens do menu (topnav-link) — deliberadamente mais suave que o
     nome da app (.topbar-brand, sempre na cor cheia) para dar
     hierarquia visual. color-mix() combina a cor de texto REAL da
     barra (--cor-texto-topbar, configurável em Definições) com 35%
     de preto, preservando essa distinção mesmo quando a cor muda —
     antes era um cinzento fixo (#a8b5c8), sempre igual
     independentemente de --cor-topbar/--cor-texto-topbar. */
  --sidebar-text: color-mix(in srgb, var(--cor-texto-topbar, #fff) 75%, #000 25%);
}

/* Tamanho base de toda a app.
 *
 * :root e nao html: o Tabler define ':root{font-size:16px}', e o
 * :root tem MAIOR especificidade que o html -- uma regra 'html'
 * aqui era simplesmente ignorada, por muito que viesse depois.
 * Levou um bocado a descobrir.
 *
 * Quase todo o CSS usa rem, que se calcula a partir daqui: mudar
 * este valor aumenta ou reduz a app inteira em proporcao.
 */
:root { font-size: 16px; }

/* Portateis de 13 a 15 polegadas (ate 1600 de largura).
 *
 * Num ecra destes o texto das celulas ficava a 13px e os
 * cabecalhos a 10,9px -- pequeno demais para se ler o dia todo.
 * A 18px passam a 14,8px e 12,2px.
 *
 * Perdem-se umas linhas por ecra, e e o compromisso certo: mais
 * vale ver menos e ler bem.
 */
@media (max-width: 1600px) {
  :root { font-size: 18px; }
}

body { background: var(--cor-fundo-app, #f0f4f8); font-family: 'Inter', sans-serif; }

[x-cloak] { display: none !important; }

/* Cor das checkboxes (nativas do browser) em toda a aplicação — usa
   a Cor Principal configurável, em vez do azul por defeito do browser.
   accent-color é suportado por todos os browsers modernos. */
input[type="checkbox"] { accent-color: var(--accent); }

/* ── Topbar horizontal (substitui a antiga sidebar vertical) ────── */
.topbar {
  background: var(--cor-topbar, var(--texto-principal, #1a2332)); border-bottom: 1px solid rgba(255,255,255,0.08);
  padding: 0 1.5rem; height: 56px;
  display: flex; align-items: center; justify-content: space-between;
  position: sticky; top: 0; z-index: 100;
}
.topbar-esquerda { display: flex; align-items: center; gap: 2rem; height: 100%; }
.topbar-brand { color: var(--cor-texto-topbar, #fff); font-size: 1rem; font-weight: 700; white-space: nowrap; }

.topnav { display: flex; align-items: center; gap: 0.25rem; height: 100%; }
.topnav-link {
  display: flex; align-items: center; gap: 0.45rem;
  padding: 0 0.85rem; height: 56px;
  color: var(--sidebar-text); text-decoration: none; font-size: 0.85rem;
  border-bottom: 2px solid transparent; transition: all 0.15s; cursor: pointer;
  background: none; border-top: none; border-left: none; border-right: none;
  white-space: nowrap;
}
.topnav-link:hover { color: #fff; }
.topnav-link.active { color: #fff; border-bottom-color: var(--accent); }
.topnav-link svg { width: 16px; height: 16px; flex-shrink: 0; }

.topnav-mais { position: relative; height: 100%; }
.topnav-dropdown {
  position: absolute; top: 100%; left: 0; margin-top: 1px;
  background: #fff; border: 1px solid #e5e9f0; border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.12); min-width: 180px; padding: 0.4rem;
  z-index: 110;
}
.topnav-dropdown-item {
  display: block; padding: 0.5rem 0.75rem; border-radius: 6px;
  color: var(--texto-secundario, #374151); text-decoration: none; font-size: 0.85rem;
}
.topnav-dropdown-item:hover { background: #f0f4f8; }
.topnav-dropdown-item.active { color: var(--accent); font-weight: 600; }

.topbar-direita { display: flex; align-items: center; gap: 0.75rem; }

/* SUPER-ADMIN — elementos visíveis SÓ a ele, na topbar (ver
   partials/topbar.php). Discretos de propósito: são ferramentas de
   administração, nunca devem competir com a navegação normal. */
.btn-topo-superadmin {
  background: rgba(255,255,255,0.12);
  color: #fff;
  border: 1px solid rgba(255,255,255,0.25);
  border-radius: 5px;
  padding: 0.3rem 0.7rem;
  font-size: 0.78rem;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
}
.btn-topo-superadmin:hover { background: rgba(255,255,255,0.22); }

/* "a vestir" — aviso real de que a app está a ser vista como outra
   pessoa. Cor de aviso (âmbar) de propósito: é um estado invulgar,
   deve mesmo saltar à vista de quem o está a usar. */
.aviso-vestindo {
  background: #f59e0b;
  color: #1a2332;
  border-radius: 5px;
  padding: 0.25rem 0.6rem;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.btn-logout-topo {
  background: none; border: none; cursor: pointer; color: var(--sidebar-text);
  padding: 0.4rem; border-radius: 6px; display: flex; transition: all 0.15s;
}
.btn-logout-topo:hover { color: #fff; background: rgba(255,255,255,0.08); }
.btn-logout-topo svg { width: 17px; height: 17px; }

.avatar {
  width: 30px; height: 30px; border-radius: 50%; background: var(--accent); color: #fff;
  display: flex; align-items: center; justify-content: center; font-size: 0.75rem; font-weight: 600;
  flex-shrink: 0;
}
.user-nome { font-size: 0.83rem; color: #fff; }
.app-page-body { padding: 1.5rem; }

/* Em ecrãs mais estreitos, esconde os nomes dos itens principais e
   mostra só os ícones, para tudo continuar a caber sem sobrepor */
@media (max-width: 860px) {
  .topnav-link span, .topnav-link { font-size: 0; gap: 0; padding: 0 0.6rem; }
  .topnav-link svg { width: 18px; height: 18px; }
  .topbar-brand { display: none; }
}

/* Estatísticas */
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 1.5rem; }
.stat {
  background: #fff; border-radius: 8px; padding: 1.1rem 1.25rem;
  border: 1px solid #e5e9f0; display: flex; align-items: center; gap: 1rem;
}
.stat-icon {
  width: 44px; height: 44px; border-radius: 8px;
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.stat-icon svg { width: 22px; height: 22px; }
.stat-label { font-size: 0.75rem; color: var(--texto-secundario, #6b7a90); margin-bottom: 2px; }
.stat-value { font-size: 1.5rem; font-weight: 700; color: var(--texto-principal, #1a2332); line-height: 1; }

/* Cards e tabela */
.card { background: var(--cor-caixa-geral, #fff); border-radius: 8px; border: 1px solid #e5e9f0; overflow: hidden; }

/* Página "Mapas" (mapas.php) — cartões clicáveis, um por Vista/Mapa
   (só os que são AMBOS is_vista E is_mapa). Grelha responsiva,
   preenche o espaço disponível com quantos cartões couberem por
   linha, sem nunca ficarem demasiado estreitos nem demasiado largos. */
.mapas-grelha-cartoes {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 1rem; padding: 1.25rem;
}
.mapa-cartao {
  display: flex; flex-direction: column; align-items: center; gap: 0.75rem;
  padding: 1.5rem 1rem; border: 1px solid #e5e9f0; border-radius: 10px;
  background: #fafbfd; cursor: pointer; text-align: center;
  transition: border-color 0.15s, box-shadow 0.15s, transform 0.1s;
}
.mapa-cartao:hover {
  border-color: #206bc4; box-shadow: 0 4px 12px rgba(32,107,196,0.12);
  transform: translateY(-2px);
}
.mapa-cartao-icone {
  width: 48px; height: 48px; border-radius: 50%;
  background: #eaf2fc; color: #206bc4;
  display: flex; align-items: center; justify-content: center;
}
.mapa-cartao-titulo { font-size: 0.9rem; font-weight: 600; color: #1a2332; }
/* Link "Ver PDF" — pequeno texto clicável extra dentro de cada
   cartão (ver mapas.php), para abrir o PDF diretamente sem passar
   pela lista. Deliberadamente discreto (menor, cor mais clara) para
   não competir visualmente com o título do cartão, que continua a
   ser a ação principal (clicar no cartão inteiro abre a lista). */
.mapa-cartao-link-pdf {
  font-size: 0.75rem; color: #6b7a90; text-decoration: none;
  padding: 2px 8px; border-radius: 4px; transition: background 0.15s, color 0.15s;
}
.mapa-cartao-link-pdf:hover { background: #eaf2fc; color: #206bc4; }

/* Construtor de Mapas Personalizados — layout esquerda/direita:
   painel esquerdo com as definições do Mapa (largura fixa, com
   scroll próprio se o conteúdo crescer mais que o ecrã), painel
   direito com o <iframe> da lista real de Utentes (ocupa o resto do
   espaço, altura generosa mas finita — um <iframe> sem altura
   definida colapsa para 0px, por isso nunca deixar isto "automático"). */
.construtor-mapa-layout {
  display: flex; gap: 0; align-items: stretch;
  height: calc(100vh - 200px); min-height: 500px;
}
.construtor-mapa-painel-esquerdo {
  flex-shrink: 0; width: 420px; padding: 1.25rem;
  overflow-y: auto; border-right: 1px solid #e5e9f0;
}
.construtor-mapa-painel-direito {
  flex: 1; min-width: 0; background: #fafbfd;
}
.construtor-mapa-iframe {
  width: 100%; height: 100%; border: none; display: block;
}

/* Página de Definições — layout esquerda/direita: menu de secções à
   esquerda (largura fixa), conteúdo da secção escolhida à direita
   (ocupa o resto do espaço). */
.definicoes-layout {
  display: flex; gap: 1.5rem; max-width: 900px; margin: 0 auto; align-items: flex-start;
}
.definicoes-menu {
  flex-shrink: 0; width: 220px; display: flex; flex-direction: column; gap: 0.15rem;
  background: var(--cor-caixa-geral, #fff); border-radius: 8px; border: 1px solid #e5e9f0;
  padding: 0.5rem;
}
.definicoes-menu-item {
  text-align: left; padding: 0.6rem 0.75rem; border-radius: 6px;
  background: none; border: none; cursor: pointer;
  color: var(--texto-secundario, #4b5768); font-size: 0.85rem; transition: all 0.15s;
}
.definicoes-menu-item:hover { background: #f0f4f8; color: var(--accent); }
.definicoes-menu-item.active { background: var(--accent); color: #fff; font-weight: 600; }
.definicoes-conteudo { flex: 1; min-width: 0; }
.card-header {
  padding: 0.5rem 1.25rem;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  flex-wrap: wrap;
  border-bottom: none;
  margin-bottom: 0.5rem;
}
.card-header-title { font-weight: 600; font-size: 0.95rem; color: var(--texto-principal, #1a2332); }
.ficha-identificador {
  display: block; font-size: 0.78rem; color: var(--texto-secundario, #6b7a90); margin-top: 0.1rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
.search-box {
  display: flex; align-items: center; gap: 0.5rem; background: var(--cor-pesquisa, #f0f4f8);
  border: 1px solid #e5e9f0; border-radius: 6px; padding: 0.4rem 0.75rem; width: 220px;
}
.search-box input { border: none; background: none; outline: none; font-size: 0.85rem; width: 100%; }
.search-box svg { width: 15px; height: 15px; color: var(--texto-secundario, #6b7a90); flex-shrink: 0; }

.btn-primary {
  background: var(--accent); color: #fff; border: none; border-radius: 6px;
  padding: 0.45rem 1rem; font-size: 0.85rem; font-weight: 500; cursor: pointer;
  display: flex; align-items: center; gap: 0.4rem; transition: background 0.15s;
}
.btn-primary:hover { background: var(--accent-hover, #1a5baf); }
.btn-primary:disabled { opacity: 0.7; cursor: not-allowed; }
.btn-primary svg { width: 15px; height: 15px; }

.btn-secondary {
  background: #fff; color: var(--texto-secundario, #374151); border: 1px solid #d1d5db; border-radius: 6px;
  padding: 0.45rem 1rem; font-size: 0.85rem; font-weight: 500; cursor: pointer; transition: all 0.15s;
}
.btn-secondary:hover { background: #f9fafb; }

.btn-danger { background: #dc2626; color: #fff; border: none; border-radius: 6px; padding: 0.45rem 1rem; font-size: 0.85rem; font-weight: 500; cursor: pointer; }
.btn-danger:hover { background: #b91c1c; }

.filter-row {
  display: flex; gap: 0.3rem; align-items: center; padding: 0.0rem 1rem 0.5rem 1.5rem;
  background: var(--cor-caixa-lista, #fafbfd);
  /* Passa à linha quando nao cabem (a pedido do utilizador: com 24
   * salas, os chips saiam do ecra). row-gap separa as linhas entre si. */
  flex-wrap: wrap;
  row-gap: 0.3rem;
}
/* A etiqueta ("Sala:") nunca encolhe nem passa a linha sozinha */
.filter-row > .filter-label { flex-shrink: 0; }
.filter-label { font-size: 0.7rem; color: var(--texto-secundario, #6b7a90); }
.filter-chip {
  padding: 0.15rem 0.55rem; border-radius: 20px; border: 1px solid #e5e9f0; background: #fff;
  font-size: 0.7rem; color: var(--texto-secundario, #6b7a90); cursor: pointer; transition: all 0.15s;
  /* O texto do chip nunca parte a meio ("SAD A." ficava em 2 linhas) */
  white-space: nowrap;
  flex-shrink: 0;
}
.filter-chip.active, .filter-chip:hover { background: var(--accent); border-color: var(--accent); color: #fff; }

table { width: 100%; border-collapse: collapse; }
/* A tabela principal (a única com 2 linhas de cabeçalho sticky — nomes
   de coluna + campos de filtro) precisa de border-collapse:separate,
   não collapse — com collapse, as bordas das células ficam "presas"
   ao fluxo normal do documento em vez de ao elemento sticky, criando
   uma pequena fresta entre as duas linhas sticky onde as linhas de
   dados (tbody), ao passar por trás durante o scroll, ficam
   visualmente por CIMA do cabeçalho em vez de por baixo — exatamente
   o problema de "duas linhas de cabeçalho sticky" já documentado como
   uma limitação conhecida de border-collapse:collapse combinado com
   sticky em <th>. border-spacing:0 evita introduzir espaço visual
   extra entre células, que normalmente viria com "separate". */
.tabela-lista-com-filtros { border-collapse: separate; border-spacing: 0; }
/* Cor própria (--cor-cabecalho-lista, mais escura por defeito que o
   resto da lista) para as 2 linhas de cabeçalho da tabela principal —
   mais específica que a regra genérica "th" acima, para não afetar
   os cabeçalhos de outras tabelas do projeto (Mapas fixos, Mapas
   Personalizados), que continuam a usar --cor-caixa-lista. */
.tabela-lista-com-filtros th { background: var(--cor-cabecalho-lista, #e5e9f0); }
thead tr { border-bottom: 2px solid #c7cfdb; }
th {
  text-align: left; font-size: 0.68rem; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--texto-secundario, #6b7a90);
  /* Padding inferior reduzido (de 0.35rem para 0.15rem) — só o
     ESPAÇO ENTRE o nome da coluna e o campo "Filtrar..." por baixo,
     não o espaço ACIMA do texto (padding-top mantido em 0.35rem).
     Horizontal reduzido de 1rem para 0.5rem, consistente com td. */
  padding: 0.35rem 0.5rem 0.15rem;
  /* white-space: nowrap garante SEMPRE 1 única linha — combinado com
     abreviarNomeColuna() (ver tabela-lista.js), que já reduz nomes
     compostos ("Código Postal" -> "Código P.") antes de sequer
     chegar aqui. min-height reduzido de 1.8rem para 1.2rem, já que a
     razão original de precisar de espaço para 2 linhas deixou de
     existir — o "top" calculado para a linha de filtros por baixo
     (ver .linha-filtros-coluna th) continua a funcionar bem, agora
     com uma altura sempre previsível. */
  white-space: nowrap;
  min-height: 1.2rem; box-sizing: border-box;
  /* Sticky: o cabeçalho fica sempre visível ao rolar as linhas — o
     background sólido é essencial aqui, senão o texto das linhas
     por baixo "atravessa" visualmente o cabeçalho ao passar por trás.
     Mesma cor da linha de filtros por baixo (--cor-caixa-lista),
     para as duas linhas ficarem visualmente uma só unidade — antes
     esta usava um branco fixo, que destoava sempre que a Cor da
     Caixa da Lista fosse configurada como algo diferente de branco. */
  position: sticky; top: 0; background: var(--cor-caixa-lista, #fff); z-index: 5;
}
td {
  /* Padding horizontal reduzido de 1rem (16px) para 0.5rem (8px) —
     menos espaço entre colunas, mais dados visíveis sem scroll
     horizontal. Vertical mantido intacto. */
  padding: 0.28rem 0.5rem;
  border-bottom: 1px solid #c7cfdb;
  /* Texto NUNCA parte a meio (a pedido do utilizador).
   *
   * Antes, com nomes como "Ana Silva Santos" numa coluna de 82px,
   * quase todas as células ocupavam 2 ou 3 linhas: medidas 156 de
   * 158. A lista mostrava 14 linhas onde cabiam 25, e ler de cima a
   * baixo era penoso porque a altura variava de linha para linha.
   *
   * Cada linha passa a ter a mesma altura, e as colunas ficam com a
   * largura de que precisam — a tabela usa scroll horizontal quando
   * não cabe, que a lista já suporta. */
  white-space: nowrap;
  /* Reduzido de 0.875rem (14px) para 0.82rem (13.1px) — o texto das
     células era, na prática, o maior elemento denso da interface,
     criando um contraste de tamanho desproporcionado face aos
     cabeçalhos e resto da app. 0.82rem alinha com .tabela-preview,
     já usado noutro sítio da app com esse mesmo tamanho. */
  font-size: 0.82rem; color: var(--texto-principal, #2d3748);
  /* Fundo BASE de cada linha de dados — distinto de :hover/selecionada
     abaixo, que só se veem em interação. transparent por defeito,
     herda sempre a cor da caixa por trás (comportamento de sempre,
     antes desta variável existir). */
  background: var(--cor-fundo-linha, transparent);
}
tr:last-child td { border-bottom: none; }
/* Linhas alternadas (zebra striping) — só as ÍMPARES (1ª, 3ª, 5ª...)
   recebem --cor-linha-intercalada; as pares continuam com
   --cor-fundo-linha (já definida em td, normalmente transparente).
   :nth-child em vez de uma classe JS: funciona automaticamente com
   qualquer número de linhas, sem depender do Alpine.js calcular
   índice nenhum. Vem ANTES de :hover/.linha-selecionada de propósito
   — a ordem no ficheiro dá a esses maior especificidade prática,
   garantindo que continuam a ganhar mesmo em linhas ímpares. */
tbody tr:nth-child(odd) td { background: var(--cor-linha-intercalada, #f7f8fa); }
tbody tr:hover td {
  /* tbody adicionado de propósito — aumenta a especificidade para
     ganhar SEMPRE sobre "tbody tr:nth-child(odd) td" (a alternância),
     que sem isto ganhava nas linhas ímpares (mais específica: 3
     elementos+1 pseudo-classe vs. 2 elementos+1 pseudo-classe),
     deixando o hover sem efeito visual metade das vezes. */
  background: var(--cor-hover-linha, #e8ecf2);
}
/* Arrastar-e-largar em mapas-personalizados.php — a linha de ORIGEM
   (a que está mesmo a ser arrastada, não a que está por baixo do
   cursor) fica semitransparente, dando feedback claro de qual item
   se está a mover. */
.linha-a-arrastar { opacity: 0.4; }
/* Desativa o hover das linhas enquanto se navega com o teclado (setas
   cima/baixo) — sem isto, se o cursor do rato ficar parado sobre uma
   linha diferente da selecionada, essa linha continua a destacar-se
   visualmente, confundindo com a linha realmente selecionada. A
   classe .navegacao-teclado-ativa é aplicada/removida via JS. */
.navegacao-teclado-ativa tbody tr:hover td {
  /* --cor-fundo-linha (o fundo normal, não hover), em vez de
     transparent — "transparent" deixava a cor de fundo INTERCALADA
     (definida em "tbody tr:nth-child(odd) td") continuar visível por
     trás, já que transparent não sobrepõe nada, só deixa ver o que
     já lá estava. tbody adicionado de propósito, mesmo raciocínio de
     especificidade já explicado na regra de hover normal acima. */
  background: var(--cor-fundo-linha, transparent);
}

.member-info { display: flex; align-items: center; gap: 0.75rem; }
.member-avatar {
  width: 34px; height: 34px; border-radius: 50%; display: flex; align-items: center;
  justify-content: center; font-size: 0.8rem; font-weight: 600; color: #fff; flex-shrink: 0;
}
.member-name { font-weight: 500; color: var(--texto-principal, #1a2332); }
.member-email { font-size: 0.78rem; color: var(--texto-secundario, #6b7a90); }

.badge { display: inline-flex; padding: 0.2rem 0.6rem; border-radius: 20px; font-size: 0.72rem; font-weight: 600; }
.badge-success { background: #d1fae5; color: #065f46; }
.badge-danger  { background: #fee2e2; color: #991b1b; }
.badge-warning { background: #fef3c7; color: #92400e; }

.action-btns { display: flex; gap: 0.4rem; }
.btn-icon {
  width: 28px; height: 28px; border-radius: 6px; border: 1px solid #e5e9f0; background: #fff;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: all 0.15s; color: var(--texto-secundario, #6b7a90);
}
.btn-icon:hover { background: var(--accent-light); border-color: var(--accent); color: var(--accent); }
.btn-icon.danger:hover { background: #fee2e2; border-color: #f87171; color: #dc2626; }
.btn-icon svg { width: 14px; height: 14px; }

.pagination {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0.4rem 1.25rem; font-size: 0.8rem; color: var(--texto-secundario, #6b7a90);
}

.estado-vazio { text-align: center; padding: 3rem 1rem; color: var(--texto-secundario, #6b7a90); }
.estado-vazio svg { width: 40px; height: 40px; margin: 0 auto 0.75rem; display: block; opacity: 0.4; }
.spinner-inline {
  width: 20px; height: 20px; border: 2px solid #e5e9f0; border-top-color: var(--accent);
  border-radius: 50%; animation: spin 0.6s linear infinite; margin: 2rem auto;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Modais */
.app-modal-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,0.4); z-index: 200;
  display: flex; align-items: flex-start; justify-content: center;
  /* Alinhado ao TOPO (não centrado verticalmente) — se centrado, o
     modal "salta" para cima/baixo sempre que a altura do conteúdo
     muda (ex: ao trocar de separador Geral -> Datas), porque o
     overlay recalcula o centro a cada mudança. Alinhado ao topo,
     a posição fica sempre estável, independente da altura. */
  padding-top: 5vh;
  overflow-y: auto;
}
.app-modal {
  background: #fff; border-radius: 10px; width: 540px; max-width: 95vw;
  max-height: 90vh; overflow-y: auto; box-shadow: 0 20px 60px rgba(0,0,0,0.2);
  /* Evita que o modal encolha para menos que o necessário quando
     está dentro de um flex container alinhado ao topo */
  flex-shrink: 0;
}
.app-modal-header {
  padding: 1.25rem 1.5rem; border-bottom: 1px solid #e5e9f0;
  display: flex; align-items: center; justify-content: space-between;
}
.app-modal-header h3 { font-size: 1rem; font-weight: 600; margin: 0; }
.app-modal-close { background: none; border: none; cursor: pointer; color: var(--texto-secundario, #6b7a90); padding: 0.25rem; border-radius: 4px; }
.app-modal-close:hover { background: #f0f4f8; }
.app-modal-body { padding: 1.5rem; }
.app-modal-footer { padding: 1rem 1.5rem; border-top: 1px solid #e5e9f0; display: flex; justify-content: flex-end; gap: 0.75rem; }

.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.form-group { display: flex; flex-direction: column; gap: 0.3rem; }
.form-group.modo-leitura { gap: 0.05rem; }
.form-group.full { grid-column: 1 / -1; }
.form-label { font-size: 0.8rem; font-weight: 600; color: var(--texto-principal, #1e3a5f); }
.form-control {
  border: 1px solid #d1d5db; border-radius: 6px; padding: 0.5rem 0.75rem;
  font-size: 0.875rem; outline: none; transition: border 0.15s; width: 100%; box-sizing: border-box;
}
.form-control:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(32,107,196,0.1); }
select.form-control { cursor: pointer; }
.form-control-sm { padding: 0.4rem 0.6rem; font-size: 0.8rem; }

.alerta-erro {
  background: #fee2e2; border: 1px solid #fca5a5; border-radius: 6px;
  padding: 0.6rem 0.875rem; font-size: 0.82rem; color: #991b1b; margin-bottom: 1rem;
}
.input-invalido { border-color: #fca5a5 !important; }
.input-invalido:focus { box-shadow: 0 0 0 3px rgba(220,38,38,0.1) !important; }
.form-erro-padrao { display: block; font-size: 0.75rem; color: #991b1b; margin-top: 0.25rem; }
.alerta-bloqueio {
  background: #fef3c7; border: 1px solid #fcd34d; border-radius: 6px;
  padding: 0.6rem 0.875rem; font-size: 0.82rem; color: #92400e; margin-bottom: 1rem;
  display: flex; align-items: center;
}

.app-modal-confirm { max-width: 380px; margin-top: 15vh; }
.app-modal-confirm .app-modal-body { text-align: center; padding: 2rem 1.5rem; }
.icone-aviso {
  width: 48px; height: 48px; background: #fee2e2; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; margin: 0 auto 1rem;
}
.icone-aviso svg { width: 24px; height: 24px; color: #dc2626; }
.app-modal-confirm h4 { font-size: 1rem; font-weight: 600; margin: 0 0 0.5rem; }
.app-modal-confirm p { font-size: 0.875rem; color: var(--texto-secundario, #6b7a90); margin: 0; }

/* Blocos de relação muitos-para-muitos (ex: Encarregados de Educação) */
.relacao-bloco {
  margin-top: 1.5rem; padding-top: 1.5rem; border-top: 1px solid #e5e9f0;
}
.relacao-cabecalho {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 0.75rem; font-weight: 600; font-size: 0.9rem; color: var(--texto-principal, #1a2332);
}
.btn-sm { padding: 0.3rem 0.7rem; font-size: 0.78rem; }
.relacao-vazio {
  color: var(--texto-secundario, #9ca3af); font-size: 0.85rem; padding: 1rem; text-align: center;
  background: var(--cor-pesquisa, #f8fafc); border-radius: 6px; border: 1px dashed #e5e9f0;
}
.relacao-item {
  display: flex; gap: 0.75rem; align-items: flex-start;
  background: var(--cor-pesquisa, #f8fafc); border: 1px solid #e5e9f0; border-radius: 8px;
  padding: 1rem; margin-bottom: 0.75rem;
}
.relacao-item-campos {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 0.75rem; flex: 1;
}
.relacao-item .btn-icon { flex-shrink: 0; margin-top: 1.5rem; }

/* Importação Excel */
.alerta-sucesso {
  background: #d1fae5; border: 1px solid #6ee7b7; border-radius: 6px;
  padding: 0.6rem 0.875rem; font-size: 0.82rem; color: #065f46; margin-bottom: 1rem;
}
.tabela-preview {
  max-height: 320px; overflow-y: auto; border: 1px solid #e5e9f0; border-radius: 8px;
}
.tabela-preview table { width: 100%; border-collapse: collapse; }
.tabela-preview th {
  position: sticky; top: 0; background: #fafbfd; text-align: left;
  font-size: 0.72rem; font-weight: 700; text-transform: uppercase; color: var(--texto-secundario, #6b7a90);
  padding: 0.6rem 0.75rem; border-bottom: 1px solid #e5e9f0;
}
.tabela-preview td { padding: 0.6rem 0.75rem; font-size: 0.82rem; border-bottom: 1px solid #f0f4f8; }
.tabela-preview tr.linha-com-erro td { background: #fef2f2; }

/* Modal: Tabelas */
.tabs-listas {
  display: flex; flex-wrap: wrap; gap: 0.25rem; border-bottom: 1px solid #e5e9f0;
  margin-bottom: 1.25rem;
}
.tab-lista {
  padding: 0.5rem 1rem; background: none; border: none; border-bottom: 2px solid transparent;
  font-size: 0.85rem; color: var(--texto-secundario, #6b7a90); cursor: pointer; font-weight: 500;
}
.tab-lista:hover { color: var(--accent); }
.tab-lista.active { color: var(--accent); border-bottom-color: var(--accent); }

/* Título de secção dentro de um separador (ex: "Saúde", "Sénior") —
   agrupa visualmente campos relacionados sem precisar de outro
   separador próprio; ver secaoMudou() em recurso.js */
.form-secao-titulo {
  font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em;
  color: var(--accent); margin: 1.25rem 0 0.5rem; padding-bottom: 0.35rem;
  border-bottom: 1px solid #e5e9f0;
}
.form-secao-titulo:first-child { margin-top: 0; }
.lista-form-dinamico {
  background: var(--cor-pesquisa, #f8fafc); border: 1px solid #e5e9f0; border-radius: 8px;
  padding: 1rem; margin-bottom: 1rem;
}
.lista-form-dinamico .form-grid { margin-bottom: 0; }
.lista-itens { max-height: 280px; overflow-y: auto; }
.lista-item-linha {
  display: flex; justify-content: space-between; align-items: center;
  padding: 0.6rem 0.75rem; border-bottom: 1px solid #f0f4f8; font-size: 0.875rem;
}
.lista-item-linha:hover { background: #fafbfd; }
/* Múltiplos campos do item (ver Object.entries em recurso.php),
   lado a lado com separador discreto entre eles -- funciona com
   qualquer número de campos, não fica preso a nenhum recurso
   específico. */
.lista-item-valores { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.lista-item-valor { color: var(--texto-principal, #2d3748); }
.lista-item-valor:not(:last-child)::after {
  content: '•'; margin-left: 0.5rem; color: #c7cfdb; font-weight: 400;
}

/* Dashboard */
.dash-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem;
}
.dash-card { display: flex; flex-direction: column; }
.dash-card-body { padding: 1.25rem; }
.barra-linha {
  display: flex; align-items: center; gap: 0.75rem; margin-bottom: 0.85rem;
  text-decoration: none; color: inherit; cursor: default; border-radius: 6px;
  padding: 0.2rem 0.35rem; margin-left: -0.35rem; transition: background 0.15s;
}
.barra-linha:last-child { margin-bottom: 0; }
/* Só as linhas com um valor real por trás (ex: uma Sala existente,
   não "Sem sala") ficam com aparência de link — as outras mantêm o
   cursor normal, já que clicar não leva a lado nenhum */
.barra-linha-clicavel { cursor: pointer; }
.barra-linha-clicavel:hover { background: #f0f4f8; }
.barra-label { width: 110px; font-size: 0.82rem; color: var(--texto-secundario, #374151); flex-shrink: 0; }
.barra-fundo {
  flex: 1; height: 10px; background: #f0f4f8; border-radius: 6px; overflow: hidden;
}
.barra-valor { height: 100%; background: var(--accent); border-radius: 6px; transition: width 0.3s; }
.barra-numero { width: 28px; text-align: right; font-size: 0.82rem; font-weight: 600; color: var(--texto-principal, #1a2332); flex-shrink: 0; }

@media (max-width: 900px) {
  .dash-grid { grid-template-columns: 1fr; }
}

/* Links de utente clicáveis (dashboard → ficha) */
.link-utente {
  color: var(--texto-principal, #1a2332); font-weight: 600; text-decoration: none;
}
.link-utente:hover { color: var(--accent); text-decoration: underline; }

/* Barra do construtor de Mapas Personalizados — só visível dentro do
   <iframe> aberto a partir de "Gerar Lista" (ver ?modo_construtor_mapa=1
   em recurso.php). Fundo de destaque suave, para ficar bem visível
   sem competir com o resto da interface. */
.construtor-mapa-barra-aviso {
  background: #eaf2fc; border-bottom: 1px solid #b8d4f0;
  padding: 0.6rem 1.5rem; display: flex; align-items: center;
  justify-content: space-between; gap: 1rem;
  font-size: 0.85rem; color: #1a4d80;
}

/* Barra de funções da área (2ª linha, horizontal, dentro de recurso.php).
   Agrupa Mapas / Exportar / Importar / Listas — só aparece quando o
   utilizador tem pelo menos uma dessas permissões nesta área. */
.funcoes-barra {
  background: #fff; border-bottom: 1px solid #e5e9f0;
  padding: 0 1.5rem; display: flex; align-items: center; gap: 1.5rem;
  height: 42px; overflow-x: auto;
}
.funcoes-grupo {
  display: flex; align-items: center; gap: 0.25rem;
  padding-right: 1.5rem; border-right: 1px solid #e5e9f0; height: 100%;
}
.funcoes-grupo:last-child { border-right: none; padding-right: 0; }

/* Rodapé da lista (Mapas | Tabelas | Opções) — a pedido do
 * utilizador, estes botões ficam juntos, sem o separador vertical
 * nem o espaçamento largo que a barra de topo usa. Ali fazem sentido
 * (grupos de funções distintas); aqui são todos ações da mesma lista. */
.pagination .funcoes-grupo {
  border-right: none;
  padding-right: 0;
}
/* Sem margin extra entre grupos: o .pagination já tem gap:4px, o
 * mesmo dos botões dentro de cada grupo. Uma margin adicional fazia
 * o espaço Tabelas|Opções (14px) ficar ao triplo do Mapas|Tabelas
 * (4px) — medido, não estimado. */
.funcoes-item {
  display: flex; align-items: center; gap: 0.4rem;
  padding: 0.4rem 0.65rem; border-radius: 6px;
  background: none; border: none; cursor: pointer; white-space: nowrap;
  color: var(--texto-secundario, #4b5768); font-size: 0.82rem; text-decoration: none; transition: all 0.15s;
}
.funcoes-item:hover { background: #f0f4f8; color: var(--accent); }
.funcoes-item svg { flex-shrink: 0; color: var(--texto-secundario, #8b96a5); transition: color 0.15s; }
.funcoes-item:hover svg { color: var(--accent); }

/* Dropdown reaproveitado por vários menus (Imprimir Lista, Opções em
   recurso.php) — apanhado em falta ao testar "Opções" de facto: já
   usado antes (Imprimir Lista), mas sem CSS próprio nenhum, herdando
   um aspeto "cru" que nunca tinha reparado. Mesmo espírito visual já
   confirmado em .topnav-dropdown, adaptado para funcionar bem tanto
   com <a> como <button> dentro. */
.menu-mais-opcoes {
  position: absolute; top: 100%; margin-top: 0.3rem;
  background: #fff; border: 1px solid #e5e9f0; border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.12); min-width: 200px; padding: 0.4rem;
  z-index: 110;
}
.menu-mais-opcoes-item {
  display: flex; align-items: center; gap: 0.5rem; width: 100%;
  padding: 0.5rem 0.75rem; border-radius: 6px;
  background: none; border: none; cursor: pointer; white-space: nowrap; text-align: left;
  color: var(--texto-secundario, #374151); text-decoration: none; font-size: 0.85rem;
}
.menu-mais-opcoes-item:hover { background: #f0f4f8; color: var(--accent); }
.menu-mais-opcoes-item svg { flex-shrink: 0; color: var(--texto-secundario, #8b96a5); transition: color 0.15s; }
.menu-mais-opcoes-item:hover svg { color: var(--accent); }
.menu-mais-opcoes-item:disabled { opacity: 0.5; cursor: not-allowed; }
/* Destaca a página ATUAL dentro do grupo Mapas (ver
   $paginaAtivaFuncoes em partials/funcoes-recurso.php) — mesma
   combinação já usada em :hover acima, mas permanente, para navegar
   entre Utentes/Mapas/Mapas Personalizados sempre mostrar claramente
   onde já estás, mesmo sem o rato por cima. */
.funcoes-item.active { background: #eaf2fc; color: var(--accent); font-weight: 600; }
.funcoes-item.active svg { color: var(--accent); }

/* Modo apenas visualização — campos desativados ficam visualmente distintos */
.form-control:disabled {
  background: #f8fafc; color: var(--texto-secundario, #6b7a90); cursor: not-allowed;
  border-color: #e5e9f0;
}

/* Modo apenas visualização — valores mostrados como texto, não inputs */
.valor-leitura {
  padding: 0.1rem 0 0; font-size: 0.9rem; color: var(--texto-principal, #1a2332); font-weight: 500;
  min-height: 1.3rem;
}

/* Página de Utilizadores — tabela de permissões e seleção de salas */
.tabela-permissoes {
  border: 1px solid #e5e9f0; border-radius: 8px; overflow: hidden;
}
.tabela-permissoes table { width: 100%; border-collapse: collapse; }
.tabela-permissoes th {
  background: #fafbfd; text-align: center; font-size: 0.72rem; font-weight: 700;
  text-transform: uppercase; color: var(--texto-secundario, #6b7a90); padding: 0.6rem 0.5rem;
  border-bottom: 1px solid #e5e9f0;
}
.tabela-permissoes th:first-child { text-align: left; }
.tabela-permissoes td {
  text-align: center; padding: 0.6rem 0.5rem; font-size: 0.85rem;
  border-bottom: 1px solid #f0f4f8;
}
.tabela-permissoes td:first-child { text-align: left; font-weight: 500; color: var(--texto-principal, #1a2332); }
.tabela-permissoes input[type="checkbox"] { width: 16px; height: 16px; cursor: pointer; }
.tabela-permissoes input[type="checkbox"]:disabled { opacity: 0.3; cursor: not-allowed; }

.lista-salas-checkbox {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 0.5rem; padding: 0.75rem; background: var(--cor-pesquisa, #f8fafc); border-radius: 8px; border: 1px solid #e5e9f0;
}
.sala-checkbox-item {
  display: flex; align-items: center; gap: 0.5rem; font-size: 0.85rem;
  color: var(--texto-secundario, #374151); cursor: pointer;
}
.sala-checkbox-item input[type="checkbox"] { width: 16px; height: 16px; cursor: pointer; }

/* Cabeçalho de coluna com nome + filtro juntos na mesma célula —
   substituiu a estrutura antiga de 2 <tr> sobrepostas (uma só para
   nomes, outra só para filtros), que exigia calcular manualmente a
   altura de uma para a outra não se sobrepor ao ficarem "sticky"
   (frágil, dependia do tamanho de letra do browser). Uma célula só,
   um único sticky, resolve isto de raiz. */
/* Linha de filtros por coluna — segunda linha do cabeçalho, um
   campo de texto por baixo de cada nome de coluna. Sticky com "top"
   calculado a partir do min-height já definido no "th" genérico
   acima (2.6rem = 41.6px, já incluindo padding, graças a
   box-sizing:border-box) — como TODAS as células da primeira linha
   têm essa mesma altura mínima garantida (mesmo que o nome de uma
   coluna precise de 2 linhas), o "top" desta segunda linha fica
   sempre correto e alinhado, célula a célula, para qualquer coluna. */
/* Linha de filtros por coluna — segunda linha do cabeçalho, um
   campo de texto por baixo de cada nome de coluna. Sticky com "top"
   vindo de --altura-linha-cabecalho, uma variável CSS MEDIDA
   dinamicamente em JS (ver ajustarAlturaLinhaCabecalho() em
   tabela-lista.js), nunca um valor fixo calculado à mão — isso
   revelou-se frágil na prática (a altura real varia com o tamanho
   de fonte do sistema, zoom do browser, e o comportamento de
   min-height em células de tabela é historicamente inconsistente
   entre browsers). Medir a altura real, já depois de tudo
   renderizado, garante que o valor está sempre certo, seja qual for
   o ambiente. O fallback (44px) só entra em jogo antes da primeira
   medição acontecer (ex: primeiro carregamento da página). */
.linha-filtros-coluna th {
  /* Padding superior reduzido (de 0.3rem para 0.12rem) — a outra
     metade da aproximação vertical entre o nome da coluna e o campo
     "Filtrar..." (ver padding-bottom de th, logo acima neste
     ficheiro). Espaço total entre os 2 elementos: de ~10.4px para
     ~4.3px. */
  padding: 0.12rem 0.5rem 0.3rem; background: var(--cor-cabecalho-lista, #e5e9f0);
  border-bottom: 1px solid #e5e9f0; cursor: default;
  position: sticky; top: var(--altura-linha-cabecalho, 44px); z-index: 4;
}
/* .th-ordenavel — cabeçalho clicável simples, sem filtro por baixo
   (usado em mapa.php e mapas-personalizados.php, que não têm
   pesquisa por coluna, só ordenação; também usado na primeira linha
   da tabela de Utentes/Mensagens, que tem os filtros por baixo) */
.th-ordenavel {
  cursor: pointer; user-select: none; transition: color 0.15s;
}
.th-ordenavel:hover { color: var(--accent); }
.seta-ordenacao { margin-left: 0.3rem; font-size: 0.65rem; color: var(--accent); }
.seta-ordenacao sup { font-size: 0.6rem; margin-left: 0.1rem; font-weight: 700; }
.input-filtro-coluna {
  width: 100%; box-sizing: border-box; padding: 0.3rem 0.5rem;
  border: 1px solid #e5e9f0; border-radius: 4px; font-size: 0.78rem;
  font-weight: 400; color: var(--texto-principal, #1a2332);
  text-transform: none; letter-spacing: normal; /* o th "pai" é uppercase/espaçado — o texto digitado não deve ser */
  cursor: text;
}
.input-filtro-coluna:focus { outline: none; border-color: var(--accent); }

/* Construtor de Mapas Personalizados */
.construtor-secao {
  margin-bottom: 1.75rem; padding-bottom: 1.75rem; border-bottom: 1px solid #e5e9f0;
}
.construtor-secao:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; }
.construtor-secao-titulo {
  font-weight: 600; font-size: 0.9rem; color: var(--texto-principal, #1a2332); margin-bottom: 0.85rem;
  display: flex; align-items: center; justify-content: space-between;
}
.construtor-campos-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 0.6rem; padding: 1rem; background: var(--cor-pesquisa, #f8fafc); border-radius: 8px; border: 1px solid #e5e9f0;
}
.campo-checkbox-item {
  display: flex; align-items: center; gap: 0.5rem; font-size: 0.85rem;
  color: var(--texto-secundario, #374151); cursor: pointer;
}
.campo-checkbox-item input[type="checkbox"] { width: 16px; height: 16px; cursor: pointer; flex-shrink: 0; }
.construtor-filtro-linha {
  display: flex; gap: 0.6rem; align-items: center; margin-bottom: 0.6rem;
  padding: 0.75rem; background: var(--cor-pesquisa, #f8fafc); border-radius: 8px; border: 1px solid #e5e9f0;
}
.construtor-filtro-linha .form-control { flex: 1; min-width: 0; }
.construtor-filtro-linha[draggable="true"] { cursor: move; }
.construtor-filtro-linha.a-arrastar { opacity: 0.4; }
.construtor-filtro-linha .coluna-item-alca { cursor: move; flex-shrink: 0; }

/* Construtor de Mapas — duas listas (disponíveis / selecionadas) */
.colunas-duas-listas {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1rem;
}
.colunas-lista-bloco {
  border: 1px solid #e5e9f0; border-radius: 8px; overflow: hidden;
}
.colunas-lista-titulo {
  background: #fafbfd; padding: 0.5rem 0.85rem; font-size: 0.72rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.05em; color: var(--texto-secundario, #6b7a90);
  border-bottom: 1px solid #e5e9f0;
}
.colunas-lista {
  max-height: 260px; overflow-y: auto; padding: 0.5rem;
}
.coluna-item-disponivel {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0.5rem 0.7rem; border-radius: 6px; font-size: 0.85rem;
  color: var(--texto-secundario, #374151); cursor: pointer; margin-bottom: 0.3rem; transition: background 0.15s;
}
.coluna-item-disponivel:hover { background: #eef4fc; }
.coluna-item-mais { color: var(--accent); font-weight: 700; }
.coluna-item-selecionada {
  display: flex; align-items: center; gap: 0.6rem;
  padding: 0.5rem 0.7rem; border-radius: 6px; font-size: 0.85rem;
  background: var(--cor-pesquisa, #f8fafc); border: 1px solid #e5e9f0;
  cursor: grab; margin-bottom: 0.3rem;
}
.coluna-item-selecionada.a-arrastar { opacity: 0.4; }
.coluna-item-selecionada span:nth-child(2) { flex: 1; }
.coluna-item-alca { color: var(--texto-secundario, #9ca3af); letter-spacing: -2px; user-select: none; }
.coluna-item-remover {
  background: none; border: none; color: #dc2626; cursor: pointer;
  font-size: 0.8rem; padding: 0.15rem 0.4rem; border-radius: 4px;
}
.coluna-item-remover:hover { background: #fee2e2; }
.estado-vazio-pequeno { color: var(--texto-secundario, #9ca3af); font-size: 0.8rem; padding: 0.75rem; text-align: center; }

/* ── Layout de duas colunas: lista + ficha lado a lado ────────────── */
/* A altura usa flexbox no body inteiro (ver 'body, html' abaixo) em
   vez de um calc() fixo, porque a barra de funções (.funcoes-barra)
   pode ou não estar presente consoante as permissões do utilizador —
   com flex, o espaço disponível ajusta-se sozinho em qualquer caso. */
html, body { height: 100%; margin: 0; }
body { display: flex; flex-direction: column; }
/* O <div x-data="recursoApp(...)"> que envolve toda a página de
   recurso.php (Sócios/Utentes/Mensagens) precisava desta classe —
   sem ela, era um <div> genérico com display:block, o que quebrava a
   cadeia flex a meio: mesmo com .app-page-body-split tendo
   "flex: 1; min-height: 0" corretos, isso só funciona dentro de um
   pai display:flex. Com o pai em display:block, o filho cresce
   sempre ao tamanho do seu conteúdo, ignorando flex por completo —
   foi esta a causa raiz de o ecrã inteiro "esticar" com a lista. */
.app-raiz-pagina {
  display: flex; flex-direction: column; flex: 1; min-height: 0;
}
/* Páginas "normais" (Dashboard, Mapas, Utilizadores) continuam a
   poder rolar livremente, com o scroll contido dentro desta zona —
   só a vista de duas colunas (.app-page-body-split, ver abaixo) é
   que trata o scroll de forma diferente, delegando-o às suas
   próprias sub-zonas internas. */
.app-page-body { overflow-y: auto; flex: 1; min-height: 0; }
.app-page-body-split {
  display: flex; align-items: stretch; flex: 1; min-height: 0;
  padding: 1.25rem; gap: 0;
}
.recurso-lista {
  flex-shrink: 0; min-width: 0; height: 100%;
  display: flex; flex-direction: column;
}
.recurso-lista .card { overflow: hidden; background: var(--cor-caixa-lista, #fff); }
.recurso-lista-corpo {
  flex: 1; overflow-y: auto; overflow-x: auto;
  margin-top: 0.5rem;
  /* min-width: 0 é essencial aqui — sem isto, um filho flex (a
     tabela) mais largo que o espaço disponível pode forçar todo o
     container a crescer para se ajustar ao conteúdo, em vez de
     respeitar a largura definida em .recurso-lista e mostrar scroll
     horizontal contido. É a mesma razão pela qual min-height:0 é
     necessário em containers flex verticais. */
  min-width: 0;
}
.recurso-divisor {
  width: 6px; flex-shrink: 0; cursor: col-resize;
  position: relative; margin: 0 0.5rem;
}
.recurso-divisor::after {
  content: ''; position: absolute; top: 0; bottom: 0; left: 50%;
  width: 2px; background: #dde3ec; transform: translateX(-50%);
  transition: background 0.15s;
}
.recurso-divisor:hover::after { background: var(--accent); }
.recurso-ficha {
  flex: 1; min-width: 420px; height: 100%; overflow: hidden;
}
.recurso-ficha .card { overflow: hidden; background: var(--cor-caixa-ficha, #fff); }
.recurso-ficha-vazia {
  height: 100%; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 1rem; color: var(--texto-secundario, #9ca3af); text-align: center;
  background: #fff; border-radius: 10px; border: 1px solid #e5e9f0;
}
.recurso-ficha-vazia p { font-size: 0.9rem; margin: 0; }
.linha-selecionada td { background: var(--cor-linha-selecionada, #eaf1fb) !important; }

/* Em ecrãs mais estreitos, empilha em vez de lado a lado */
@media (max-width: 980px) {
  .app-page-body-split { flex-direction: column; height: auto; }
  .recurso-lista { width: 100% !important; min-width: 0; height: 45vh; }
  .recurso-divisor { display: none; }
  .recurso-ficha { min-width: 0; height: 55vh; }
}

/* Componente de tabela de lista padronizado (recurso.php, mapa.php,
   mapas-personalizados.php) — ver partials/tabela-lista.php */
.tabela-total-inline {
  font-size: 0.78rem; font-weight: 600; color: var(--texto-secundario, #4b5768); white-space: nowrap;
}
.tabela-lista-topo {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem;
  padding: 0.75rem 1.25rem; border-bottom: 1px solid #e5e9f0;
}
.tabela-acoes-massa {
  display: flex; align-items: center; gap: 0.75rem;
  padding: 0.6rem 1.25rem; background: var(--cor-pesquisa, #eaf1fb); border-bottom: 1px solid #dbe6f5;
  font-size: 0.82rem; color: var(--texto-principal, #1a2332); font-weight: 500;
}
.th-checkbox { width: 34px; text-align: center !important; }
.th-checkbox input, td input[type="checkbox"] { width: 15px; height: 15px; cursor: pointer; }

/* Vista de cards de navegação (Valências/Salas/Grupos em Utentes) */
.cards-secao { margin-bottom: 2rem; }
.cards-secao:last-child { margin-bottom: 0; }
.cards-secao-titulo {
  font-size: 0.78rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--texto-secundario, #6b7a90); margin-bottom: 0.75rem;
}
.cards-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 0.85rem;
}
.card-navegacao {
  background: #fff; border: 1px solid #e5e9f0; border-radius: 10px;
  padding: 1.25rem 1rem; text-align: center; cursor: pointer;
  transition: all 0.15s;
}
.card-navegacao:hover {
  border-color: var(--accent); box-shadow: 0 4px 12px rgba(32,107,196,0.12);
  transform: translateY(-1px);
}
.card-navegacao-numero { font-size: 1.6rem; font-weight: 700; color: var(--accent); }
.card-navegacao-nome { font-size: 0.82rem; color: var(--texto-secundario, #4b5768); margin-top: 0.25rem; }

/* Página de Definições — seletores de cor */
.definicoes-cor-linha {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem; padding: 1rem 0; border-bottom: 1px solid #e5e9f0;
}
.definicoes-cor-linha:last-of-type { border-bottom: none; }
.definicoes-cor-descricao { font-size: 0.78rem; color: var(--texto-secundario, #6b7a90); margin: 0.2rem 0 0; }
.definicoes-cor-input {
  width: 52px; height: 36px; border: 1px solid #e5e9f0; border-radius: 8px;
  cursor: pointer; padding: 2px; flex-shrink: 0;
}
.definicoes-cor-input:disabled { cursor: not-allowed; opacity: 0.6; }
.definicoes-preview {
  margin-top: 1.5rem; border: 1px solid #e5e9f0; border-radius: 10px;
  overflow: hidden;
}
.definicoes-preview-topbar { height: 42px; }
.definicoes-preview-caixa { padding: 1rem; }
.definicoes-preview-pesquisa {
  height: 32px; border-radius: 6px; border: 1px solid #e5e9f0; margin-bottom: 0.75rem;
}
.definicoes-preview-linha {
  padding: 0.5rem 0.75rem; border-radius: 4px; font-size: 0.78rem;
  color: var(--texto-secundario, #4b5768); margin-bottom: 0.5rem;
}
.definicoes-preview-botao {
  padding: 0.5rem 1.25rem; border: none; border-radius: 6px;
  color: #fff; font-size: 0.85rem; font-weight: 500; cursor: default;
}

/* Grelha de temas prontos — cada cartão mostra uma mini-prévia (topbar
   + botão) das cores desse tema, para dar ideia visual antes de clicar */
.temas-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 0.75rem; margin-top: 0.5rem;
}
.tema-cartao {
  background: none; border: 1px solid #e5e9f0; border-radius: 10px;
  padding: 0; cursor: pointer; overflow: hidden; text-align: left;
  transition: border-color 0.15s, transform 0.15s;
}
.tema-cartao:hover { border-color: var(--accent, #206bc4); transform: translateY(-1px); }
.tema-cartao-preview { height: 56px; position: relative; }
.tema-cartao-topbar { height: 18px; }
.tema-cartao-botao {
  position: absolute; bottom: 8px; left: 8px; width: 32px; height: 10px; border-radius: 3px;
}
.tema-cartao-nome {
  display: block; padding: 0.5rem 0.6rem; font-size: 0.75rem; font-weight: 600;
  color: var(--texto-principal, #1a2332);
}

/* Foto de Utente na ficha — círculo grande com iniciais como
   fallback (mesma lógica visual do .avatar pequeno da topbar).
   Fica FIXO no topo da ficha (fora de .app-modal-body, que tem o
   scroll), por isso não leva flex:1 nem overflow — o .card pai já
   garante que este bloco fica no tamanho do seu próprio conteúdo,
   sem crescer, e o resto do espaço vai para .app-modal-body. */
.ficha-foto-bloco {
  display: flex; align-items: flex-start; gap: 1.5rem;
  padding: 1.25rem 1.5rem; border-bottom: 1px solid #e5e9f0;
  flex-shrink: 0; /* nunca encolhe, mesmo se o .card ficar pequeno */
}
.ficha-foto-circulo {
  width: 72px; height: 72px; border-radius: 50%; background: var(--accent); color: #fff;
  display: flex; align-items: center; justify-content: center; font-size: 1.3rem; font-weight: 600;
  flex-shrink: 0; overflow: hidden; position: relative;
}
.ficha-foto-circulo.clicavel { cursor: pointer; }
.ficha-foto-circulo img { width: 100%; height: 100%; object-fit: cover; }

/* Variante pequena — usada nas fotos de Pessoas, dentro de cada
   .relacao-item da ficha de Utente (várias ao mesmo tempo, não fazia
   sentido usar o tamanho grande da foto principal do Utente) */
.ficha-foto-circulo.pequeno { width: 48px; height: 48px; font-size: 0.95rem; }
.relacao-item-foto {
  display: flex; flex-direction: column; align-items: center;
  margin-right: 1rem; flex-shrink: 0;
}

/* Colunas 2 (dados do Utente) e 3 (dados do Responsável) — mesma
   largura/estilo de texto, lado a lado depois da foto */
.ficha-resumo-utente, .ficha-resumo-responsavel {
  font-size: 0.83rem; color: var(--texto-secundario, #4b5768); line-height: 1.5; flex: 1; min-width: 0;
}
.ficha-resumo-nome { font-size: 1.05rem; font-weight: 700; color: var(--texto-principal, #1a2332); margin-bottom: 0.2rem; }
.badge-inativo {
  display: inline-block; font-size: 0.68rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.02em; color: #92400e; background: #fef3c7; border: 1px solid #fcd34d;
  border-radius: 4px; padding: 0.1rem 0.4rem; margin-left: 0.5rem; vertical-align: middle;
}
.badge-tipo-modelo {
  display: inline-block; font-size: 0.68rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.02em; color: #1d4ed8; background: #dbeafe; border: 1px solid #bfdbfe;
  border-radius: 4px; padding: 0.1rem 0.4rem; margin-left: 0.5rem; vertical-align: middle;
}
.ficha-resumo-linha { margin-bottom: 0.1rem; }
.ficha-resumo-responsavel-titulo {
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--texto-secundario, #9ca3af); margin-bottom: 0.3rem;
}

/* Estado vazio das listas — centrado na ZONA VISÍVEL da tabela.
 *
 * Duas tentativas falhadas antes desta, ambas apanhadas a olhar para
 * o ecrã:
 *   1) sem sticky: em tabelas largas (Utentes, ~2900px de célula) o
 *      texto centrava-se na célula e caía fora do ecrã;
 *   2) com width fixa (600px) ou 100vw: encostava à esquerda em
 *      tabelas estreitas, ou saía cortado quando a ficha lateral
 *      está aberta e a lista só ocupa metade da janela.
 *
 * A referência certa não é o ecrã nem a célula: é .recurso-lista-corpo,
 * o contentor que tem o scroll horizontal. 100% dele = exatamente a
 * zona visível, seja qual for a largura da tabela ou a ficha lateral.
 */
.recurso-lista-corpo { position: relative; }

.estado-vazio-sticky {
  position: sticky;
  left: 0;
  /* A largura tem de ser a do CONTENTOR com scroll, nunca a da
   * célula (que em Utentes chega a ~2900px). Como o CSS não permite
   * referir o contentor diretamente a partir de dentro da tabela,
   * o valor é definido por JS numa variável, quando a lista é
   * medida — ver definirLarguraEstadoVazio() em tabela-lista.js.
   * O fallback de 100% serve para tabelas estreitas, onde célula e
   * contentor têm a mesma largura. */
  width: var(--largura-lista-visivel, 100%);
  text-align: center;
  /* left:0 posiciona no início da célula, mas o conteúdo começa
   * DEPOIS do padding dela (24px). Sem esta compensação, o texto
   * ficava 24px à direita do centro real da zona visível. */
  margin-left: -24px;
}

/* Botões do modal "Tabelas" (Mapa | Exportar | Importar).
 *
 * Dois são <a> e um é <button>: o <a> ajusta-se ao conteúdo, o
 * <button> tem altura e alinhamento próprios do browser. O resultado
 * era o "Importar" visivelmente mais baixo que os outros dois.
 *
 * align-items:stretch faz todos ocupar a altura da linha; o
 * display:inline-flex em cada um centra o ícone e o texto lá dentro.
 */
.botoes-tabela {
  display: flex;
  align-items: stretch;
  gap: 0.5rem;
}
.botoes-tabela > a,
.botoes-tabela > button {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  text-decoration: none;
  line-height: 1.2;
}

/* Separadores do recurso (Utentes / Responsáveis) — a pedido do
 * utilizador. Ficam no topo do cartão da lista, e dizem O QUE se está
 * a ver; a barra de cima dá as ferramentas disso.
 */
.separadores-recurso {
  display: flex;
  background: #f7f9fc;
  border-bottom: 1px solid #e5e9f0;
  border-radius: 6px 6px 0 0;
  overflow-x: auto;
  flex-shrink: 0;
}
.separador-recurso {
  padding: 0.55rem 1.25rem;
  font-size: 0.86rem;
  color: #6b7280;
  text-decoration: none;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
}
.separador-recurso:hover { color: #374151; background: #eef1f6; }
.separador-recurso.ativo {
  background: #fff;
  color: #1a2332;
  font-weight: 700;
  border-bottom-color: #2563eb;
}

/* Formulários EMPILHADOS (modais como "Nova Entidade").
 *
 * O .form-group tem gap interno entre rótulo e campo, mas nenhuma
 * margem POR BAIXO: nas fichas isso não se nota, porque a grelha
 * trata do espaçamento entre campos. Num modal onde os grupos ficam
 * uns por cima dos outros, o resultado era o rótulo seguinte a
 * aparecer mais perto do campo de cima (5px) do que do seu próprio
 * campo (8px) — parecia pertencer ao campo errado.
 */
.app-modal-body > .form-group + .form-group,
.app-modal-body > .form-group {
  margin-bottom: 1rem;
}
.app-modal-body > .form-group:last-child {
  margin-bottom: 0;
}

/* Cabeçalho de cartão com botão: 0.5rem deixava o botão a 9px do
 * topo, visivelmente apertado. Aplica-se só quando o cabeçalho tem
 * mesmo um botão — nos que só têm título, o valor original chega. */
.card-header:has(button) {
  padding-top: 0.85rem;
  padding-bottom: 0.85rem;
}

/* Etiquetas de estado do convite de dono (Gerir Entidades).
 * Cores com significado: âmbar = à espera de ação de outra pessoa,
 * vermelho = já não serve, é preciso reenviar. */
.etiqueta-estado {
  display: inline-block;
  padding: 0.12rem 0.5rem;
  border-radius: 4px;
  font-size: 0.72rem;
  font-weight: 700;
  margin-right: 0.4rem;
  white-space: nowrap;
}
.etiqueta-estado.pendente { background: #fef3c7; color: #92400e; }
.etiqueta-estado.expirado { background: #fee2e2; color: #991b1b; }

/* Linha das datas do convite (Gerir Entidades) — em bloco próprio,
 * por baixo do email. Feito por classe e não por style inline porque
 * o x-show do Alpine escreve no atributo style ao mostrar/esconder,
 * e apagava um display:block posto ali. */
.linha-datas { display: block; font-size: 0.75rem; margin-top: 0.15rem; }

/* "Por enviar" — convite preparado mas ainda não enviado.
 * Cor neutra de propósito: não é um problema (como o âmbar do
 * pendente ou o vermelho do expirado), é só uma tarefa por concluir. */
.etiqueta-estado.preparado { background: #e5e9f0; color: #4b5563; }

/* ── Abas na barra de separadores ──────────────────────────────────
 * Grupos abre como aba em vez de substituir a lista. Herda o aspeto
 * do separador normal; só acrescenta o × para fechar. */
.separador-aba { display: inline-flex; align-items: center; gap: 0.4rem; }
.fechar-aba {
  font-size: 1.1rem;
  line-height: 1;
  opacity: 0.5;
  padding: 0 0.15rem;
  border-radius: 3px;
}
.fechar-aba:hover { opacity: 1; background: rgba(0,0,0,0.08); }

/* O estado vazio e os cabeçalhos de grupo são frases, não valores de
 * coluna — precisam de partir a linha, ao contrário das células
 * normais (que têm white-space:nowrap para não partirem nomes). */
.estado-vazio-sticky,
.estado-vazio-sticky *,
.linha-agrupamento td { white-space: normal; }
