
:root {
  --azul-esc:   #1A3C5E;
  --azul-med:   #2E6DA4;
  --azul-clar:  #D6E4F0;
  --azul-hover: #245a8a;
  --verde:      #27AE60;
  --amarelo:    #F39C12;
  --vermelho:   #E74C3C;
  --cinza-bg:   #F4F6F9;
  --cinza-brd:  #DDE2EA;
  --branco:     #FFFFFF;
  --texto:      #1A2940;
  --texto-sec:  #5A6A7E;
  --titulo:     #1A3C5E;  /* texto de títulos — no escuro NÃO pode seguir o --azul-esc */
  --sidebar-w:  240px;
  --topbar-h:   56px;

  /* ── FUNDAÇÕES DE DESENHO (2026-07-31) ──────────────────────────
     Havia 31 tamanhos de letra, 7 pesos, 12 raios de canto e 60 sombras
     espalhados pelo projeto. Nada disto era decidido: era escrito à mão em
     cada sítio. Estas variáveis são a escala oficial -- quem escreve interface
     nova usa estas e mais nenhuma. */

  /* Texto: 6 tamanhos, chega para tudo */
  --t-xs:   11px;   /* rótulos, notas de rodapé */
  --t-sm:   12px;
  --t-base: 13px;   /* corpo, tabelas, botões */
  --t-md:   15px;
  --t-lg:   20px;   /* títulos de ecrã */
  --t-xl:   28px;   /* números grandes de KPI */

  /* Peso: 3 chegam. O 800/900 fazia blocos pretos ilegíveis */
  --p-normal: 400;
  --p-medio:  500;
  --p-forte:  600;

  /* Cantos: 3 */
  --r-sm:  4px;    /* controlos: campos, botões pequenos */
  --r-md:  6px;    /* cartões, janelas, botões */
  --r-pill: 99px;  /* pastilhas */

  /* Sombra: 2 níveis. As de 60px de desfoque eram sombras de apresentação */
  --s-cartao: 0 1px 2px rgba(0,0,0,.06);
  --s-flutua: 0 8px 24px rgba(0,0,0,.12);

  /* Camadas: hierarquia FIXA. Havia 10 valores diferentes de z-index entre os
     módulos -- é por isso que mais cedo ou mais tarde uma janela aparecia por
     baixo de outra. */
  --z-painel:   100;
  --z-janela:   1000;
  --z-confirma: 2000;
  --z-aviso:    9000;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
/* ── POLIMENTO (2026-07-31, "manter como está mas mais bonito") ──
   Micro-detalhes de acabamento: seleção, foco visível, scrollbars finas.
   Nada disto muda o desenho — muda a sensação de cuidado. */
::selection { background: var(--azul-clar); }
:focus-visible { outline: 2px solid var(--azul-med); outline-offset: 1px; border-radius: 4px; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #C3CBD6; border-radius: 99px; border: 3px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-thumb:hover { background: #A8B2BF; border: 3px solid transparent; background-clip: content-box; }
[data-theme="dark"] ::-webkit-scrollbar-thumb { background: #3A4656; border: 3px solid transparent; background-clip: content-box; }
/* Segoe UI é do Windows: num Mac caía tudo para Arial, a letra que faz um
   software parecer de 2005. Esta lista usa a letra nativa de cada sistema. */
body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Inter, system-ui, sans-serif;
  background: var(--cinza-bg); color: var(--texto);
  -webkit-font-smoothing: antialiased;
}

/* ── ÍCONES (2026-07-31) ──
   Os 837 emoji a cores foram substituídos por SVG de traço fino (sprite no
   index.html). O ícone herda a cor do texto — nunca traz cor própria. */
.ico {
  width: 16px; height: 16px; flex-shrink: 0;
  stroke: currentColor; fill: none;
  stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round;
}
.icon .ico { display: block; margin: 0 auto; }
.btn .ico, .btn-logout .ico { vertical-align: -3px; margin-right: 2px; }

/* ── LOGIN ── */
#screen-login {
  display: flex; align-items: center; justify-content: center;
  min-height: 100vh; background: var(--azul-esc);
}
.login-card {
  background: var(--branco); border-radius: 16px;
  padding: 48px 40px; width: 100%; max-width: 400px;
  box-shadow: var(--s-flutua); text-align: center;
}
.login-logo { font-size: 38px; font-weight: var(--p-forte); color: var(--titulo); letter-spacing: 3px; margin-bottom: 4px; }
.login-sub  { font-size: 12px; color: var(--texto-sec); letter-spacing: 1.5px; text-transform: uppercase; margin-bottom: 32px; }
.login-divider { border: none; border-top: 1px solid var(--cinza-brd); margin: 28px 0; }
.login-tagline { font-size: 15px; color: var(--texto-sec); margin-bottom: 32px; line-height: 1.5; }
.btn-google {
  display: flex; align-items: center; justify-content: center; gap: 12px;
  width: 100%; padding: 13px 20px; border-radius: 8px;
  border: 2px solid var(--cinza-brd); background: var(--branco);
  font-size: 14px; font-weight: 600; color: var(--texto); cursor: pointer;
  transition: all .2s;
}
.btn-google:hover { border-color: var(--azul-med); background: var(--azul-clar); }
.btn-google svg { width: 20px; height: 20px; flex-shrink: 0; }
.login-footer { margin-top: 28px; font-size: 11px; color: var(--texto-sec); }

/* ── ACCESS DENIED ── */
/* 2026-07-31: nasce ESCONDIDO (como o #screen-app). Nascia visível e só o
   checkAccess/logout o escondiam — em modo demo ninguém lhe tocava e o ecrã
   "Acesso Negado" aparecia por cima da app; no login de produção aparecia
   ao fazer scroll. O show() põe display:flex quando for preciso. */
#screen-denied {
  display: none; align-items: center; justify-content: center;
  min-height: 100vh; background: var(--azul-esc);
}
.denied-card {
  background: var(--branco); border-radius: 16px; padding: 48px 40px;
  width: 100%; max-width: 420px; text-align: center;
  box-shadow: var(--s-flutua);
}
.denied-icon { margin-bottom: 16px; color: var(--texto-sec); }
.denied-icon .ico { width: 32px; height: 32px; }
.denied-card h2 { font-size: 22px; font-weight: 700; color: var(--titulo); margin-bottom: 10px; }
.denied-card p  { font-size: 14px; color: var(--texto-sec); line-height: 1.6; margin-bottom: 24px; }

/* ── APP ── */
#screen-app { display: none; min-height: 100vh; }

/* ── SIDEBAR ── */
#sidebar {
  width: var(--sidebar-w); background: var(--azul-esc); color: #fff;
  display: flex; flex-direction: column; position: fixed;
  top: 0; left: 0; height: 100vh; z-index: 100; overflow-y: auto;
}
.sidebar-brand { padding: 20px 18px 14px; border-bottom: 1px solid rgba(255,255,255,.1); }
.brand-logo { font-size: 22px; font-weight: var(--p-forte); letter-spacing: 2px; }
.brand-tag  { font-size: 9px; color: rgba(255,255,255,.4); letter-spacing: 1.5px; text-transform: uppercase; margin-top: 1px; }
.sidebar-user {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 18px; border-bottom: 1px solid rgba(255,255,255,.1);
  background: rgba(0,0,0,.15);
}
.user-avatar {
  width: 34px; height: 34px; border-radius: 50%; background: var(--azul-med);
  display: flex; align-items: center; justify-content: center;
  font-size: 13px; font-weight: 700; flex-shrink: 0; overflow: hidden;
}
.user-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
.user-info { flex: 1; min-width: 0; }
.user-name { font-size: 12px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.user-role { font-size: 10px; color: rgba(255,255,255,.45); }
.nav-section { padding: 18px 18px 5px; font-size: 9px; text-transform: uppercase; letter-spacing: 1.8px; color: rgba(255,255,255,.32); font-weight: 600; }
.nav-item {
  display: flex; align-items: center; gap: 10px;
  margin: 1px 8px; padding: 7px 10px; border-radius: 7px;
  cursor: pointer; font-size: 13px;
  color: rgba(255,255,255,.72);
  transition: background .12s, color .12s;
}
.nav-item:hover  { background: rgba(255,255,255,.07); color: #fff; }
.nav-item.active { background: rgba(255,255,255,.13); color: #fff; font-weight: 600; box-shadow: inset 2px 0 0 #5BA8F5; }
.nav-item .icon  { font-size: 15px; width: 20px; text-align: center; flex-shrink: 0; }
.nav-item .badge-soon { margin-left: auto; font-size: 9px; background: rgba(255,255,255,.12); color: rgba(255,255,255,.45); padding: 2px 6px; border-radius: 99px; }
.nav-item .chevron { margin-left: auto; font-size: 10px; opacity: .6; transition: transform .15s; }
.nav-item.expanded .chevron { transform: rotate(180deg); }
.nav-subgroup { display: none; background: rgba(0,0,0,.18); }
.nav-subgroup.open { display: block; }
/* Submenus escondidos que expandem ao passar o rato (hover). O activo fica preso via .open */
.nav-item:hover + .nav-subgroup,
.nav-subgroup:hover { display: block; }
.nav-sub {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 18px 7px 50px; cursor: pointer; font-size: 12.5px;
  color: rgba(255,255,255,.55); border-left: 3px solid transparent;
  transition: all .15s;
}
.nav-sub:hover { background: rgba(255,255,255,.05); color: #fff; }
.nav-sub.active { color: #fff; border-left-color: #5BA8F5; background: rgba(255,255,255,.06); font-weight: 600; }
.nav-sub .icon { font-size: 13px; width: 16px; text-align: center; }
/* ── Camada de GRUPOS (TÉCNICA, CONTROLE, ...) — colapsável, independente do roteamento ── */
.nav-group {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 18px 7px; cursor: pointer;
  font-size: 10.5px; font-weight: 700; letter-spacing: .6px; text-transform: uppercase;
  color: rgba(255,255,255,.38); user-select: none;
}
.nav-group:hover { color: rgba(255,255,255,.65); }
.nav-group .chevron { margin-left: auto; font-size: 9px; opacity: .6; transition: transform .15s; }
.nav-group.collapsed .chevron { transform: rotate(-90deg); }
.nav-group-body { display: block; }
.nav-group-body.closed { display: none; }
.sidebar-bottom { margin-top: auto; padding: 14px 18px; border-top: 1px solid rgba(255,255,255,.1); display: flex; flex-direction: column; gap: 4px; }
.btn-logout {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px;
  border-radius: 6px; cursor: pointer; font-size: 12px; color: rgba(255,255,255,.5);
  transition: all .15s; border: none; background: none; width: 100%; text-align: left;
}
.btn-logout:hover { background: rgba(255,0,0,.15); color: #FF8080; }
.sidebar-version { font-size: 10px; color: rgba(255,255,255,.2); padding: 0 10px; }

/* ── TOPBAR ── */
#topbar { display:none; }
#topbar-DISABLED {
  position: fixed; top: 0; left: var(--sidebar-w); right: 0;
  height: var(--topbar-h); background: var(--branco);
  border-bottom: 1px solid var(--cinza-brd);
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 28px; z-index: 50;
}
.topbar-left { display: flex; align-items: center; gap: 8px; }
.topbar-module { font-size: 11px; color: var(--texto-sec); }
.topbar-sep    { color: var(--cinza-brd); }
.topbar-title  { font-size: 15px; font-weight: 700; color: var(--titulo); }
.topbar-right  { display: flex; gap: 10px; align-items: center; }

/* ── MAIN ── */
/* 2026-07-31: o #screen-app e flex e o #main, como filho flex, ENCOLHIA para a
   largura do conteudo — cada pagina usava so uma fatia do ecra e o resto ficava
   vazio. flex:1 estica-o para ocupar tudo; min-width:0 deixa as tabelas largas
   fazerem scroll dentro dele em vez de o rebentarem. */
#main { flex: 1; min-width: 0; margin-left: var(--sidebar-w); padding-top: 16px; min-height: 100vh; }
#content { padding: 24px 28px; }

/* ── BUTTONS ── */
.btn { padding: 8px 16px; border-radius: 7px; border: none; cursor: pointer; font-size: 13px; font-weight: 600; transition: background .13s, color .13s, border-color .13s, box-shadow .13s; display: inline-flex; align-items: center; gap: 6px; }
.btn:active { transform: translateY(.5px); }
.btn-primary { background: var(--azul-med); color: #fff; }
.btn-primary:hover { background: var(--azul-hover); }
.btn-danger  { background: var(--vermelho); color: #fff; }
.btn-danger:hover  { background: #c0392b; }
.btn-outline { background: var(--branco); color: var(--texto-sec); border: 1px solid var(--cinza-brd); }
.btn-outline:hover { color: var(--titulo); border-color: var(--azul-med); background: var(--branco); }
.btn-sm { padding: 5px 10px; font-size: 11px; }
.btn:disabled { opacity: .45; cursor: not-allowed; }

/* ── LOADING ── */
#loading {
  display: flex; position: fixed; inset: 0;
  background: var(--azul-esc);
  align-items: center; justify-content: center; z-index: 9999;
  flex-direction: column; gap: 16px;
}
.loading-logo    { font-size: 36px; font-weight: var(--p-forte); color: #fff; letter-spacing: 3px; }
.loading-spinner { width: 36px; height: 36px; border: 3px solid rgba(255,255,255,.2); border-top-color: #fff; border-radius: 50%; animation: spin .7s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ── HOME ── */
.home-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 20px; }
.module-card { background: var(--branco); border-radius: 12px; padding: 22px; box-shadow: var(--s-cartao); cursor: pointer; transition: border-color .15s, box-shadow .15s; border: 1px solid var(--cinza-brd); display: flex; flex-direction: column; gap: 12px; }
/* 2026-07-31: o cartão "saltava" 2px no hover com sombra colorida — efeito de
   página de marketing. Numa ferramenta de trabalho o hover é só a borda. */
.module-card:hover { border-color: var(--azul-med); box-shadow: 0 4px 14px rgba(46,109,164,.13); }
.module-card.soon { opacity: .55; cursor: default; }
.module-card.soon:hover { border-color: transparent; transform: none; box-shadow: var(--s-cartao); }
.mc-icon { width: 42px; height: 42px; border-radius: 10px; background: var(--azul-clar); color: var(--azul-esc); display: flex; align-items: center; justify-content: center; }
.mc-icon .ico { width: 20px; height: 20px; }
[data-theme="dark"] .mc-icon { color: #9CC3E8; }
.mc-name  { font-size: 15px; font-weight: 700; color: var(--titulo); }
.mc-desc  { font-size: 12px; color: var(--texto-sec); line-height: 1.5; }
.mc-badge { display: inline-block; align-self: flex-start; padding: 3px 10px; border-radius: 99px; font-size: 10px; font-weight: 700; }
.mc-badge.active { background: #D4EDDA; color: #155724; }
.mc-badge.soon   { background: #FFF3CD; color: #856404; }
.home-welcome { margin-bottom: 28px; }
.home-welcome h2 { font-size: 22px; font-weight: 700; color: var(--titulo); margin-bottom: 4px; }
.home-welcome p  { font-size: 13px; color: var(--texto-sec); }

/* ── KPI ── */
.kpi-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 24px; }
.kpi-card { background: var(--branco); border: 1px solid var(--cinza-brd); border-radius: 10px; padding: 18px 20px; box-shadow: var(--s-cartao); border-left: 4px solid var(--azul-med); }
.kpi-card.verde    { border-left-color: var(--verde); }
.kpi-card.amarelo  { border-left-color: var(--amarelo); }
.kpi-card.vermelho { border-left-color: var(--vermelho); }
.kpi-label { font-size: 11px; text-transform: uppercase; letter-spacing: .8px; color: var(--texto-sec); margin-bottom: 4px; }
.kpi-value { font-size: 30px; font-weight: 700; color: var(--titulo); line-height: 1.1; font-variant-numeric: tabular-nums; letter-spacing: -.5px; }
.kpi-sub   { font-size: 11px; color: var(--texto-sec); margin-top: 2px; }
.dash-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.dash-card { background: var(--branco); border: 1px solid var(--cinza-brd); border-radius: 10px; padding: 20px; box-shadow: var(--s-cartao); }
.dash-card h3 { font-size: 13px; font-weight: 700; color: var(--titulo); margin-bottom: 14px; padding-bottom: 10px; border-bottom: 1px solid var(--cinza-brd); }
.status-row { display: flex; align-items: center; gap: 10px; padding: 7px 0; border-bottom: 1px solid var(--cinza-brd); font-size: 13px; }
.status-row:last-child { border-bottom: none; }
.status-dot  { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.status-name { flex: 1; }
.status-count{ font-weight: 700; color: var(--titulo); }
.progress-item { margin-bottom: 12px; }
.progress-item:last-child { margin-bottom: 0; }
.progress-label { display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 5px; }
.progress-label span:first-child { font-weight: 600; }
.progress-bar-bg { background: var(--cinza-brd); border-radius: 99px; height: 8px; overflow: hidden; }
.progress-bar { height: 100%; border-radius: 99px; background: var(--azul-med); transition: width .4s; }

/* ── TABLES ── */
.table-card { background: var(--branco); border: 1px solid var(--cinza-brd); border-radius: 10px; box-shadow: var(--s-cartao); overflow: hidden; }
.table-header { padding: 16px 20px; display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid var(--cinza-brd); flex-wrap: wrap; gap: 10px; }
.table-header h3 { font-size: 14px; font-weight: 700; color: var(--titulo); }
@keyframes pulseDot { 0%,100% { opacity: 1; transform: scale(1); } 50% { opacity: .35; transform: scale(.7); } }
.table-search { padding: 6px 12px; border: 1.5px solid var(--cinza-brd); border-radius: 6px; font-size: 13px; width: 220px; outline: none; }
.table-search:focus { border-color: var(--azul-med); }
table { width: 100%; border-collapse: collapse; }
thead th { background: var(--azul-esc); color: #fff; padding: 11px 14px; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .6px; text-align: left; white-space: nowrap; }
thead tr.col-filters th { background: #EEF3F9; padding: 6px 8px; }
[data-theme="dark"] thead tr.col-filters th { background: #1c2a3e; }
.col-filters input, .col-filters select { width: 100%; min-width: 60px; padding: 4px 6px; border: 1px solid var(--cinza-brd); border-radius: 4px; font-size: 11px; font-weight: 400; text-transform: none; letter-spacing: 0; color: var(--texto); background: var(--branco); outline: none; }
.col-filters input:focus, .col-filters select:focus { border-color: var(--azul-med); }
tbody tr { border-bottom: 1px solid var(--cinza-brd); transition: background .1s; }
tbody tr:hover { background: #F7FAFD; }
[data-theme="dark"] tbody tr:hover { background: #16202e; }
tbody tr:last-child { border-bottom: none; }
tbody td { padding: 10px 14px; font-size: 13px; vertical-align: middle; font-variant-numeric: tabular-nums; }
.empty-row td { text-align: center; color: var(--texto-sec); padding: 32px; font-size: 13px; }

/* ── BADGES ── */
/* (2026-08-01) Limpeza: 12 classes órfãs removidas (badge-em-curso/planeado/
   concluido/suspenso/cancelado/a-fazer/bloqueada/ativo/inativo, btn-success,
   gp-inline-sel, prior-urgente) — zero usos em todo o projeto; git guarda. */
.badge { display: inline-block; padding: 3px 10px; border-radius: 99px; font-size: 11px; font-weight: 600; white-space: nowrap; }
.badge-revisao   { background: #D6E4F0; color: #1A3C5E; }
.badge-altissima { background: #B71C1C; color: #FFFFFF; }
.tmpl-chip {
  display: inline-block;
  background: var(--cinza-bg);
  color: var(--texto);
  border: 1px solid var(--cinza-brd);
  border-radius: 4px;
  padding: 2px 7px;
  margin: 2px 3px 2px 0;
  font-size: 10px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  cursor: pointer;
  transition: background .15s;
}
.tmpl-chip:hover { background: var(--azul-clar); color: var(--titulo); border-color: var(--titulo); }
.badge-urgente   { background: #E74C3C; color: #FFFFFF; }
.badge-alta      { background: #FFF3CD; color: #8A5A00; }
.badge-media     { background: #ECEFF1; color: #455A64; }
.badge-baixa     { background: #ECEFF1; color: #78909C; }
/* Role badges */
.badge-admin      { background: #1A3C5E; color: #fff; }
.badge-supervisor { background: #2E6DA4; color: #fff; }
.badge-user       { background: #ECEFF1; color: #5A6A7E; }

/* ── PROGRESS MINI ── */
.prog-mini { display: flex; align-items: center; gap: 8px; }
.prog-mini-bar  { flex: 1; background: var(--cinza-brd); border-radius: 99px; height: 6px; overflow: hidden; min-width: 60px; }
.prog-mini-fill { height: 100%; border-radius: 99px; background: var(--azul-med); }
.prog-mini-pct  { font-size: 11px; font-weight: 600; color: var(--texto-sec); min-width: 32px; }

/* ── FILTER BAR ── */
.filter-bar { display: flex; gap: 10px; margin-bottom: 16px; flex-wrap: wrap; align-items: center; }
.filter-bar select { padding: 7px 12px; border: 1.5px solid var(--cinza-brd); border-radius: 6px; font-size: 12px; outline: none; background: var(--branco); }
.filter-bar select:focus { border-color: var(--azul-med); }

/* ── AVATAR ── */
.avatar { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 50%; background: var(--azul-clar); color: var(--titulo); font-size: 11px; font-weight: 700; }
.action-btns { display: flex; gap: 6px; }

/* ── MODAL ── */
.modal-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.45); z-index: 1000; align-items: center; justify-content: center; }
.modal-overlay.open { display: flex; }
.modal { background: var(--branco); border-radius: 12px; width: 100%; max-width: 560px; max-height: 90vh; overflow-y: auto; box-shadow: var(--s-flutua); animation: slideUp .2s ease; }
@keyframes slideUp { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
.modal-header { padding: 18px 24px; background: var(--azul-esc); border-radius: 12px 12px 0 0; display: flex; align-items: center; justify-content: space-between; }
.modal-header h3 { color: #fff; font-size: 15px; font-weight: 700; }
.modal-close { background: none; border: none; color: rgba(255,255,255,.6); font-size: 22px; cursor: pointer; line-height: 1; }
.modal-close:hover { color: #fff; }
.modal-body   { padding: 24px; }
.modal-footer { padding: 16px 24px; border-top: 1px solid var(--cinza-brd); display: flex; gap: 10px; justify-content: flex-end; }
.form-row  { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 14px; }
.form-row.single { grid-template-columns: 1fr; }
.form-group { display: flex; flex-direction: column; gap: 5px; }
.form-group label { font-size: 11px; font-weight: 700; color: var(--texto-sec); text-transform: uppercase; letter-spacing: .5px; }
.form-group input, .form-group select, .form-group textarea {
  padding: 8px 12px; border: 1.5px solid var(--cinza-brd); border-radius: 6px;
  font-size: 13px; font-family: inherit; outline: none; transition: border-color .15s;
  background: var(--branco); color: var(--texto);
}
.form-group input:focus, .form-group select:focus, .form-group textarea:focus { border-color: var(--azul-med); }
.form-group textarea { resize: vertical; min-height: 70px; }
.form-group input:disabled, .form-group select:disabled { background: var(--cinza-bg); color: var(--texto-sec); cursor: not-allowed; }

/* ── TOAST ── */
#toast-container { position: fixed; bottom: 24px; right: 24px; z-index: 9999; display: flex; flex-direction: column; gap: 10px; }
.toast { background: var(--azul-esc); color: #fff; padding: 12px 18px; border-radius: 8px; font-size: 13px; font-weight: 600; box-shadow: 0 4px 16px rgba(0,0,0,.2); display: flex; align-items: center; gap: 10px; animation: fadeIn .2s ease; min-width: 220px; }
.toast.success { background: var(--verde); }
.toast.error   { background: var(--vermelho); }
@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }

/* ── CONFIRM ── */
#confirm-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.5); z-index: 2000; align-items: center; justify-content: center; }
#confirm-overlay.open { display: flex; }
#confirm-box { background: var(--branco); border-radius: 12px; padding: 28px; max-width: 360px; width: 100%; box-shadow: var(--s-flutua); text-align: center; }
#confirm-box h4 { font-size: 16px; font-weight: 700; margin-bottom: 8px; }
#confirm-box p  { font-size: 13px; color: var(--texto-sec); margin-bottom: 20px; }
#confirm-box .btns { display: flex; gap: 10px; justify-content: center; }

/* ── COMING SOON ── */
.coming-soon-wrap { display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 50vh; gap: 16px; text-align: center; }
.coming-soon-wrap .cs-icon { color: var(--texto-sec); }
.coming-soon-wrap .cs-icon .ico { width: 32px; height: 32px; margin: 0 auto; }
.coming-soon-wrap h2 { font-size: 22px; font-weight: 700; color: var(--titulo); }
.coming-soon-wrap p  { font-size: 14px; color: var(--texto-sec); max-width: 380px; line-height: 1.6; }

/* ── SETUP BANNER ── */
#setup-banner { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.7); z-index: 9000; align-items: center; justify-content: center; }
#setup-banner.show { display: flex; }
.setup-card { background: var(--branco); border-radius: 16px; padding: 36px 40px; max-width: 560px; width: 100%; box-shadow: 0 20px 60px rgba(0,0,0,.3); }
.setup-card h2 { font-size: 20px; font-weight: 700; color: var(--titulo); margin-bottom: 8px; }
.setup-card p  { font-size: 13px; color: var(--texto-sec); margin-bottom: 20px; line-height: 1.6; }
.setup-card ol { margin-left: 20px; font-size: 13px; color: var(--texto-sec); line-height: 2; margin-bottom: 20px; }
.setup-card ol li a { color: var(--azul-med); }
.setup-card code { background: var(--cinza-bg); padding: 2px 6px; border-radius: 4px; font-size: 12px; color: var(--vermelho); }

.section { display: none; }
.section.active { display: block; }

/* ── NOTIFICATION BELL ── */

/* 2026-07-31: o sino deixou de flutuar por cima do conteúdo — vive agora na
   linha do utilizador, dentro do menu. Botão fantasma, discreto. */
.notif-bell {
  position: relative;
  width: 28px; height: 28px; border-radius: 7px; flex-shrink: 0;
  background: transparent; border: none; color: rgba(255,255,255,.55);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; transition: background .13s, color .13s;
}
.notif-bell:hover { background: rgba(255,255,255,.10); color: #fff; }
.notif-bell .notif-badge {
  position: absolute; top: -3px; right: -3px;
  background: #E74C3C; color: #fff; font-size: 10px;
  border-radius: 99px; padding: 1px 5px; min-width: 16px; text-align: center;
}

.notif-badge {
  position: absolute; top: 4px; right: 4px;
  background: var(--vermelho); color: #fff;
  font-size: 9px; font-weight: 700; min-width: 16px; height: 16px;
  border-radius: 99px; display: flex; align-items: center; justify-content: center;
  padding: 0 4px;
}

/* ── NOTIFICATION PANEL ── */
.notif-panel {
  position: fixed; top: var(--topbar-h); right: 0; width: 360px;
  height: calc(100vh - var(--topbar-h)); background: var(--branco);
  border-left: 1px solid var(--cinza-brd); z-index: 200;
  display: none; flex-direction: column; box-shadow: -4px 0 20px rgba(0,0,0,.08);
}
.notif-panel.open { display: flex; }
.notif-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 18px; border-bottom: 1px solid var(--cinza-brd);
  flex-shrink: 0;
}
.notif-header h3 { font-size: 15px; font-weight: 700; }
.notif-list { flex: 1; overflow-y: auto; }
.notif-item {
  padding: 14px 18px; border-bottom: 1px solid var(--cinza-brd);
  cursor: pointer; transition: background .15s;
}
.notif-item:hover { background: var(--cinza-bg); }
.notif-item.unread { background: #EEF5FF; }
.notif-item.unread:hover { background: #dceeff; }
.notif-item-icon { font-size: 20px; margin-right: 10px; flex-shrink: 0; }
.notif-item-body { flex: 1; min-width: 0; }
.notif-item-title { font-size: 13px; font-weight: 600; color: var(--texto); margin-bottom: 2px; }
.notif-item-desc  { font-size: 11px; color: var(--texto-sec); }
.notif-item-time  { font-size: 10px; color: var(--texto-sec); margin-top: 4px; }
.notif-item-row   { display: flex; align-items: flex-start; }
.notif-empty { padding: 40px; text-align: center; color: var(--texto-sec); font-size: 13px; }

/* ── EQUIPA CARDS ── */
.eq-membros-pills { display: flex; flex-wrap: wrap; gap: 4px; }
.eq-pill { background: var(--azul-clar); color: var(--titulo); font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 99px; white-space: nowrap; }

/* ── GP: SELECT INLINE (edição de estado/prioridade na tabela) ── */
.gp-inline-sel:focus { border-color: var(--azul-med); }

/* ── GP: KANBAN ── */
.kb-board { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; align-items: start; }
.kb-col { background: var(--cinza-bg); border: 1px solid var(--cinza-brd); border-radius: 10px; padding: 10px; min-height: 320px; }
.kb-col.drag-over { outline: 2px dashed var(--azul-med); outline-offset: -4px; }
.kb-col-head { display: flex; align-items: center; justify-content: space-between; font-size: 12px; font-weight: 700; color: var(--texto-sec); text-transform: uppercase; letter-spacing: .6px; padding: 2px 4px 10px; }
.kb-count { background: var(--branco); border: 1px solid var(--cinza-brd); border-radius: 99px; padding: 1px 8px; font-size: 11px; }
.kb-card { background: var(--branco); border-radius: 8px; padding: 10px 12px; margin-bottom: 8px; box-shadow: 0 1px 3px rgba(0,0,0,.08); cursor: grab; border-left: 3px solid var(--cinza-brd); font-size: 12.5px; }
.kb-card:active { cursor: grabbing; }
.kb-card.prior-alta { border-left-color: #F39C12; }
.kb-card.prior-media { border-left-color: #B0BEC5; }
.kb-card.prior-baixa { border-left-color: #CFD8DC; }
.kb-card .kb-proj { font-size: 10.5px; color: var(--texto-sec); margin-bottom: 3px; }
.kb-card .kb-meta { display: flex; align-items: center; gap: 8px; margin-top: 7px; font-size: 11px; color: var(--texto-sec); }
.kb-card .kb-meta .avatar { width: 22px; height: 22px; font-size: 9px; }
.kb-late { color: var(--vermelho); font-weight: 700; }

/* ── RESPONSIVE ── */
#sidebar-toggle { display: none; position: fixed; top: 10px; left: 10px; z-index: 300; width: 40px; height: 40px; border-radius: 8px; border: none; background: var(--azul-esc); color: #fff; font-size: 18px; cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,.25); }
@media (max-width: 1024px) {
  #sidebar { transform: translateX(-100%); transition: transform .2s ease; }
  #sidebar.open { transform: translateX(0); box-shadow: 4px 0 24px rgba(0,0,0,.35); }
  #sidebar-toggle { display: block; }
  #main { margin-left: 0; }
  #content { padding: 62px 14px 24px; }
}
@media (max-width: 768px) {
  .kpi-grid { grid-template-columns: 1fr 1fr; }
  .dash-grid { grid-template-columns: 1fr; }
  .form-row { grid-template-columns: 1fr; }
  .kb-board { grid-template-columns: 1fr; }
  .table-header { flex-direction: column; align-items: stretch; }
  .table-search { width: 100%; }
  thead th { padding: 8px; font-size: 10px; }
  tbody td { padding: 8px; font-size: 12px; }
  .notif-panel { width: 100vw; }
  .modal { max-width: 96vw; }
}

/* ── DARK MODE (experimental — via variáveis) ── */
[data-theme="dark"] {
  --azul-clar: #1e3a5c; --azul-esc: #0f2135;
  --cinza-bg: #10161f; --cinza-brd: #2a3648; --branco: #1a2332;
  --texto: #E8EDF4; --texto-sec: #8FA1B8; --titulo: #E8EDF4;
}
[data-theme="dark"] thead tr.col-filters th { background: #20304a; }
[data-theme="dark"] .notif-item.unread { background: #152a44; }
[data-theme="dark"] .notif-item.unread:hover { background: #1b344f; }

[data-theme="dark"] .kb-card { box-shadow: 0 1px 3px rgba(0,0,0,.4); }


/* Linha de tarefa atrasada — tinta leve de alerta que respeita o tema */
.row-atrasada { background: #FFF5F5; }
[data-theme="dark"] .row-atrasada { background: #2a1a1e; }

/* ── GP: PESQUISA GLOBAL (Ctrl+K) ── */
#gp-palette-overlay { display: none; position: fixed; inset: 0; background: rgba(10,20,35,.45); z-index: 2500; align-items: flex-start; justify-content: center; padding: 12vh 16px 0; }
#gp-palette-overlay.open { display: flex; }
.pal-box { width: 100%; max-width: 560px; background: var(--branco); border-radius: 12px; box-shadow: var(--s-flutua); overflow: hidden; }
#gp-palette-input { width: 100%; padding: 15px 18px; border: none; outline: none; font-size: 15px; background: var(--branco); color: var(--texto); border-bottom: 1px solid var(--cinza-brd); }
#gp-palette-list { max-height: 46vh; overflow-y: auto; }
.pal-item { display: flex; align-items: center; gap: 10px; padding: 10px 16px; cursor: pointer; font-size: 13.5px; border-bottom: 1px solid var(--cinza-bg); }
.pal-item:hover, .pal-item.sel { background: var(--azul-clar); }
.pal-item .pal-tipo { margin-left: auto; font-size: 10px; text-transform: uppercase; letter-spacing: .5px; color: var(--texto-sec); white-space: nowrap; }
.pal-empty { padding: 18px; text-align: center; color: var(--texto-sec); font-size: 13px; }

/* ── GP: SELEÇÃO MÚLTIPLA ── */
.gp-sel-cb { width: 15px; height: 15px; cursor: pointer; }
tr.gp-row-sel { background: #EEF5FF !important; }
[data-theme="dark"] tr.gp-row-sel { background: #152a44 !important; }
[data-theme="dark"] #gp-bulkbar { background: #152a44 !important; }

/* ── GP: PAINEL AGORA (presença) ── */
.agora-badge { display: inline-block; padding: 2px 10px; border-radius: 99px; font-size: 12px; font-weight: 600; color: #fff; }
.agora-badge.on { background: #27AE60; }
.agora-badge.pausa { background: #F39C12; }
.agora-badge.off { background: #8b95a1; }

/* ── GP: caixa de seleção de equipas (chips) ── */
.eq-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 12px; border-radius: 99px;
  border: 1px solid var(--cinza-brd); background: var(--branco, #fff);
  font-size: 12.5px; line-height: 1.4; color: var(--texto-sec);
  cursor: pointer; user-select: none; transition: all .12s ease;
}
.eq-chip:hover { border-color: var(--azul-med, #2E6DA4); color: var(--texto); }
.eq-chip > input { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; }
.eq-chip > span { text-transform: lowercase; }
.eq-chip::before {
  content: ""; width: 14px; height: 14px; border-radius: 4px; flex: 0 0 auto;
  border: 1.5px solid var(--cinza-brd); background: transparent; transition: all .12s ease;
}
.eq-chip.on {
  background: color-mix(in srgb, var(--azul-med, #2E6DA4) 12%, transparent);
  border-color: var(--azul-med, #2E6DA4); color: var(--azul-med, #2E6DA4); font-weight: 600;
}
.eq-chip.on::before {
  background: var(--azul-med, #2E6DA4); border-color: var(--azul-med, #2E6DA4);
  box-shadow: inset 0 0 0 2px var(--branco, #fff);
}
[data-theme="dark"] .eq-chip { background: transparent; }

/* ── "EM BREVE" ESCONDIDO (2026-07-31, pedido do dono) ──
   O que ainda não existe não aparece. Para reativar um item quando o
   módulo ficar pronto: tirar a classe "em-breve" a esse elemento no
   index.html (a pastilha badge-soon pode ficar, volta a ver-se sozinha). */
.em-breve { display: none !important; }

/* ══ MÓDULO CALENDÁRIO/NOTIFICAÇÕES (2026-09-02) ══════════════════════
   O Offy não tinha nenhuma vista com eixo de horas — o Agendamento das
   assistências é por dia e por ordem de rota, não por relógio. Isto é a
   parte nova; o resto do módulo usa as classes que já existem acima
   (.modal, .btn-primary, .modal-overlay…).

   Só variáveis da casa: nenhuma cor, tamanho ou raio escrito à mão. */

/* Barra de cima */
.cal-barra { display:flex; align-items:center; gap:12px; margin-bottom:14px; flex-wrap:wrap; }
.cal-barra h2 { font-size:var(--t-lg); font-weight:var(--p-medio); color:var(--titulo); margin:0; }
.cal-nav { display:flex; gap:4px; }
.cal-nav button { padding:5px 10px; font-size:var(--t-base); border:1px solid var(--cinza-brd);
  background:var(--branco); color:var(--texto); border-radius:var(--r-sm); cursor:pointer; }
.cal-nav button:hover { border-color:var(--azul-med); }
/* A seta "semana anterior" do RH desliga-se ao chegar à semana actual — uma segunda
   que já passou não tem porque reaparecer. Mesmo padrão do × dos tópicos (.rh-top-x). */
.cal-nav button:disabled { opacity:.35; cursor:default; }
.cal-nav button:disabled:hover { border-color:var(--cinza-brd); }
.cal-vistas { margin-left:auto; display:flex; gap:4px; }
.cal-vistas button { padding:5px 12px; font-size:var(--t-base); border:1px solid var(--cinza-brd);
  background:var(--branco); color:var(--texto-sec); border-radius:var(--r-sm); cursor:pointer; }
.cal-vistas button.ativo { background:var(--azul-clar); color:var(--azul-esc);
  border-color:var(--azul-med); font-weight:var(--p-medio); }

/* Cartão que envolve o calendário */
.cal-caixa { background:var(--branco); border:1px solid var(--cinza-brd);
  border-radius:var(--r-md); box-shadow:var(--s-cartao); overflow:hidden; }
.cal-vazio, .cal-erro { padding:32px; text-align:center; color:var(--texto-sec); font-size:var(--t-base); }
/* Uma leitura falhada NÃO pode parecer "não tem nada marcado" */
.cal-erro { color:var(--vermelho); }

/* ── Vista de ANO ──
   Doze mini-meses. So numeros e um ponto nos dias com marcacoes: mostra QUE ha,
   nao QUAIS. Clicar num dia abre o mes desse dia.
   Sem cores escritas a mao — so as variaveis da casa. */
.cal-ano { display:grid; grid-template-columns:repeat(4,1fr); gap:18px; padding:18px; }
.cal-ano-mes { min-width:0; }
.cal-ano-tit { font-size:var(--t-base); font-weight:var(--p-forte); color:var(--titulo);
  text-align:center; padding:4px 0 6px; cursor:pointer; border-radius:var(--r-sm); }
.cal-ano-tit:hover { background:var(--cinza-bg); }
.cal-ano-dow { display:grid; grid-template-columns:repeat(7,1fr); }
.cal-ano-dow span { text-align:center; font-size:var(--t-xs); color:var(--texto-sec);
  font-weight:var(--p-medio); padding-bottom:3px; }
.cal-ano-grelha { display:grid; grid-template-columns:repeat(7,1fr); gap:1px; }
.cal-ano-d { position:relative; aspect-ratio:1; display:flex; align-items:center;
  justify-content:center; font-size:var(--t-xs); color:var(--texto);
  border-radius:var(--r-sm); cursor:pointer; }
.cal-ano-d:hover { background:var(--azul-clar); }
.cal-ano-d.fora { color:var(--cinza-brd); }
.cal-ano-d.hoje { background:var(--azul-med); color:var(--branco); font-weight:var(--p-forte); }
/* O ponto: um dia com marcacoes le-se de relance, sem ler o numero. */
.cal-ano-d.tem::after { content:''; position:absolute; bottom:1px; left:50%;
  transform:translateX(-50%); width:4px; height:4px; border-radius:50%;
  background:var(--azul-med); }
.cal-ano-d.hoje.tem::after { background:var(--branco); }

@media (max-width:1100px) { .cal-ano { grid-template-columns:repeat(3,1fr); } }
@media (max-width:820px)  { .cal-ano { grid-template-columns:repeat(2,1fr); gap:12px; padding:12px; } }
@media (max-width:520px)  { .cal-ano { grid-template-columns:1fr; } }

/* ── Vista de mês ── */
.cal-mes-cab { display:grid; grid-template-columns:repeat(7,1fr); border-bottom:1px solid var(--cinza-brd); }
.cal-mes-cab div { padding:8px 6px; text-align:center; font-size:var(--t-sm);
  color:var(--texto-sec); font-weight:var(--p-medio); }
.cal-mes-grelha { display:grid; grid-template-columns:repeat(7,1fr); }
.cal-cel { min-height:92px; padding:4px; border-right:1px solid var(--cinza-brd);
  border-bottom:1px solid var(--cinza-brd); cursor:pointer; overflow:hidden; }
.cal-cel:nth-child(7n) { border-right:none; }
.cal-cel:hover { background:var(--cinza-bg); }
.cal-cel.fora { background:var(--cinza-bg); }
.cal-cel.fora .cal-cel-dia { color:var(--texto-sec); opacity:.55; }
.cal-cel.hoje .cal-cel-dia { background:var(--azul-med); color:var(--branco);
  border-radius:var(--r-pill); padding:1px 7px; }
.cal-cel-dia { font-size:var(--t-sm); color:var(--texto-sec); margin-bottom:3px; display:inline-block; }
.cal-mais { font-size:var(--t-xs); color:var(--texto-sec); padding-left:3px; }

/* Pastilha de um compromisso */
.cal-chip { background:var(--azul-clar); color:var(--azul-esc); border-radius:var(--r-sm);
  padding:2px 6px; font-size:var(--t-xs); margin-bottom:2px; cursor:pointer;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.cal-chip:hover { background:var(--azul-med); color:var(--branco); }
.cal-chip.inteiro { background:var(--azul-med); color:var(--branco); }
/* Prazo de tarefa (não é um compromisso) — cor diferente para se distinguir à vista.
   Vem depois de `.inteiro` de propósito: as tarefas também são "dia inteiro", e esta
   regra tem de ganhar a cor a essa. */
.cal-chip.tarefa { background:var(--amarelo); color:var(--azul-esc); }
.cal-chip.tarefa:hover { background:var(--amarelo); opacity:.85; }

/* ── Vista de semana / dia: o eixo de horas ── */
.cal-h-cab, .cal-h-inteiro, .cal-h-corpo {
  display:grid; grid-template-columns:56px repeat(var(--cal-cols),1fr); }
.cal-h-cab { border-bottom:1px solid var(--cinza-brd); }
.cal-h-dia { padding:8px 6px; text-align:center; font-size:var(--t-base); color:var(--texto); }
.cal-h-dia.hoje { color:var(--azul-med); font-weight:var(--p-medio); }
.cal-h-dow { color:var(--texto-sec); font-size:var(--t-sm); }
.cal-h-eixo { font-size:var(--t-xs); color:var(--texto-sec); padding:6px; text-align:right; }

/* A faixa de "dia inteiro" é uma zona SEPARADA do eixo, de propósito: um evento
   sem hora não é o mesmo objecto pousado à meia-noite. */
.cal-h-inteiro { border-bottom:2px solid var(--cinza-brd); background:var(--cinza-bg); min-height:30px; }
.cal-h-col-inteiro { padding:3px 4px; border-right:1px solid var(--cinza-brd); }

.cal-h-corpo { position:relative; }
.cal-h-eixo-col { border-right:1px solid var(--cinza-brd); }
.cal-h-marca { font-size:var(--t-xs); color:var(--texto-sec); text-align:right;
  padding:2px 6px 0 0; border-bottom:1px solid var(--cinza-bg); }
.cal-h-col { position:relative; border-right:1px solid var(--cinza-brd); cursor:pointer; }
.cal-h-col.hoje { background:rgba(46,109,164,.03); }

/* Bandas do horário de trabalho (9-13 e 14-18) — a hora de almoço vê-se */
.cal-banda { position:absolute; left:0; right:0; background:var(--branco); pointer-events:none; }
.cal-h-col { background:var(--cinza-bg); }

/* Um compromisso na grelha */
.cal-bloco { position:absolute; left:3px; right:3px; background:var(--azul-clar);
  border-left:3px solid var(--azul-med); border-radius:var(--r-sm); padding:2px 5px;
  font-size:var(--t-xs); color:var(--azul-esc); overflow:hidden; cursor:pointer; z-index:1; }
.cal-bloco:hover { background:var(--azul-med); color:var(--branco); }
/* Compromisso fora do eixo de horas mostrado (07:00-21:00). Fica preso na borda em vez
   de desaparecer: antes havia um `continue` que o escondia da semana, e ele continuava
   a aparecer no mes -- ver num sitio e nao ver no outro e pior do que nao ver de todo.
   A hora dentro do bloco mostra a verdadeira, e o tracejado diz que esta encostado. */
.cal-bloco.fora { border:1px dashed var(--amarelo); background:var(--cinza-bg); color:var(--texto-sec); }
.cal-bloco-h { font-weight:var(--p-medio); }
.cal-bloco-t { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.cal-bloco-r { font-size:var(--t-xs); opacity:.75; }

/* ── Editor ── */
/* ⛔ ISTO ERA `max-width:520px` — mais estreito que TODOS os outros modais da casa
   (o `.modal` sao 560px), sem razao nenhuma. Com tres campos numa linha (Dia · Hora ·
   Duracao) dentro de 520px, ficava apertado. Herda agora a largura da casa. */
/* ⛔ AQUI VIVIAM `.cal-rot` E `.cal-campo`, INVENTADAS POR MIM.
   Faziam etiquetas em minusculas de 12px e campos com borda de 1px e raio 4px, quando
   todos os outros modais da casa usam `.form-group` — etiqueta 11px MAIUSCULAS bold,
   borda 1.5px, raio 6px. O dono olhou para o formulario da sala e disse "ta muito
   basico e muito artificial": era isso, um formulario que nao se parecia com nenhum
   outro da aplicacao. Foram apagadas de proposito, para ninguem lhes voltar a pegar. */

/* A unica coisa que faltava a casa: a linha de ajuda por baixo de um campo. */
.form-ajuda { font-size:var(--t-xs); color:var(--texto-sec); line-height:1.45; }

/* Tres campos numa linha (Dia · Hora · Duracao). O `.form-row` da casa e de dois. */
.cal-linha-3 { grid-template-columns:1fr 1fr 1fr; }
/* Fica entre duas linhas de campos, por isso leva margem dos DOIS lados: sem a de
   baixo, colava-se a etiqueta "REPETE" da linha seguinte. */
.cal-check { display:flex; align-items:center; gap:7px; margin:2px 0 14px;
  font-size:var(--t-base); color:var(--texto); cursor:pointer; }
.cal-ops { display:flex; gap:5px; flex-wrap:wrap; }
.cal-op { padding:5px 12px; font-size:var(--t-sm); border:1px solid var(--cinza-brd);
  background:var(--branco); color:var(--texto-sec); border-radius:var(--r-sm); cursor:pointer; }
.cal-op.ativo { background:var(--azul-clar); color:var(--azul-esc);
  border-color:var(--azul-med); font-weight:var(--p-medio); }
/* Dentro de um campo da casa, os botoes ficam com a MESMA altura e a mesma borda dos
   inputs ao lado. Sem isto tinham 26px contra os 34px do campo ao lado, e a linha
   ficava a saltar -- visto no browser antes de publicar. */
.form-group .cal-op { padding:8px 14px; border-width:1.5px; border-radius:6px;
  font-size:var(--t-base); }
.form-group .cal-ops { gap:6px; }
.cal-nota-op { font-size:var(--t-xs); color:var(--texto-sec); margin-top:5px; }
.cal-erro-linha { display:none; color:var(--vermelho); font-size:var(--t-sm); margin-top:5px; }
/* ⛔ ISTO ERA PASTILHAS QUE QUEBRAVAM LINHA (`display:flex; flex-wrap:wrap`), copiadas
   da caixa de equipas do modal de projeto. Numa lista de 20+ pessoas ficava "tudo ao
   molho" — o dono viu-o e disse-o. Agora e uma lista vertical de verdade: uma pessoa
   por linha, com scroll quando nao cabe, como uma caixa de selecao normal. */
.cal-conv-lista { display:flex; flex-direction:column; padding:2px;
  border:1.5px solid var(--cinza-brd); border-radius:var(--r-md);
  background:var(--branco); max-height:190px; overflow-y:auto; }
.cal-conv-linha { display:flex; align-items:center; gap:10px; padding:7px 10px;
  border-radius:var(--r-sm); cursor:pointer; user-select:none; }
.cal-conv-linha:hover { background:var(--cinza-bg); }
.cal-conv-linha.on { background:var(--azul-clar); }
.cal-conv-linha input { flex:0 0 auto; }
/* As iniciais e o circulo sao a MESMA classe .avatar do canto da barra lateral
   (styles.css:356) — so o tamanho muda, como o `.kb-card .kb-meta .avatar` ja faz. */
.cal-conv-avatar { width:24px; height:24px; font-size:9.5px; flex:0 0 auto; }
/* ⛔ CADA LINHA É UM <label> (para o clique cair no checkbox), e vive dentro de
   `.form-group` — cuja regra `.form-group label { text-transform:uppercase; ... }` é
   para as ETIQUETAS DOS CAMPOS ("TÍTULO", "DIA"). Sem esta excepção, herdava-se por
   acidente: o texto já vinha certo ("André Cavalcante") e o CSS reescrevia-o por cima
   para "ANDRÉ CAVALCANTE". Visto no browser antes de publicar. */
.cal-conv-nome { font-size:var(--t-base); font-weight:var(--p-normal);
  color:var(--texto); text-transform:none; letter-spacing:normal; }

/* Campo so de leitura no ecra do convite: parece um campo, mas nao se escreve nele. */
.cal-so-ler { padding:8px 12px; border:1.5px solid var(--cinza-brd); border-radius:6px;
  background:var(--cinza-bg); color:var(--texto); font-size:var(--t-base); }

/* Um compromisso para que fui convidado: nao e meu, e ve-se. */
.cal-bloco.convite { border-left-style:dashed; }
.cal-chip.convite { border-left:3px dashed var(--azul-med); padding-left:5px; }

/* A leitura dos convites falhou: a agenda esta incompleta e tem de o dizer. */
.cal-erro-faixa { margin:10px 12px 0; padding:8px 12px; border-radius:var(--r-sm);
  background:var(--cinza-bg); border-left:3px solid var(--amarelo);
  font-size:var(--t-sm); color:var(--texto); }

.cal-aviso-serie { margin-top:12px; padding:8px 10px; border-radius:var(--r-sm);
  background:var(--cinza-bg); border-left:3px solid var(--amarelo);
  font-size:var(--t-sm); color:var(--texto); }

/* Cabecalho de "quando" dos formularios da sala e do RH: o dia e a hora que a pessoa
   escolheu, para nao ter de se lembrar em que celula carregou. */
.sala-quando { display:flex; align-items:baseline; gap:10px; padding:10px 12px;
  background:var(--cinza-bg); border-radius:var(--r-sm); margin-bottom:4px; }
/* ⛔ `text-transform:capitalize` punha maiuscula em TODAS as palavras: "Segunda-Feira,
   7 De Setembro". So a primeira letra e que sobe — o resto vem ja certo do
   toLocaleDateString('pt-PT'). Visto no browser antes de publicar. */
.sala-quando-dia { font-size:var(--t-md); font-weight:var(--p-forte); color:var(--titulo); }
.sala-quando-dia::first-letter { text-transform:uppercase; }
.sala-quando-hora { font-size:var(--t-base); color:var(--texto-sec); }

/* Uma linha da lista de topicos do RH: campo + botao de remover. */
.rh-top-linha { display:flex; gap:6px; align-items:center; margin-bottom:6px; }
/* ⛔ Sem `flex:1` o campo ficava com a largura do conteudo (~200px) e a linha parecia
   meia vazia. E o `.form-group` e uma coluna flex, por isso o botao de acrescentar
   esticava a toda a largura e lia-se como mais um campo, nao como um botao.
   Visto no browser antes de publicar. */
.rh-top-linha input { flex:1; min-width:0; }
.rh-top-mais { align-self:flex-start; margin-top:2px; }
.rh-top-x { flex:0 0 auto; width:30px; height:30px; line-height:1; font-size:var(--t-md);
  border:1px solid var(--cinza-brd); background:var(--branco); color:var(--texto-sec);
  border-radius:var(--r-sm); cursor:pointer; }
.rh-top-x:hover:not(:disabled) { border-color:var(--vermelho); color:var(--vermelho); }
.rh-top-x:disabled { opacity:.35; cursor:default; }

@media (max-width:760px) {
  .cal-linha-3 { grid-template-columns:1fr; }
  .cal-cel { min-height:64px; }
}

/* ═══ SALA DE REUNIÕES E RH ═══════════════════════════════════════════════════
   Reutiliza as variáveis da casa e as classes .cal-* onde dá (.cal-caixa,
   .cal-barra, .cal-vazio, .cal-erro). Só o que é próprio da grelha vive aqui. */

.sala-grelha { display:grid; }
.sala-cab, .sala-linha {
  display:grid; grid-template-columns:64px repeat(var(--sala-cols,5),1fr);
}
.sala-cab { border-bottom:1px solid var(--cinza-brd); }
.sala-dia, .sala-eixo-cab {
  padding:8px 6px; text-align:center; font-size:var(--t-sm);
  color:var(--texto-sec); font-weight:var(--p-medio);
}
.sala-eixo {
  padding:6px; font-size:var(--t-xs); color:var(--texto-sec);
  text-align:right; border-right:1px solid var(--cinza-brd);
}
/* ⛔ ISTO TINHA `white-space:nowrap` + reticencias. Numa coluna de ~200px, "Reuniao
   comercial trimestral" ficava "Reuniao comer...". O `title` salvava no hover, mas
   quem passa os olhos pela grelha nao passa o rato por cima de tudo.
   Agora o texto passa a duas linhas, e so a partir dai e que corta. */
.sala-cel {
  min-height:var(--sala-alt,46px); padding:6px; border-right:1px solid var(--cinza-brd);
  border-bottom:1px solid var(--cinza-brd); font-size:var(--t-xs);
  overflow:hidden; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
  line-clamp:2; word-break:break-word;
}
.sala-cel:last-child { border-right:none; }
.sala-cel.livre { color:var(--texto-sec); text-align:center; cursor:pointer; opacity:.45; }
.sala-cel.livre:hover { background:var(--azul-clar); color:var(--azul-esc); opacity:1; }
.sala-cel.ocupada { background:var(--azul-clar); color:var(--azul-esc); }
.sala-cel.ocupada.minha { background:var(--azul-med); color:var(--branco); cursor:pointer; }
/* A segunda (e terceira) hora de uma reuniao longa: mesma cor, texto discreto. */
.sala-cel.ocupada.continua { opacity:.72; }
.sala-cont { font-size:9px; opacity:.7; font-style:italic; }
/* Um bloco de RH visto por terceiros: ocupado, sem dizer de quem nem porquê. */
.sala-cel.ocupada.rh { background:var(--cinza-bg); color:var(--texto-sec); font-style:italic; }

.rh-lista { padding:4px; }
.rh-nota {
  padding:10px 12px; margin-bottom:10px; background:var(--cinza-bg);
  border-radius:var(--r-sm); font-size:var(--t-sm); color:var(--texto-sec);
}
.rh-bloco {
  /* A altura vem do JS (`--rh-alt`), calculada com o espaco que a pagina tem. Com
     `padding` fixo, oito blocos davam ~30px cada e sobrava meia pagina em branco. */
  min-height:var(--rh-alt,44px);
  display:flex; align-items:center; gap:12px; padding:10px 12px;
  border-bottom:1px solid var(--cinza-brd); font-size:var(--t-base);
}
.rh-bloco:last-child { border-bottom:none; }
.rh-hora { min-width:52px; font-weight:var(--p-medio); color:var(--texto-sec); }
.rh-txt { flex:1; min-width:0; }
.rh-bloco.livre { cursor:pointer; color:var(--texto-sec); }
.rh-bloco.livre:hover { background:var(--azul-clar); color:var(--azul-esc); }
.rh-bloco.ocupado { color:var(--texto-sec); font-style:italic; }
.rh-bloco.meu { background:var(--cinza-bg); }
.rh-tops { margin:4px 0 0 16px; font-size:var(--t-sm); color:var(--texto-sec); }

/* ⛔ ABAIXO DE 760px A GRELHA DA SALA NAO TINHA TRATAMENTO NENHUM: as colunas ficavam
   com ~50px e ilegiveis. O `.cal-cel` do calendario ja o tinha; foi esquecimento meu.
   Aqui o eixo das horas encolhe e o texto passa a caber em tres linhas.

   ⚠️ E ESTA MEDIA QUERY TEM DE VIR DEPOIS DAS REGRAS BASE DA SALA. Escrevi-a primeiro
   la em cima, junto a do calendario: aplicava-se, mas a regra base vinha a seguir no
   ficheiro e ganhava — as colunas ficavam nos 64px na mesma. O meu proprio teste dizia
   que estava feito, porque so procurava o texto e nao a ORDEM. Apanhado no browser a
   420px de largura, nao pelo teste. */
@media (max-width:760px) {
  .sala-cab, .sala-linha { grid-template-columns:44px repeat(var(--sala-cols,5),1fr); }
  .sala-eixo { padding:4px 2px; font-size:9px; }
  .sala-cel { min-height:52px; padding:4px 3px; -webkit-line-clamp:3; line-clamp:3; }
  .sala-grelha { --sala-alt:52px; }
  .sala-dia, .sala-eixo-cab { padding:6px 2px; font-size:var(--t-xs); }
}

/* ═══ SUPORTE (Apoio > Suporte) ═══════════════════════════════════════════════
   Reutiliza as classes da casa em tudo o que já existe: .table-card, .table-header,
   .table-search, thead/tbody, .form-row/.form-group, .cal-ops/.cal-op (o seletor do
   tópico), .form-ajuda, .cal-erro-linha, .cal-vazio/.cal-erro, .btn/.btn-outline.
   ⛔ Só vive aqui o que NÃO existia: a faixa de contexto do ticket e a conversa.
   Inventar aspecto novo para o resto seria o "design de IA" que o dono recusou. */

/* A faixa Departamento · Tópico · Estado · Onde · De · Registado, no topo da ficha.
   Grelha que se adapta: cabem 3 num ecrã largo e 1 no telemóvel, sem media query. */
.sup-meta {
  display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:10px 16px;
  padding:14px 16px; margin-bottom:16px;
  background:var(--cinza-bg); border:1px solid var(--cinza-brd); border-radius:var(--r-md);
}
.sup-meta > div { display:flex; flex-direction:column; align-items:flex-start; gap:3px; min-width:0; }
/* ⛔ `> div > span:first-child`, e NÃO `.sup-meta span`. O rótulo do campo é maiúsculas,
   mas o valor do Estado é uma PASTILHA, que também é um <span> — com o seletor largo,
   ela saía "EM RESOLUÇÃO" em maiúsculas e com o espaçamento de rótulo. Visto no
   browser antes de publicar. */
.sup-meta > div > span:first-child {
  font-size:var(--t-xs); font-weight:var(--p-forte); color:var(--texto-sec);
  text-transform:uppercase; letter-spacing:.5px;
}
.sup-meta b { font-size:var(--t-base); font-weight:var(--p-medio); color:var(--texto); overflow-wrap:anywhere; }

/* O texto do pedido. `pre-wrap` porque as pessoas escrevem em parágrafos e passos —
   sem isto, um relato de "faço A, depois B" vinha tudo colado numa linha só. */
.sup-desc {
  white-space:pre-wrap; overflow-wrap:anywhere;
  font-size:var(--t-base); line-height:1.55; color:var(--texto); margin-bottom:18px;
}

.sup-conversa { display:flex; flex-direction:column; gap:10px; margin-bottom:18px; }
.sup-sem-msg { font-size:var(--t-sm); color:var(--texto-sec); font-style:italic; }

/* Cada mensagem. Quem PEDIU fica com a barra neutra; quem RESPONDE (o outro lado) fica
   com a barra azul — assim vê-se de relance quem disse o quê, sem cores a mais. */
.sup-msg {
  border-left:3px solid var(--cinza-brd); border-radius:0 var(--r-sm) var(--r-sm) 0;
  background:var(--cinza-bg); padding:10px 14px;
}
.sup-msg-resp { border-left-color:var(--azul-med); }
.sup-msg-topo {
  display:flex; justify-content:space-between; gap:12px; align-items:baseline;
  font-size:var(--t-xs); color:var(--texto-sec); margin-bottom:5px;
}
.sup-msg-topo b { color:var(--texto); font-weight:var(--p-forte); }
.sup-msg-texto {
  white-space:pre-wrap; overflow-wrap:anywhere;
  font-size:var(--t-base); line-height:1.5; color:var(--texto);
}

/* A ficha é mais larga do que o modal padrão (560px): leva a conversa inteira, e a
   560px as mensagens ficavam com quatro palavras por linha. Continua com o
   `max-height:90vh` e o scroll do `.modal`, por isso não sai do ecrã.
   ⚠️ Escrito como `.modal.sup-ficha` de propósito: a regra da casa proíbe `max-width`
   em contentores de PÁGINA, e permite-o em modais. Assim o seletor diz por si que é um
   modal, e quem auditar o CSS não tem de ir ao HTML confirmar. */
.modal.sup-ficha { max-width:720px; }

/* A barra de filtros do Suporte: os mesmos .btn da casa, só com o espaçamento. */
#sup-filtros { display:flex; gap:6px; flex-wrap:wrap; align-items:center; margin-bottom:14px; }

/* ⛔ A LARGURA DAS COLUNAS. Sem isto, o navegador reparte o espaço pelo conteúdo e o
   ASSUNTO — a coluna que interessa ler — ficava espremido em cinco linhas enquanto as
   datas, que são todas do mesmo tamanho, sobravam de largura. Visto no browser antes
   de publicar; não é teórico.
   O `min-width` na tabela garante o scroll horizontal DENTRO do cartão (a regra da
   casa) em vez de encolher a página.
   ⚠️ As três últimas colunas levam CLASSE e não `nth-child`: a coluna "De" só aparece
   a quem resolve, por isso as posições mudam conforme quem está a ver — e um seletor
   por posição acertaria numa coluna diferente para cada pessoa.
   ⛔ E AS LARGURAS TÊM DE CABER O CABEÇALHO. O `thead th` da casa é `nowrap` e
   MAIÚSCULAS: "ÚLTIMA ALTERAÇÃO" precisa de 150px e tinha 104, por isso empurrava a
   tabela para fora e aparecia cortada com uma barra de scroll — mesmo com a lista
   VAZIA. Medido no browser, coluna a coluna. O rótulo passou a "Alterado" (93px) e
   cada largura tem folga sobre o que o seu cabeçalho precisa. */
.sup-tabela { min-width:900px; table-layout:fixed; }
.sup-tabela th:nth-child(1) { width:116px; }   /* Número   — precisa 82  */
.sup-tabela th:nth-child(2) { width:auto;  }   /* Assunto  — leva todo o resto */
.sup-tabela th:nth-child(3) { width:130px; }   /* Tópico   — rótulo CURTO ("Esclarecimento",
                                                  121px). O nome por extenso precisava de
                                                  185 e roubava-o ao Assunto. */
.sup-tabela th:nth-child(4) { width:130px; }   /* Estado   — cabeçalho 77, a pastilha
                                                  "Em resolução" é que manda */
.sup-tabela th:nth-child(5) { width:64px;  }   /* Msg.     — precisa 60 */
.sup-tabela th.sup-col-de   { width:120px; }   /* De       — cabeçalho 45, nomes */
.sup-tabela th.sup-col-data { width:128px; }   /* cabeçalho 99, mas o CONTEÚDO
                                                  ("04/09/26 06:33") precisa de 125 —
                                                  é o conteúdo que manda, não o rótulo */
/* O assunto é a única coluna que pode partir em várias linhas — é texto de pessoas. */
.sup-tabela td:nth-child(2) { white-space:normal; overflow-wrap:anywhere; }

/* A pastilha de estado do Suporte. A cor vem de `--sup-cor`, posta no elemento pelo JS
   (`supPastilha`), para o tema escuro poder ajustá-la — ver a razão medida abaixo. */
.sup-pastilha {
  display:inline-flex; align-items:center; gap:6px; white-space:nowrap;
  padding:4px 10px; border-radius:var(--r-pill);
  font-size:var(--t-sm); font-weight:var(--p-forte);
  /* ⛔ O TEXTO É A COR ESCURECIDA, não a cor cheia. Medido: o laranja `#F39C12` em cima
     do fundo claro da faixa dava 2.03:1 — ilegível (o mínimo é 4.5:1). É o mesmo
     princípio das pastilhas que a casa já tem: `.badge-alta` é fundo `#FFF3CD` com
     texto `#8A5A00`, nunca o âmbar cheio. */
  color:color-mix(in srgb, var(--sup-cor) 62%, #000000);
  background:color-mix(in srgb, var(--sup-cor) 14%, transparent);
  border:1px solid color-mix(in srgb, var(--sup-cor) 32%, transparent);
}
.sup-ponto {
  width:8px; height:8px; border-radius:50%; flex:0 0 auto;
  background:var(--sup-cor);
}
/* ⛔ MEDIDO no browser a 2026-09-04, não deduzido: com a cor cheia sobre o fundo do
   tema escuro (#10161f) o contraste era 3.32:1 — abaixo do mínimo legível de 4.5:1, e
   a pastilha ficava quase invisível. Clareia-se a cor do texto e reforça-se o fundo.
   ⚠️ As Assistências têm o mesmo padrão e o mesmo problema (`atStatusBadge` concatena
   `${cor}1A` à mão). Não se mexeu nelas nesta entrega — fica escrito para se saber que
   a dívida é conhecida, não despercebida. */
[data-theme="dark"] .sup-pastilha {
  color:color-mix(in srgb, var(--sup-cor) 55%, #FFFFFF);
  background:color-mix(in srgb, var(--sup-cor) 26%, transparent);
  border-color:color-mix(in srgb, var(--sup-cor) 48%, transparent);
}
[data-theme="dark"] .sup-ponto { background:color-mix(in srgb, var(--sup-cor) 55%, #FFFFFF); }

/* ── Novo pedido: os cartões de escolha do tipo ──────────────────────────────
   ⛔ A PRIMEIRA VERSÃO ERAM TRÊS PASTILHAS `.cal-op` IGUAIS, e o dono disse-o por
   palavras dele: "muito básico e simples... é sempre a mesma coisa e enjoa". O
   problema não era decoração — a escolha do tipo é a decisão que MUDA o resto do
   formulário, e estava a ser mostrada como o item menos importante do ecrã.
   Cada cartão diz por uma linha quando se usa, e leva o ícone do sprite da casa.
   ⚠️ Continuam a ser `<button>` dentro de um `.form-group`, com o mesmo raio e a
   mesma espessura de borda dos campos — a regra é não INVENTAR um vocabulário
   visual novo, não é ficar preso a três botões cinzentos. */
.sup-tipos { display:grid; grid-template-columns:repeat(3,1fr); gap:8px; }
.sup-tipo {
  display:flex; flex-direction:column; align-items:flex-start; gap:2px;
  padding:12px 14px; text-align:left; cursor:pointer;
  border:1.5px solid var(--cinza-brd); border-radius:var(--r-md);
  background:var(--branco); color:var(--texto-sec);
  font-family:inherit; transition:border-color .13s, background .13s, color .13s;
}
.sup-tipo:hover { border-color:var(--azul-med); }
.sup-tipo .ico { margin-bottom:4px; }
.sup-tipo-nome { font-size:var(--t-base); font-weight:var(--p-forte); color:var(--texto); }
.sup-tipo-desc { font-size:var(--t-xs); line-height:1.35; color:var(--texto-sec); }
/* O escolhido: o mesmo azul-claro que o `.cal-op.ativo` da casa usa para "seleccionado". */
.sup-tipo.ativo {
  border-color:var(--azul-med); background:var(--azul-clar); color:var(--azul-esc);
}
.sup-tipo.ativo .sup-tipo-nome, .sup-tipo.ativo .sup-tipo-desc { color:var(--azul-esc); }

/* ⛔ NO TEMA ESCURO O CARTÃO ESCOLHIDO PRECISA DE TEXTO CLARO.
   No escuro o `--azul-clar` passa a ser um azul ESCURO (#1e3a5c) e o `--azul-esc` fica
   ainda mais escuro (#0f2135) — texto escuro sobre fundo escuro. Só afecta o cartão
   ESCOLHIDO; os outros dois estão a 13.4:1 e 5.98:1 sem precisarem de nada.

   ⚠️ NOTA DE MÉTODO, porque me enganei duas vezes a medir isto:
   1. Li o ecrã e concluí que o problema eram os cartões NÃO escolhidos. Era o
      contrário — a medição desmentiu o olho.
   2. A medição seguinte deu 1.41:1 e era INVÁLIDA: estava a medir uma janela criada
      enquanto o tema era claro, e que não acompanhou a mudança de tema. Só medindo
      com a janela ABERTA DE NOVO depois de trocar o tema é que os números valem.
   Os números bons, com janela nova em cada tema: claro 8.76 / 14.63 / 5.53;
   escuro 9.84 / 13.42 / 5.98, e o descritivo do escolhido subiu de 4.38 para acima
   de 5 com a cor clareada abaixo (4.38 passava à vista, mas está debaixo do mínimo
   de 4.5 e este ecrã é para toda a gente). */
[data-theme="dark"] .sup-tipo.ativo { color:var(--texto); }
[data-theme="dark"] .sup-tipo.ativo .sup-tipo-nome { color:var(--texto); }
[data-theme="dark"] .sup-tipo.ativo .sup-tipo-desc {
  color:color-mix(in srgb, var(--texto) 55%, var(--texto-sec));
}

/* O MESMO DEFEITO, na classe generica desta vez. O `.cal-op.ativo` e
   `--azul-esc` sobre `--azul-clar`; no tema escuro as duas variaveis viram tons
   escuros (#0f2135 sobre #1e3a5c) e o rotulo escolhido desaparece.
   MEDIDO, nao deduzido: 1.41:1 — o minimo legivel e 4.5:1. Com `--texto`
   (#E8EDF4) passa a 9.8:1.
   ⚠️ Isto vale para TODOS os `.cal-op`, e sao tres sitios: o calendario
   (calendario.js), a sala de reunioes (sala.js) e agora os tres niveis do editor de
   Privilegios (adm.js). Nenhuma outra regra poe `color` no `.cal-op.ativo`, por isso
   esta ganha em todos por igual.
   ⚠️ MEDIR com a vista REABERTA depois de trocar o tema: medir uma janela criada no
   tema anterior da um valor invalido (enganei-me assim duas vezes numa semana).
   MEDIDO no editor de Privilegios: 9.84:1 no escuro, 8.76:1 no claro. Os ecras do
   calendario NAO foram medidos ao vivo (precisam de dados do servidor) — a prova de
   que estao bem e a regra ser a mesma e nao haver concorrente. */
[data-theme="dark"] .cal-op.ativo { color: var(--texto); }

/* A COR VOLTA A TER SIGNIFICADO no editor de Privilegios.
   O ecra ate 2026-09-04 pintava os tres botoes com cores proprias — cinzento=nada,
   azul=ler, verde=escrever — e isso deixava VARRER a coluna sem ler rotulo a rotulo.
   Ao passar tudo para o `.cal-op` generico, o escolhido ficou sempre do mesmo
   azul-claro e essa leitura perdeu-se. O dono viu-o: "organizaste e removeste coisas".
   ⚠️ MAS AS CORES ANTIGAS ERAM ILEGIVEIS — medido contra o branco que tinham por cima:
   #95a5a6 = 2.56:1 · #5BA8F5 = 2.50:1 · #27AE60 = 2.88:1, quando o minimo e 4.5.
   Por isso a cor volta como FUNDO CLARO com texto escuro da mesma familia, que e o
   padrao das `.badge` da casa e passa nos dois temas. */
.cal-op.ativo.nivel-nada     { background:var(--cinza-bg);  color:var(--texto);      border-color:var(--cinza-brd); }
.cal-op.ativo.nivel-ler      { background:#D6E4F0;          color:#14395E;           border-color:#9DBFDD; }
.cal-op.ativo.nivel-escrever { background:#D4EDDA;          color:#14532A;           border-color:#A5D6B7; }
/* No tema escuro os hex acima ficariam claros de mais: inverte-se para fundo escuro com
   texto claro, mantendo a MESMA familia de cor para o significado nao se perder. */
[data-theme="dark"] .cal-op.ativo.nivel-nada     { background:#232c3a; color:var(--texto);  border-color:var(--cinza-brd); }
[data-theme="dark"] .cal-op.ativo.nivel-ler      { background:#1e3a5c; color:#CFE2F5;       border-color:#356394; }
[data-theme="dark"] .cal-op.ativo.nivel-escrever { background:#173f28; color:#CDEBD6;       border-color:#2F6B45; }

/* Num ecrã estreito três cartões lado a lado ficam com duas palavras por linha. */
@media (max-width:620px) { .sup-tipos { grid-template-columns:1fr; } }

/* A janela do novo pedido é um pouco mais larga que o modal padrão (560px) — leva os
   três cartões lado a lado e a linha de dois campos sem apertar. */
.modal.sup-novo { max-width:680px; }

/* A nota do rodapé fica à esquerda, e empurra os botões para a direita. */
.sup-rodape-nota { margin-right:auto; font-size:var(--t-xs); color:var(--texto-sec); }

/* ══════════════════════════════════════════════════════════════════════════════
   PRIVILÉGIOS (2026-09-07)

   ⛔ PORQUE É QUE ESTE BLOCO EXISTE. O dono, à terceira entrega neste ecrã:
   "está bue feio e nada bonito … assim não está intuitivo nem bonito".
   As entregas anteriores mexeram no CONTEÚDO das células (glifos → palavras,
   máximo → mistura). A forma nunca foi tocada, e era ela o problema. Medido:

       Privilégios (renderPrivilegios)   185 linhas   66 style="…"   21 class="…"
       Suporte     (apoio.js inteiro)    730 linhas   11 style="…"   57 class="…"

   Quinze vezes mais desenho escrito à mão. E o que era escrito JÁ EXISTIA aqui:
   o `thead th` (azul escuro, maiúsculas) era anulado por `<th style="font-size:
   10.5px">`; o `tbody td` (com `tabular-nums`, que alinha os números) era anulado;
   a borda de `tbody tr` era redeclarada 5 vezes; a `.cal-conv-lista` foi copiada à
   mão duas vezes e a `.table-header` quatro. E 13 dos 30 tamanhos de letra estavam
   FORA da escala oficial — 10.5, 11.5, 12.5 e 10px — contra a regra escrita lá em
   cima ("usa estas e mais nenhuma").

   ⚠️ E havia um efeito que não se vê a olho: um `padding`/`font-size` inline tem
   mais peso que o `@media` da linha 513, por isso a tabela NÃO encolhia em ecrã
   pequeno. Foi a queixa anterior do dono ("está tudo cortado").

   Reutiliza da casa, sem redesenhar: `.table-card`, `.table-header`,
   `.table-search`, `thead th`/`tbody td`/`tbody tr`, `.badge*`, `.avatar`,
   `.btn*`, `.cal-ops`/`.cal-op` (com as variantes `.nivel-*`), `.cal-conv-lista`/
   `.cal-conv-linha`/`.cal-conv-avatar`, `.form-row`/`.form-group`, `.empty-row`,
   `.ico`. Só vive aqui o que NÃO existia.
   ══════════════════════════════════════════════════════════════════════════════ */

/* A grelha é larga por natureza (uma coluna por módulo) e rola DENTRO do cartão —
   regra da casa: a página nunca rola de lado. `fixed` para as colunas não dançarem
   conforme o conteúdo de cada linha. */
/* ⛔ AS COLUNAS ESTICAVAM PARA ENCHER O ECRA, e era isso o "desconfigurado" que o dono
   viu. Com `table-layout:fixed`, quando a soma das larguras declaradas e MENOR do que a
   largura da tabela, o browser distribui a folga por TODAS, proporcionalmente. Medido
   num ecra de 1900px: declarei 230px para o Alvo e 86px por modulo (832px ao todo), a
   tabela ficou com 1592px, e o browser esticou o Alvo para 440 e cada modulo para 165 —
   quase o DOBRO. Uma coluna feita para caber "Le" com 165px de largura.
   A casa ja tinha a solucao e eu nao a segui: o `.sup-tabela` da `width:auto` a UMA
   coluna ("Assunto — leva todo o resto") e essa absorve a folga sozinha.
   Aqui a folga vai para uma coluna VAZIA no fim: assim nem o nome nem os modulos
   esticam, e a tabela fica um bloco compacto em vez de sete colunas de ar. */
.priv-tabela { table-layout:fixed; min-width:820px; }
.priv-tabela th:first-child, .priv-tabela td:first-child { width:250px; }
.priv-tabela th.priv-col-mod, .priv-tabela td.priv-col-mod { width:104px; }
.priv-tabela th.priv-col-folga, .priv-tabela td.priv-col-folga { width:auto; }
/* A folga nao e uma coluna — e o espaco que sobra. Por isso nao leva o fundo azul do
   `thead th` nem a borda das celulas: a barra do cabecalho acaba onde os dados acabam,
   em vez de se esticar por cima do vazio a parecer uma coluna por preencher. */
.priv-tabela th.priv-col-folga { background:var(--branco); border:none; }
[data-theme="dark"] .priv-tabela th.priv-col-folga { background:var(--branco); }
/* ⛔ A COLUNA DO NOME FICA FIXA. Numa grelha de 11 colunas, rolar para ver os
   módulos da direita fazia desaparecer o nome — e deixava de se saber de quem era
   a linha. É o erro clássico das grelhas densas, e a nossa tinha-o. */
.priv-tabela th:first-child, .priv-tabela td:first-child {
  position:sticky; left:0; z-index:1;
}
.priv-tabela td:first-child { background:var(--branco); }
tbody tr:hover .priv-tabela td:first-child { background:#F7FAFD; }
/* ⛔ ESTAS COLUNAS ESTAVAM AO CENTRO, E ERA ISSO O "SOLTO".
   Do levantamento a Carbon (IBM), Ant, Primer (GitHub), Polaris (Shopify), Fluent
   (Microsoft), Material e Linear: centrado praticamente ninguem usa, so para icones e
   caixas de seleccao. E a razao e mecanica, nao gosto:
     "Quando o texto e curto, CENTRADO, e as celulas estao maioritariamente vazias, cada
      celula comeca num x diferente e nao existe rail nenhum. Nao e falta de bordas — e
      falta de alinhamento vertical partilhado. A BORDA E A MULETA; O ALINHAMENTO E A CURA."
   O rotulo parte em duas linhas porque o `thead th` da casa e `nowrap` e os nomes dos
   modulos sao longos. */
.priv-tabela th.priv-col-mod { text-align:left; white-space:normal; }
.priv-tabela td.priv-col-mod { text-align:left; }

/* ⚠️ E A EXCEPCAO QUE SE APLICA A NOS. O mesmo levantamento diz que verticais nao se
   usam — MAS abre a excepcao da MATRIZ: "quando se le tanto para baixo numa coluna como
   para o lado numa linha, a grelha completa e recomendada; verticais leves, sim, mas
   MAIS CLARAS que as horizontais, nunca mais escuras". A nossa e uma matriz de modulos x
   pessoas. Vertical `--cinza-bg` (#F4F6F9) contra horizontal `--cinza-brd` (#DDE2EA): a
   vertical fica em segundo plano e nao vira grelha de folha de calculo. */
.priv-tabela td + td, .priv-tabela th + th { border-left:1px solid var(--cinza-bg); }
[data-theme="dark"] .priv-tabela td + td { border-left-color:#141c27; }
/* A folga nao e coluna — nao leva rail nenhum. */
.priv-tabela td.priv-col-folga, .priv-tabela th.priv-col-folga { border-left:none; }

/* ⛔ A LINHA TINHA 50px. O consenso e 40px, ou 44-48 quando ha avatar (Carbon md=40,
   Linear 40/48 com avatar, Primer normal=36). O `tbody td` da casa poe `padding:10px`,
   que com o bloco avatar+nome+email dava 50. A 8px fica em 44 — e sao 96px de altura
   recuperada em 16 linhas, com o mesmo conteudo la dentro.
   O horizontal sobe de 14 para 16px, que e o consenso quase unanime dos sete. */
.priv-tabela td { padding:8px 16px; }
.priv-tabela th { padding:9px 16px; }

/* ⛔ CELULA VAZIA ERA UM BURACO. Duas versoes atras eu pintava-a de cinzento (e 75% da
   tabela virou um bloco); depois tirei o cinzento e ficou o nada. O consenso e nenhuma
   das duas: um TRACO esbatido. A razao e de desambiguacao — em branco nao se distingue
   "nao tem acesso" de "nao carregou" — e a acessibilidade pede o mesmo. */
/* ⚠️ SEM `opacity`. Escrevi primeiro `opacity:.5` (a pesquisa sugere um traco "esbatido",
   e da o exemplo #B9BFC9). Ao medir, o valor que sai do `getComputedStyle` e a cor ANTES
   da opacidade — dava 5.53:1 e parecia passar. Com a opacidade aplicada de facto, o traco
   mistura-se com o fundo e cai para ~2.2:1, abaixo do minimo de 4.5 da casa. E o traco
   NAO e decoracao: e a resposta "esta pessoa nao tem acesso aqui". Fica na cor secundaria
   sem opacidade — subtil na mesma (e a cor dos subtitulos), e mede 5.53 a serio. */
.priv-tabela td.priv-nada::before { content:'–'; color:var(--texto-sec); }
/* ⛔ "Lê 6" e "Escreve 1" em DUAS linhas davam 51px de altura por linha da tabela —
   medido. Em vinte linhas, isso e um ecra inteiro so de espacamento vertical, e era
   metade do ar que o dono via. Passam a caber numa linha. */
.priv-cel-mistura { display:inline-flex; gap:6px; align-items:baseline; white-space:nowrap; }
.priv-cel-mistura .priv-nivel-escreve { color:var(--texto); }
/* A última coluna do efectivo ("De onde vem") é texto, não um nível. */
.priv-tabela th.priv-col-origem, .priv-tabela td.priv-col-origem {
  width:170px; text-align:left; white-space:normal;
}

/* A célula de identidade: avatar + nome + email, como o `renderUsuarios` do mesmo
   ficheiro já faz. */
.priv-pessoa { display:flex; align-items:center; gap:8px; min-width:0; }
.priv-pessoa-nome { display:flex; flex-direction:column; gap:1px; min-width:0; }
.priv-pessoa-nome strong { overflow-wrap:anywhere; }
.priv-sub { font-size:var(--t-xs); color:var(--texto-sec); overflow-wrap:anywhere; }

/* ⛔ "SEM ACESSO" ERA UMA CELULA COM FUNDO CINZENTO, E ISSO INVERTEU O ECRA.
   Pus o fundo para a ausencia se ler pelo vazio em vez de um traco. So que, medido:
   **75% das celulas de modulo estao vazias** — e com fundo, 75% da area da tabela
   passou a ser um bloco cinzento. O cinzento virou a FIGURA e as poucas palavras
   viraram o fundo. Foi o que o dono viu quando disse, outra vez, "ta igual".
   A ausencia le-se sozinha: uma celula sem nada nao precisa de ser PINTADA — mas
   precisa de um traco, ver a regra do `::before` mais abaixo. */
.priv-tabela td.priv-nada { background:transparent; }
.priv-nivel-escreve { font-weight:var(--p-forte); }
/* A contagem por baixo do nível ("6 de 9", "Escreve 1") — é o detalhe que faltava
   quando o ecrã resumia pelo MÁXIMO e dizia "escreve" a quem quase só lê. */
.priv-conta { font-size:var(--t-xs); color:var(--texto-sec); }

/* A marca das excepções: quem tem privilégios PRÓPRIOS além dos da equipa. São 3 em
   25, e eram a única coisa que distinguia as linhas — estavam escondidas. O GitHub
   faz o mesmo com o badge "Mixed roles". */
.priv-proprio { color:var(--azul-med); flex:0 0 auto; }

/* O detalhe de uma pessoa, no molde do `.sup-meta`: rótulo pequeno em maiúsculas,
   valor por baixo. Substitui linhas montadas com flex/min-width inline. */
.priv-bloco { padding:10px 16px; border-top:1px solid var(--cinza-brd); }
.priv-bloco-tit {
  font-size:var(--t-xs); font-weight:var(--p-forte); color:var(--texto-sec);
  text-transform:uppercase; letter-spacing:.5px;
}
.priv-linha { display:flex; gap:12px; align-items:baseline; padding:4px 0; flex-wrap:wrap; }
.priv-linha-nome { flex:1; min-width:140px; }
.priv-linha-det, .priv-linha-orig { font-size:var(--t-sm); color:var(--texto-sec); }
.priv-linha-orig { min-width:160px; text-align:right; }
.priv-sem-lista { color:var(--texto-sec); margin-top:4px; }

/* A árvore do editor. O chevron é ícone do sprite — a casa tirou 837 emoji e um `▾`
   escrito à mão não herda a cor do texto nem tem tamanho da escala. */
.priv-arv-mod, .priv-arv-sep {
  display:flex; align-items:center; gap:10px; padding:7px 0;
  border-bottom:1px solid var(--cinza-brd);
}
.priv-arv-sep { padding-left:26px; }
.priv-arv-abrir { display:flex; align-items:center; width:16px; flex:0 0 auto;
  color:var(--texto-sec); cursor:pointer; user-select:none; }
.priv-arv-abrir .ico { width:14px; height:14px; }
.priv-arv-nome { flex:1; font-size:var(--t-base); font-weight:var(--p-forte); cursor:pointer; }
.priv-arv-sep .priv-arv-nome { font-weight:var(--p-normal); color:var(--texto-sec); }
/* O resumo do módulo ("Misto — 6 lê, 1 escreve"): é o que o cabeçalho não dizia. */
.priv-arv-resumo { font-size:var(--t-sm); color:var(--texto-sec); text-align:right; }

/* Faixa de aviso dentro de um cartão. Usa o mesmo fundo e borda do `.table-header`,
   mas sem o `justify-content:space-between` (que empurrava o texto para longe da
   pastilha). */
.priv-faixa {
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  padding:10px 20px; border-bottom:1px solid var(--cinza-brd);
  background:var(--cinza-bg); font-size:var(--t-base);
}
.priv-nota { padding:8px 20px; border-bottom:1px solid var(--cinza-brd);
  font-size:var(--t-sm); color:var(--texto-sec); }

/* Espaçamento entre os cartões empilhados do ecrã e a caixa do detalhe. Eram
   `style="margin-bottom:16px"` repetidos, e um `overflow-x:auto` por tabela. */
.priv-cartao { margin-bottom:16px; }
.priv-rolar { overflow-x:auto; }
.priv-espaco { flex:1; }
.priv-msg { padding:16px; line-height:1.55; }
.priv-msg-txt { margin-top:8px; }
.priv-resumo-topo {
  padding:10px 20px; border-bottom:1px solid var(--cinza-brd);
  font-size:var(--t-base); line-height:1.6;
}
.priv-eq-topo {
  padding:12px 16px; border-bottom:1px solid var(--cinza-brd); font-size:var(--t-base);
}

/* ══ UTILIZADORES ═══════════════════════════════════════════════════════════
   O dono pediu o ecrã no molde do painel do OfficeGest. Tudo com as variáveis
   e a escala da casa — nada de cores nem tamanhos à mão, que foi o defeito
   medido no ecrã de Privilégios (141 estilos inline).                        */

.usr-resumo { font-size:var(--t-sm); color:var(--texto-sec); margin-top:2px; }

.usr-filtros { display:flex; gap:6px; padding:10px 20px; border-bottom:1px solid var(--cinza-brd); }
.usr-filtro {
  font-size:var(--t-sm); padding:5px 14px; border-radius:999px; cursor:pointer;
  background:var(--branco); border:1px solid var(--cinza-brd); color:var(--texto-sec);
}
.usr-filtro:hover { background:var(--cinza-bg); }
.usr-filtro.ativo { background:var(--azul-med); border-color:var(--azul-med); color:var(--branco); }

.usr-pessoa { display:flex; align-items:center; gap:8px; }
.usr-email  { font-size:var(--t-xs); color:var(--texto-sec); }
.usr-eu     { font-size:var(--t-xs); color:var(--azul-med); }

/* Nome INTEIRO da equipa, não a sigla — duas equipas davam a mesma sigla. */
.chip-equipa {
  display:inline-block; font-size:var(--t-xs); padding:2px 8px; border-radius:4px;
  background:var(--cinza-bg); border:1px solid var(--cinza-brd); color:var(--texto);
  margin-right:4px; margin-bottom:2px;
}

/* Ponto colorido + palavra. O ponto sozinho não serve a quem não distingue cores. */
.estado-ponto { font-size:var(--t-base); }
.estado-ponto::before {
  content:'●'; margin-right:6px; font-size:10px; vertical-align:middle;
}
.estado-ativo::before    { color:var(--verde); }
.estado-suspenso         { color:var(--vermelho-txt); }
/* Os dois estados que entraram a 2026-09-09. ⚠️ A cor nunca vai sozinha — o rótulo
   diz o mesmo que a cor, e o `title` explica porquê. */
.estado-pendente         { color:var(--amarelo-txt); }
.estado-pendente::before { color:var(--amarelo); }
.estado-inativo          { color:var(--texto-sec); }
.estado-inativo::before  { color:var(--texto-sec); }

.estado-suspenso::before { color:var(--vermelho); }

.usr-acesso       { font-size:var(--t-base); color:var(--texto); }
.usr-acesso-vazio { font-size:var(--t-sm);   color:var(--texto-sec); }
/* ⚠️ "não consegui ler" NUNCA pode parecer "não há" — daí a cor de erro. */
.usr-acesso-erro  { font-size:var(--t-sm);   color:var(--vermelho-txt); }

/* ⛔ AS QUATRO VARIAVEIS DE TEXTO ABAIXO SO TEM DOIS ESTADOS: `:root` (claro) e
   `[data-theme="dark"]` (escuro) — E NENHUM `@media (prefers-color-scheme)`.
   O Offy so fica escuro pelo botao: `toggleTheme()` (base/app.js) poe `data-theme="dark"`
   ou TIRA o atributo, e o resto da app nao olha para o sistema. Ate 10/09 estas quatro
   tinham tambem o molde das paginas que SEGUEM o sistema
   (`@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) {...} }`) —
   posto por mim a 09/09 (v2.17). Com o Offy claro o atributo nao existe, por isso esse
   seletor apanhava SEMPRE num computador com o sistema em modo escuro: texto claro sobre
   fundo branco. Medido no browser: o "Gerir" a 2.53:1; e o ensaio passou a mostrar 7
   textos reprovados nesse caso, incluindo o AVISO amarelo (2.19:1). Nao se viu antes
   porque o ensaio so lia `:root` e `[data-theme="dark"]`.
   ⛔ Nao voltar a por `prefers-color-scheme` aqui sem a app inteira passar a segui-lo. */

/* ⛔ O `--vermelho` da casa (#E74C3C) NAO passa em TEXTO em tema nenhum — medido no
   browser: 3.82:1 no claro e 4.13:1 no escuro, quando o minimo legivel e 4.5:1.
   Serve para fundos e pontos, nao para letras. Esta variavel e so para TEXTO, e muda
   com o tema. Nao se toca no `--vermelho`: outros sitios usam-no como fundo, e mexer
   nele espalhava-se pela app inteira. */
:root { --vermelho-txt: #B42318; }                                  /* 6.57:1 no branco */
[data-theme="dark"] { --vermelho-txt: #F1705F; }                    /* 5.43:1 no escuro */

/* ⛔ E o `--azul-med` (#2E6DA4) tem exactamente a mesma doenca, do outro lado: e uma
   cor pensada para fundo BRANCO e NAO e redefinida no bloco escuro. Em texto da 5.47:1
   no claro e **2.89:1** no escuro — azul-escuro sobre azul-escuro. Apanhado a medir os
   contrastes no browser antes de publicar a v2.17.0, no botao "Gerir" dos cartoes de
   Equipas; a reler o CSS nao se via nada, porque a regra esta certa e a variavel e que
   nao acompanha o tema. Nao se toca no `--azul-med`: serve de fundo e de borda em
   dezenas de sitios. */
:root { --azul-txt: #2E6DA4; }                                      /* 5.47:1 no branco */
[data-theme="dark"] { --azul-txt: #6FA8DC; }                        /* 6.25:1 no escuro */

/* ⛔ E o `--amarelo` (#F39C12) falha do lado CONTRARIO: 7.20:1 no escuro, mas **2.19:1
   no claro** — e e o texto de AVISO, o que mais precisa de ser lido. Apanhado pelo
   mesmo ensaio, na fusao de 09/09 com a ficha do utilizador em seccoes. O escuro fica
   exactamente como estava; so o claro escurece o ambar o suficiente para se ler.
   Nao se toca no `--amarelo`: e fundo de pastilhas e pontos noutros sitios. */
:root { --amarelo-txt: #8A5A00; }                                   /* 5.93:1 no branco */
[data-theme="dark"] { --amarelo-txt: #F39C12; }                     /* 7.20:1 no escuro */

/* ⚠️ E há um terceiro caso, que só apareceu ao MEDIR o menu lateral novo: o
   `--azul-txt` é para texto sobre fundo NEUTRO. Sobre o azul-claro do item
   seleccionado (`--azul-clar`) o contraste cai para **4.22:1** no claro e 4.58:1 no
   escuro — um reprovado e o outro à tangente. Texto sobre fundo TINGIDO precisa de
   ser mais escuro (ou mais claro) do que sobre fundo neutro; é a mesma família de
   erro das outras duas, um degrau abaixo. */
:root { --azul-txt-forte: #245a8a; }                                /* 5.58:1 no --azul-clar */
[data-theme="dark"] { --azul-txt-forte: #8AB8E8; }                  /* 5.57:1 no --azul-clar escuro */

.btn-reativar  { background:var(--branco); border:1px solid #A5D6B7; color:#1F7A46; }
.btn-suspender { background:var(--branco); border:1px solid var(--cinza-brd); color:var(--texto-sec); }

[data-theme="dark"] .chip-equipa { background:transparent; }

/* ══ EQUIPAS EM CARTÕES ═════════════════════════════════════════════════════
   Era uma tabela de cinco colunas; o dono pediu cartões. Grelha que se adapta
   sozinha — nada de larguras fixas, que é a regra da casa.                    */

.eq-cartoes {
  display:grid; gap:16px; padding:0;
  grid-template-columns:repeat(auto-fill, minmax(232px, 1fr));
}
/* A linha de resumo e pesquisa, agora que os cartoes nao vivem dentro de um cartao. */
.eq-barra {
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  flex-wrap:wrap; margin-bottom:14px;
}
.eq-vazio { padding:24px 20px; color:var(--texto-sec); font-size:var(--t-base); }

.eq-cartao {
  background:var(--branco); border:1px solid var(--cinza-brd); border-radius:8px;
  padding:14px 16px; display:flex; flex-direction:column; gap:10px;
}
.eq-cartao-topo { display:flex; align-items:flex-start; justify-content:space-between; gap:8px; }
.eq-cartao-topo h4 { margin:0; font-size:var(--t-md); color:var(--titulo); }
.eq-conta { font-size:var(--t-md); color:var(--texto-sec); }

.eq-resp { font-size:var(--t-sm); color:var(--texto-sec); }
/* "por definir" é a verdade enquanto ninguém preencher — um traço não diz nada. */
.eq-por-definir { color:var(--texto-sec); font-style:italic; }

.eq-pill-mais { opacity:1; }

.eq-cartao-fundo {
  display:flex; align-items:center; justify-content:space-between; gap:8px;
  border-top:1px solid var(--cinza-brd); padding-top:10px; margin-top:2px;
}
.eq-papel { font-size:var(--t-sm); color:var(--texto-sec); }
/* Botão a sério, não um link com onclick: funciona com teclado e leitor de ecrã. */
.eq-gerir {
  background:none; border:none; padding:0; cursor:pointer;
  font-size:var(--t-base); color:var(--azul-txt);
}
.eq-gerir:hover { text-decoration:underline; }

[data-theme="dark"] .eq-cartao { background:transparent; }

/* ══ GRUPOS DE PRIVILÉGIOS — como o OfficeGest (2026-09-10) ═════════════════════
   O que se vê primeiro é a MATRIZ DE PERMISSÕES da maqueta do dono (11/09); clicar
   num grupo abre o detalhe com as quatro caixas. A lista de grupos à esquerda de 10/09
   saiu: as colunas da matriz são a lista. O cabeçalho é o azul-escuro da casa. */

.grupos-layout { display:flex; gap:20px; align-items:flex-start; }
.grupos-layout > .table-card { flex:1; min-width:0; }

/* ── A matriz: módulos × grupos, UMA palavra por célula (a maqueta do dono) ──────── */
.pm-wrap { overflow-x:auto; }
.pm-matriz { width:100%; border-collapse:separate; border-spacing:0; }
.pm-matriz td { padding:12px 14px; border-bottom:1px solid var(--cinza-brd); vertical-align:middle; }
/* A coluna dos módulos fica PARADA ao rolar para o lado, com fundo opaco. */
.pm-perm, .pm-mod {
  position:sticky; left:0; z-index:1; background:var(--branco);
  min-width:220px; width:260px; text-align:left;
}
thead .pm-perm { z-index:2; background:var(--azul-esc); }
.pm-mod-nome { font-size:var(--t-base); font-weight:var(--p-forte); color:var(--texto); }
.pm-mod-desc { margin-top:3px; font-size:var(--t-sm); color:var(--texto-sec); line-height:1.4; }
/* `width` e `min-width` iguais: sem os dois as colunas esticavam para encher o ecrã. */
.pm-col { width:150px; min-width:150px; text-align:center; vertical-align:bottom; }
.pm-col-btn {
  display:flex; flex-direction:column; align-items:center; gap:2px; width:100%;
  background:none; border:none; padding:0; cursor:pointer; font-family:inherit; color:#fff;
}
.pm-col-btn:hover .pm-col-nome { text-decoration:underline; }
.pm-col-btn:focus-visible { outline:2px solid #fff; outline-offset:2px; }
.pm-col-nome { display:block; font-size:11px; font-weight:600; letter-spacing:.6px; text-transform:uppercase; color:#fff; }
.pm-col-sub { display:block; font-size:10px; font-weight:400; letter-spacing:0; text-transform:none; color:#C9D6E3; }
.pm-cel { text-align:center; }
.pm-faixa td {
  position:sticky; left:0;
  background:var(--cinza-bg); color:var(--texto-sec);
  font-size:var(--t-xs); font-weight:var(--p-forte);
  text-transform:uppercase; letter-spacing:.6px; padding:9px 14px;
}
/* O botão de cada célula: largo e igual em todas, como na maqueta. As quatro cores
   passam 4.5:1 nos dois temas (há ensaio: administracao-contraste-nos-dois-temas). */
.pm-chip {
  display:inline-block; min-width:118px; padding:9px 14px; border-radius:8px;
  border:1px solid var(--cinza-brd); background:var(--branco); color:var(--texto-sec);
  font-family:inherit; font-size:var(--t-base); font-weight:var(--p-forte); line-height:1.2;
  text-align:center; cursor:pointer; white-space:nowrap;
}
button.pm-chip:hover { border-color:var(--azul-txt); }
button.pm-chip:focus-visible { outline:2px solid var(--azul-txt); outline-offset:2px; }
.pm-chip.fixo { cursor:default; }
.pm-chip.nenhum  { background:var(--branco);   color:var(--texto-sec); }
.pm-chip.ver     { background:var(--cinza-bg); color:var(--texto); }
.pm-chip.criar   { background:var(--branco);   color:var(--azul-txt); border-color:var(--azul-txt); }
.pm-chip.total   { background:var(--azul-clar); color:var(--azul-txt-forte); border-color:var(--azul-clar); }
.pm-chip.parcial { background:var(--branco);   color:var(--texto); border-style:dashed; }
.pm-chip.outro   { background:var(--branco);   color:var(--texto); border-style:dashed; }
/* A faixa por cima da matriz: quem ainda está no acesso antigo, e o botão para passar. */
.pm-aviso {
  display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap;
  margin:0 0 12px; padding:12px 14px; border:1px solid var(--cinza-brd); border-radius:8px;
  background:var(--cinza-bg); color:var(--texto); font-size:var(--t-base);
}
.pm-aviso-ok { background:var(--branco); }
/* ⚠️ O `.btn` da casa tem `display` próprio e ganha ao atributo `hidden` — sem isto o
   "← Matriz" aparecia na própria matriz. Visto no browser a 11/09. */
#grupos-voltar-btn[hidden] { display:none; }
/* A barra do detalhe de um grupo (Mudar nome · Apagar grupo). */
.grp-barra { display:flex; gap:8px; justify-content:flex-end; padding:0 0 10px; }

/* A caixa de confirmação tem de respeitar as mudanças de linha: a lista dos grupos a
   passar é lida lá. Até 11/09 as quebras colapsavam — as mensagens com "\n\n" do Offy
   apareciam numa só linha corrida. */
#confirm-msg { white-space:pre-line; max-height:60vh; overflow:auto; }

.grp-tabela { width:100%; border-collapse:collapse; }
.grp-tabela td { padding:9px 12px; border-bottom:1px solid var(--cinza-brd); vertical-align:middle; }
/* As quatro colunas das caixas com largura fixa e iguais: é o que as alinha em coluna,
   como no OfficeGest — os olhos varrem a coluna "Editar" de cima a baixo. */
.grp-cx-cab { width:84px; text-align:center; }
.grp-cx { width:84px; text-align:center; }
.grp-cx input { width:18px; height:18px; cursor:pointer; accent-color:var(--azul-med); }
.grp-cx input:disabled { cursor:default; }
/* Um separador que HERDA do módulo mostra as caixas mais leves — não é excepção. */
.grp-cx.herdado input { opacity:.55; }
.grp-mod-nome { font-weight:var(--p-forte); color:var(--texto); white-space:nowrap; }
.grp-sep-nome { padding-left:44px !important; color:var(--texto-sec); }
.grp-excepcao {
  margin-left:6px; font-size:var(--t-xs); color:var(--amarelo-txt);
  border:1px solid var(--cinza-brd); border-radius:4px; padding:0 5px;
}
.grp-seta {
  background:none; border:none; cursor:pointer; padding:0; margin-right:6px;
  width:20px; height:20px; vertical-align:middle; color:var(--texto-sec);
}
.grp-seta .ico { width:14px; height:14px; }
.grp-seta-vazia { display:inline-block; width:26px; }
.grp-faixa td {
  background:var(--cinza-bg); color:var(--texto-sec);
  font-size:var(--t-xs); font-weight:var(--p-forte);
  text-transform:uppercase; letter-spacing:.6px; padding:8px 12px;
}
.grp-cmp { text-align:center; font-size:var(--t-sm); color:var(--texto); white-space:nowrap; }
.grp-parcial { font-size:var(--t-xs); color:var(--amarelo-txt); }

@media (max-width: 900px) {
  .grupos-layout { flex-direction:column; align-items:stretch; }
}

/* ══ PRIVILÉGIOS: A MATRIZ POR MÓDULO (2026-09-10, maqueta do dono) ═════════════
   Os módulos nas linhas, com descrição; os alvos nas colunas. O cabeçalho continua
   AZUL-ESCURO — decisão do dono a 07/09 e reafirmada a 09/09 ("as cores quero iguais
   às que já temos"); só a disposição veio da maqueta.                               */

.priv-matriz { border-collapse:separate; border-spacing:0; }
.priv-matriz td { padding:10px 12px; border-bottom:1px solid var(--cinza-brd); vertical-align:middle; }

/* A primeira coluna fica PARADA ao rolar para o lado: com 8+ colunas de alvos a tabela
   passa da largura do cartão, e sem isto perdia-se de vista a que módulo é cada linha.
   O fundo tem de ser opaco, senão as células que passam por baixo vêem-se através. */
.priv-mx-perm {
  position:sticky; left:0; z-index:1;
  min-width:220px; width:240px; text-align:left;
  background:var(--branco);
}
thead .priv-mx-perm { z-index:2; background:var(--azul-esc); }
.priv-mx-mod  { font-size:var(--t-base); font-weight:var(--p-forte); color:var(--texto); }
.priv-mx-desc { margin-top:2px; font-size:var(--t-xs); color:var(--texto-sec); line-height:1.4; }

/* `width` e `min-width` iguais: sem os dois a coluna esticava para encher a folga do
   ecrã — a armadilha que o 07/09 mediu (declarei 86px, ficavam 165). */
.priv-mx-col { width:132px; min-width:132px; vertical-align:bottom; white-space:normal; }
.priv-mx-alvo {
  display:flex; flex-direction:column; gap:2px; align-items:flex-start;
  width:100%; background:none; border:none; padding:0; cursor:pointer;
  font-family:inherit; text-align:left; color:#fff;
}
.priv-mx-alvo:hover .priv-mx-nome { text-decoration:underline; }
.priv-mx-alvo:focus-visible { outline:2px solid #fff; outline-offset:2px; }
.priv-mx-nome { font-size:11px; font-weight:600; letter-spacing:.6px; text-transform:uppercase; }
/* O nome das equipas dentro de um grupo: em minúsculas e mais claro, porque é lista e
   não título. Medido sobre o --azul-esc: 7.67:1 no claro e 11.02:1 no escuro. Corta a
   três linhas; a lista inteira fica no `title` do cabeçalho. */
.priv-mx-sub {
  font-size:10px; font-weight:400; letter-spacing:0; text-transform:none; color:#C9D6E3;
  display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical; overflow:hidden;
}
.priv-mx-cel { text-align:center; }
/* O traço de "sem acesso": leve, como a casa decidiu a 07/09 (o cinzento das vazias era
   75% da área), mas PRESENTE — uma célula vazia lia-se como dado em falta. */
.priv-mx-nada { color:var(--texto-sec); cursor:default; }

/* A faixa de grupo — a mesma ideia da matriz dos Papéis e da árvore do editor. */
.priv-mx-faixa td {
  position:sticky; left:0;
  background:var(--cinza-bg); color:var(--texto-sec);
  font-size:var(--t-xs); font-weight:var(--p-forte);
  text-transform:uppercase; letter-spacing:.6px; padding:8px 12px;
}

/* ══ PRIVILÉGIOS: O EDITOR EM DUAS COLUNAS ══════════════════════════════════════
   Mestre-detalhe, como nas maquetas do dono: os alvos à esquerda, o que se edita
   deles à direita. ⛔ Nada saiu do cartão — as peças mudaram de sítio. A 04/09 este
   ecrã foi "organizado" a remover coisas e não pode voltar a acontecer.            */

.priv-editor { display:flex; gap:20px; align-items:flex-start; padding:0 20px 16px; }

/* A faixa que separa os grupos na árvore — a mesma ideia da matriz dos Papéis, e
   cinzento neutro de propósito: organiza, não compete com nada. */
.priv-faixa-grupo {
  font-size:var(--t-xs); font-weight:var(--p-forte); color:var(--texto-sec);
  text-transform:uppercase; letter-spacing:.6px;
  padding:14px 2px 6px; border-bottom:1px solid var(--cinza-brd); margin-bottom:6px;
}
.priv-faixa-grupo:first-child { padding-top:2px; }

/* `flex:0 0 240px` e não `width`: sem o `0 0` a coluna encolhe quando a árvore ao lado
   fica larga, e os nomes das equipas partem-se a meio. É a mesma armadilha do menu. */
.priv-editor-alvos {
  flex:0 0 240px; align-self:stretch;
  border-right:1px solid var(--cinza-brd); padding-right:20px;
}
.priv-alvos-2 { margin-top:16px; }

/* ⛔ `min-width:0` é obrigatório: sem ele a árvore (que é larga) empurra o flex e a
   PÁGINA passa a rolar na horizontal — a regra da casa é rolar dentro do cartão. */
.priv-editor-arvore { flex:1; min-width:0; }

@media (max-width: 900px) {
  .priv-editor { flex-direction:column; gap:16px; align-items:stretch; }
  .priv-editor-alvos {
    flex:none; width:100%; align-self:auto;
    border-right:none; border-bottom:1px solid var(--cinza-brd);
    padding:0 0 16px;
  }
}

/* ══ ADMINISTRAÇÃO: MENU LATERAL E CABEÇALHO DE PÁGINA ══════════════════════════
   Eram sete botões numa tira horizontal. Passou a menu lateral por ordem do dono
   (2026-09-09), a partir das maquetas. As cores são as da casa — foi decisão dele
   manter o azul-escuro dos cabeçalhos de tabela e mudar só a disposição.            */

.adm-layout { display:flex; gap:24px; align-items:flex-start; }

/* `flex:0 0 216px` e não `width`: sem o `0 0` a barra encolhia quando a tabela ao
   lado ficava larga, e os nomes das secções partiam-se a meio. */
.adm-nav {
  flex:0 0 216px; display:flex; flex-direction:column; gap:2px;
  border-right:1px solid var(--cinza-brd); padding-right:16px; align-self:stretch;
}
.adm-nav-grupo {
  font-size:var(--t-xs); font-weight:var(--p-forte); color:var(--texto-sec);
  text-transform:uppercase; letter-spacing:.6px; padding:14px 10px 6px;
}
.adm-nav-grupo:first-child { padding-top:2px; }

/* Botão a sério, não um `div` com onclick: chega-se lá pelo teclado e um leitor de
   ecrã anuncia-o. O `aria-current` (posto no JS) é que diz qual é a página actual. */
.adm-nav-item {
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  width:100%; text-align:left; background:none; border:none; cursor:pointer;
  padding:9px 10px; border-radius:6px; font-size:var(--t-base);
  color:var(--texto); font-family:inherit;
}
.adm-nav-item:hover { background:var(--cinza-bg); }
.adm-nav-item.ativo { background:var(--azul-clar); color:var(--azul-txt-forte); font-weight:var(--p-forte); }
.adm-nav-item:focus-visible { outline:2px solid var(--azul-txt); outline-offset:1px; }
.adm-nav-conta { font-size:var(--t-sm); color:var(--texto-sec); font-weight:var(--p-normal); }
.adm-nav-item.ativo .adm-nav-conta { color:var(--azul-txt-forte); }

/* `min-width:0` é obrigatório: sem ele um filho largo (a tabela) empurra o flex e a
   página passa a ter scroll horizontal — a armadilha já registada no `#main`. */
.adm-conteudo { flex:1; min-width:0; }

.adm-cabecalho {
  display:flex; align-items:flex-start; justify-content:space-between; gap:16px;
  flex-wrap:wrap; padding-bottom:16px; margin-bottom:16px;
  border-bottom:1px solid var(--cinza-brd);
}
.adm-cabecalho-txt h2 { margin:0; font-size:22px; font-weight:700; color:var(--titulo); }
.adm-subtitulo { margin-top:4px; font-size:var(--t-base); color:var(--texto-sec); }
.adm-accoes { display:flex; gap:8px; align-items:center; flex-wrap:wrap; }

/* Em ecrã estreito a barra deita-se e rola na horizontal, em vez de comer metade da
   largura. É o mesmo limite em que a barra lateral global da app já desaparece. */
@media (max-width: 900px) {
  .adm-layout { flex-direction:column; gap:16px; align-items:stretch; }
  .adm-nav {
    flex:none; width:100%; flex-direction:row; overflow-x:auto; gap:6px;
    border-right:none; border-bottom:1px solid var(--cinza-brd);
    padding:0 0 10px;
  }
  .adm-nav-grupo { display:none; }
  .adm-nav-item { width:auto; white-space:nowrap; }
}

/* ── Selecção, menu ⋯ e rodapé dos Utilizadores ───────────────────────────── */

.usr-col-sel { width:36px; text-align:center; }
.usr-rodape  {
  padding:10px 20px; border-top:1px solid var(--cinza-brd);
  font-size:var(--t-sm); color:var(--texto-sec);
}

.usr-menu { position:relative; display:inline-block; }
.usr-menu-btn {
  background:none; border:1px solid transparent; border-radius:4px; cursor:pointer;
  font-size:var(--t-md); line-height:1; padding:2px 8px; color:var(--texto-sec);
}
.usr-menu-btn:hover { background:var(--cinza-bg); border-color:var(--cinza-brd); }
.usr-menu-lista {
  display:none; position:absolute; right:0; top:100%; z-index:20; min-width:170px;
  background:var(--branco); border:1px solid var(--cinza-brd); border-radius:6px;
  box-shadow:0 4px 14px rgba(0,0,0,.10); padding:4px;
}
.usr-menu.aberto .usr-menu-lista { display:block; }
.usr-menu-lista button {
  display:block; width:100%; text-align:left; background:none; border:none;
  padding:7px 10px; border-radius:4px; cursor:pointer;
  font-size:var(--t-base); color:var(--texto);
}
.usr-menu-lista button:hover { background:var(--cinza-bg); }
.usr-menu-bom  { color:#1F7A46 !important; }
.usr-menu-mau  { color:var(--vermelho-txt) !important; }
.usr-menu-nota { display:block; padding:7px 10px; font-size:var(--t-xs); color:var(--texto-sec); }

[data-theme="dark"] .usr-menu-lista { background:var(--cinza-bg); }

/* ══ PAPÉIS E PERMISSÕES ════════════════════════════════════════════════════
   A maqueta do dono: lista de papéis à esquerda, matriz permissão × papel à
   direita. Assenta nos perfis que já existiam e nunca tinham sido usados.     */

.papeis-layout { display:grid; grid-template-columns:260px 1fr; gap:16px; align-items:start; }
@media (max-width: 900px) { .papeis-layout { grid-template-columns:1fr; } }

.papeis-lado {
  background:var(--branco); border:1px solid var(--cinza-brd); border-radius:8px; padding:10px;
}
.papeis-lado-titulo {
  font-size:var(--t-xs); color:var(--texto-sec); text-transform:uppercase;
  letter-spacing:.6px; padding:4px 8px 8px;
}
.papel-item {
  position:relative; padding:10px 30px 10px 12px; border-radius:6px; cursor:pointer;
}
.papel-item:hover { background:var(--cinza-bg); }
.papel-item.escolhido { background:var(--azul-clar); }
.papel-nome    { font-size:var(--t-base); color:var(--titulo); font-weight:var(--p-semi, 600); }
.papel-membros { font-size:var(--t-xs); color:var(--texto-sec); }
.papel-x {
  position:absolute; right:8px; top:10px; background:none; border:none; cursor:pointer;
  color:var(--texto-sec); font-size:var(--t-md); line-height:1; padding:0 4px;
}
.papel-x:hover { color:var(--vermelho-txt); }
.papeis-novo {
  width:100%; margin-top:6px; background:none; border:none; cursor:pointer;
  padding:8px; text-align:left; font-size:var(--t-base); color:var(--azul-med);
}
.papeis-novo:hover { text-decoration:underline; }

.papeis-tabela { width:100%; }
.papeis-col { text-align:center; }
.papeis-perm     { font-size:var(--t-base); color:var(--texto); }
.papeis-perm-sub { font-size:var(--t-xs);   color:var(--texto-sec); }

/* Botão a sério, não uma célula com onclick: chega-se lá pelo teclado. */
/* A faixa que separa os grupos da matriz. Cinzento neutro de propósito: a faixa
   organiza, não compete com o cabeçalho azul-escuro da tabela. */
.papeis-faixa td {
  background:var(--cinza-bg); color:var(--texto-sec);
  font-size:var(--t-xs); font-weight:var(--p-forte);
  text-transform:uppercase; letter-spacing:.6px;
  padding:8px 12px; border-top:1px solid var(--cinza-brd);
}
.papeis-cel {
  min-width:76px; padding:5px 12px; border-radius:6px; cursor:pointer;
  font-size:var(--t-sm); border:1px solid var(--cinza-brd); background:var(--branco);
  color:var(--texto-sec);
}
.papeis-cel:hover { border-color:var(--azul-med); }
/* As três cores dizem o mesmo que a palavra — a palavra é que manda, para quem
   não distingue cores. */
.papeis-r { background:#D6E4F0; border-color:#9DBFDD; color:#14395E; }
.papeis-w { background:#D4EDDA; border-color:#A5D6B7; color:#14532A; }

[data-theme="dark"] .papeis-lado { background:transparent; }
[data-theme="dark"] .papeis-cel  { background:transparent; }
[data-theme="dark"] .papeis-r,
[data-theme="dark"] .papeis-w    { color:var(--texto); }

/* ══ NOTIFICAÇÕES ═══════════════════════════════════════════════════════════
   Duas metades, como na maqueta: os avisos à esquerda, as preferências à
   direita.                                                                   */

.notif-layout { display:grid; grid-template-columns:minmax(280px, 380px) 1fr; gap:16px; align-items:start; }
@media (max-width: 1000px) { .notif-layout { grid-template-columns:1fr; } }

.notif-avisos { max-height:520px; overflow-y:auto; }
.notif-aviso  { padding:12px 20px; border-bottom:1px solid var(--cinza-brd); }
.notif-aviso:last-child { border-bottom:none; }
.notif-aviso-topo   { display:flex; justify-content:space-between; gap:10px; align-items:baseline; }
.notif-aviso-titulo { font-size:var(--t-base); color:var(--texto); }
.notif-aviso-quando { font-size:var(--t-xs);   color:var(--texto-sec); white-space:nowrap; }
.notif-aviso-msg    { font-size:var(--t-sm);   color:var(--texto-sec); margin-top:3px; }
/* O ponto marca o que está por ler — e a palavra "por ler" está na contagem,
   para quem não distingue cores. */
.notif-aviso.por-ler .notif-aviso-titulo::before {
  content:'●'; color:var(--azul-med); font-size:9px; margin-right:7px; vertical-align:middle;
}
/* ── FORMULÁRIOS: secções, ajudas e interruptores (ficha do utilizador, 2026-09-09) ──
   Só tokens da casa, para o tema escuro herdar sem regras próprias. Substitui os <hr>
   e os style= inline que a ficha usava para separar e explicar campos. */
.form-sec { padding-top: 14px; margin-top: 6px; border-top: 1px solid var(--cinza-brd); }
.form-sec:first-of-type { padding-top: 0; margin-top: 0; border-top: 0; }
.form-sec-t { margin: 0 0 10px; font-size: var(--t-xs); font-weight: var(--p-forte); color: var(--azul-txt); text-transform: uppercase; letter-spacing: .6px; }
.form-hint { margin-top: 2px; font-size: var(--t-xs); font-weight: var(--p-normal); color: var(--texto-sec); line-height: 1.45; text-transform: none; letter-spacing: 0; }
.form-hint.aviso { color: var(--amarelo-txt); }
.form-group label.form-switch { display: flex; align-items: center; gap: 8px; padding: 6px 0 2px; font-size: var(--t-base); font-weight: var(--p-normal); color: var(--texto); text-transform: none; letter-spacing: 0; cursor: pointer; }
.form-group .form-switch input { width: auto; flex: 0 0 auto; margin: 0; accent-color: var(--azul-med); }
