/* Painel C21 — casca sidebar + topbar + componentes (cartões, tiles, chips de
   estado, tabelas, toasts). Linguagem "B espaçada à Brevo" (fase 5, frente 1,
   design v1 aprovado no Figma): sidebar CLARA com pílula ativa, fundo
   quase-branco, um só acento índigo, cartões redondos com sombra dupla suave.
   Tokens novos do Figma (ver tabela na spec). Carregado DEPOIS de base.css:
   base.css trata do reset e dos elementos nus, este ficheiro define os
   tokens (:root) e as classes específicas do painel. */

:root {
  /* ---- cor — modo claro (default) ---- */
  --fundo-pagina: #f8f9fb;
  --fundo-superficie: #ffffff;
  --fundo-superficie-2: #f3f5f9;
  --texto-principal: #191d26;
  --texto-suave: #5b6472;
  --texto-tenue: #8d95a3;
  --linha-default: #e4e8ef;
  --linha-suave: #eef1f6;
  --acento-default: #4353d9;
  --acento-suave: #e9edff;
  --acento-contraste: #ffffff;
  --sidebar-fundo: #f4f5f9;
  --sidebar-texto: #4b5364;
  --sidebar-texto-ativo: #191d26;
  --sidebar-linha: #e7eaf1;
  --estado-novo-texto: #6b7280;        --estado-novo-fundo: #eef0f3;
  --estado-contactado-texto: #2563b6;  --estado-contactado-fundo: #e6f0fb;
  --estado-1visita-texto: #6d4bc4;     --estado-1visita-fundo: #efe9fb;
  --estado-proposta-texto: #b5771a;    --estado-proposta-fundo: #fbf1de;
  /* Seguimento (fluxo novo, 2026-08-29): sépia/taupe QUENTE e DESSATURADO —
     é espera legítima (contrato a decorrer noutra agência), não alarme, e o
     limiar de «apodrecer» dele é de 30 dias por isso mesmo. Dessaturado
     distingue-o do âmbar saturado de «Com proposta», o vizinho na linha de
     cards. Contraste texto/fundo 4,65:1 (claro) e 6,65:1 (escuro), acima do
     mínimo já praticado nesta paleta. */
  --estado-seguimento-texto: #7d6551;  --estado-seguimento-fundo: #f2ece4;
  --estado-entregue-texto: #1f8f5f;    --estado-entregue-fundo: #e3f4ec;
  --estado-descartado-texto: #b0453f;  --estado-descartado-fundo: #fae9e8;
  /* Fundida (estado terminal 2026-09-01): slate-índigo neutro, deliberadamente
     LONGE do vermelho de descartado — não é rejeição, é absorção por outra
     lead. Contraste texto/fundo 4,99:1 (claro) e 6,54:1 (escuro), acima do
     mínimo já praticado nesta paleta. */
  --estado-fundida-texto: #5a6478;     --estado-fundida-fundo: #e9ebf1;
  /* Aviso neutro (higiene 2026-08-30): .mz-aviso/.tc-aviso/.vc-banner e
     companhia (tec-chip-aviso, agd-badge-aviso, ini-sub-aviso,
     ini-chip-parado, det-mercado, toast.warning) usam tokens próprios, não
     --estado-proposta-*. Os VALORES nasceram iguais aos de proposta por
     escolha estética (paleta coesa), mas já não estão acoplados. */
  --aviso-borda: #b5771a;  --aviso-fundo: #fbf1de;  --aviso-texto: #b5771a;
  /* Realce de chip (det-chip.det-chip-hl na ficha): VALORES de proposta por
     escolha de design, mas tokens próprios para desacoplar semanticamente. */
  --realce-chip-texto: #b5771a;  --realce-chip-fundo: #fbf1de;
  --semaforo-ok: #1f8f5f;
  --semaforo-perigo: #c2453f;

  /* ---- espaço e raio — fixos, iguais nos dois temas ---- */
  --espaco-xs: 4px; --espaco-sm: 8px; --espaco-md: 12px; --espaco-lg: 16px;
  --espaco-xl: 24px; --espaco-2xl: 32px; --espaco-3xl: 48px;
  --raio-sm: 8px; --raio-md: 12px; --raio-lg: 16px; --raio-pilula: 999px;

  /* ---- tipografia — stack de sistema, igual nos dois temas ---- */
  --font-ui: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --font-num: "SF Mono", "JetBrains Mono", ui-monospace, "Cascadia Code", monospace;

  /* ---- sombra de cartão — por tema (bloco escuro/claro abaixo) ---- */
  --shadow: 0 1px 2px rgba(20, 28, 43, .05), 0 4px 16px rgba(20, 28, 43, .05);

  /* ---- aliases de compatibilidade (nomes de antes da fase 5) ----
     Alguns templates com <style> próprio (transferir_carteira, mover_zona,
     agencia_form, _seletor_zona) ainda usam os nomes antigos. Cada alias
     aponta para var(--token-novo): a resolução de custom properties do CSS é
     dinâmica (feita à pintura), portanto segue o tema sozinha — não é preciso
     repor estes aliases nos blocos escuro/claro mais abaixo. */
  --ground: var(--fundo-pagina);
  --surface: var(--fundo-superficie);
  --surface-2: var(--fundo-superficie-2);
  --ink: var(--texto-principal);
  --ink-soft: var(--texto-suave);
  --ink-faint: var(--texto-tenue);
  --line: var(--linha-default);
  --line-soft: var(--linha-suave);
  --accent: var(--acento-default);
  --accent-soft: var(--acento-suave);
  --accent-ink: var(--acento-contraste);
  --sidebar-bg: var(--sidebar-fundo);
  --sidebar-ink: var(--sidebar-texto);
  --sidebar-ink-hi: var(--sidebar-texto-ativo);
  --sidebar-active: var(--acento-suave);
  --sidebar-accent: var(--acento-default);
  --sidebar-line: var(--sidebar-linha);
  --st-novo: var(--estado-novo-texto);              --st-novo-bg: var(--estado-novo-fundo);
  --st-contactado: var(--estado-contactado-texto);  --st-contactado-bg: var(--estado-contactado-fundo);
  --st-1visita: var(--estado-1visita-texto);        --st-1visita-bg: var(--estado-1visita-fundo);
  --st-proposta: var(--estado-proposta-texto);      --st-proposta-bg: var(--estado-proposta-fundo);
  --st-seguimento: var(--estado-seguimento-texto);  --st-seguimento-bg: var(--estado-seguimento-fundo);
  --st-entregue: var(--estado-entregue-texto);      --st-entregue-bg: var(--estado-entregue-fundo);
  --st-descartado: var(--estado-descartado-texto);  --st-descartado-bg: var(--estado-descartado-fundo);
  --st-fundida: var(--estado-fundida-texto);        --st-fundida-bg: var(--estado-fundida-fundo);
  --danger: var(--semaforo-perigo);
  --ok: var(--semaforo-ok);
  --radius: var(--raio-md);
  --radius-sm: var(--raio-sm);
}

@media (prefers-color-scheme: dark) {
  :root {
    --fundo-pagina: #0e131d; --fundo-superficie: #161d29; --fundo-superficie-2: #1b2330;
    --texto-principal: #e8ecf3; --texto-suave: #9aa4b4; --texto-tenue: #6b7486;
    --linha-default: #263041; --linha-suave: #1e2735;
    --acento-default: #7288ff; --acento-suave: #232d4a; --acento-contraste: #0e131d;
    --sidebar-fundo: #121826; --sidebar-texto: #9aa3b6; --sidebar-texto-ativo: #ffffff;
    --sidebar-linha: #1e2735;
    --estado-novo-texto: #9aa4b4;        --estado-novo-fundo: #242a34;
    --estado-contactado-texto: #6ba3e8;  --estado-contactado-fundo: #16283f;
    --estado-1visita-texto: #a98ce8;     --estado-1visita-fundo: #241f3a;
    --estado-proposta-texto: #d9a44f;    --estado-proposta-fundo: #33290f;
    --estado-seguimento-texto: #c3a98d;  --estado-seguimento-fundo: #2d2620;
    --estado-entregue-texto: #4fbf8f;    --estado-entregue-fundo: #123024;
    --estado-descartado-texto: #d0716c;  --estado-descartado-fundo: #331b19;
    --estado-fundida-texto: #a7afc4;     --estado-fundida-fundo: #242a38;
    --aviso-borda: #d9a44f;  --aviso-fundo: #33290f;  --aviso-texto: #d9a44f;
    --realce-chip-texto: #d9a44f;  --realce-chip-fundo: #33290f;
    --semaforo-ok: #4fbf8f;
    --semaforo-perigo: #d0716c;
    --shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 6px 20px rgba(0, 0, 0, .35);
  }
}
:root[data-theme="dark"] {
  /* Mesmo conjunto de tokens que o bloco @media acima — repetido porque o
     media query só reage à preferência do SO; isto responde ao toggle manual
     (tema.js, data-theme="dark"/"light" na raiz). */
  --fundo-pagina: #0e131d; --fundo-superficie: #161d29; --fundo-superficie-2: #1b2330;
  --texto-principal: #e8ecf3; --texto-suave: #9aa4b4; --texto-tenue: #6b7486;
  --linha-default: #263041; --linha-suave: #1e2735;
  --acento-default: #7288ff; --acento-suave: #232d4a; --acento-contraste: #0e131d;
  --sidebar-fundo: #121826; --sidebar-texto: #9aa3b6; --sidebar-texto-ativo: #ffffff;
  --sidebar-linha: #1e2735;
  --estado-novo-texto: #9aa4b4;        --estado-novo-fundo: #242a34;
  --estado-contactado-texto: #6ba3e8;  --estado-contactado-fundo: #16283f;
  --estado-1visita-texto: #a98ce8;     --estado-1visita-fundo: #241f3a;
  --estado-proposta-texto: #d9a44f;    --estado-proposta-fundo: #33290f;
  --estado-seguimento-texto: #c3a98d;  --estado-seguimento-fundo: #2d2620;
  --estado-entregue-texto: #4fbf8f;    --estado-entregue-fundo: #123024;
  --estado-descartado-texto: #d0716c;  --estado-descartado-fundo: #331b19;
  --estado-fundida-texto: #a7afc4;     --estado-fundida-fundo: #242a38;
  --aviso-borda: #d9a44f;  --aviso-fundo: #33290f;  --aviso-texto: #d9a44f;
  --realce-chip-texto: #d9a44f;  --realce-chip-fundo: #33290f;
  --semaforo-ok: #4fbf8f;
  --semaforo-perigo: #d0716c;
  --shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 6px 20px rgba(0, 0, 0, .35);
}
:root[data-theme="light"] {
  /* Repor AQUI todos os tokens que os dois blocos escuros tocam é
     load-bearing, não redundância: este bloco (especificidade 0,2,0) não está
     guardado por :not([data-theme="light"]), portanto com o SO em escuro e o
     tema forçado a claro por este atributo, um token qualquer que só fosse
     definido no @media (0,1,0, mais abaixo no ficheiro que o :root base)
     sobreviveria por não ter sido substituído aqui — ex.: o --semaforo-perigo
     escuro (#d0716c) sobre --fundo-superficie branco dá 3,35:1, PIOR que o
     ponto de partida (abaixo do 4,5:1 do WCAG AA para texto normal). O
     contrato deste bloco é repor TUDO o que os escuros tocam: os 33 tokens de
     cor + a sombra, nem um a menos. É a versão CSS da lição de 2026; a versão
     executável do contrato é painel/tests/test_tokens_css.py. */
  --fundo-pagina: #f8f9fb; --fundo-superficie: #ffffff; --fundo-superficie-2: #f3f5f9;
  --texto-principal: #191d26; --texto-suave: #5b6472; --texto-tenue: #8d95a3;
  --linha-default: #e4e8ef; --linha-suave: #eef1f6;
  --acento-default: #4353d9; --acento-suave: #e9edff; --acento-contraste: #ffffff;
  --sidebar-fundo: #f4f5f9; --sidebar-texto: #4b5364; --sidebar-texto-ativo: #191d26;
  --sidebar-linha: #e7eaf1;
  --estado-novo-texto: #6b7280;        --estado-novo-fundo: #eef0f3;
  --estado-contactado-texto: #2563b6;  --estado-contactado-fundo: #e6f0fb;
  --estado-1visita-texto: #6d4bc4;     --estado-1visita-fundo: #efe9fb;
  --estado-proposta-texto: #b5771a;    --estado-proposta-fundo: #fbf1de;
  --estado-seguimento-texto: #7d6551;  --estado-seguimento-fundo: #f2ece4;
  --estado-entregue-texto: #1f8f5f;    --estado-entregue-fundo: #e3f4ec;
  --estado-descartado-texto: #b0453f;  --estado-descartado-fundo: #fae9e8;
  --estado-fundida-texto: #5a6478;     --estado-fundida-fundo: #e9ebf1;
  --aviso-borda: #b5771a;  --aviso-fundo: #fbf1de;  --aviso-texto: #b5771a;
  --realce-chip-texto: #b5771a;  --realce-chip-fundo: #fbf1de;
  --semaforo-ok: #1f8f5f;
  --semaforo-perigo: #c2453f;
  --shadow: 0 1px 2px rgba(20, 28, 43, .05), 0 4px 16px rgba(20, 28, 43, .05);
}

/* --- casca ------------------------------------------------------------- */
.app {
  font-family: var(--font-ui);
  color: var(--texto-principal);
  background: var(--fundo-pagina);
  min-height: 100vh;
  display: grid;
  grid-template-columns: 248px 1fr;
  grid-template-rows: 100vh;
}
.app.rail { grid-template-columns: 68px 1fr; }
/* Overlay só existe em mobile; escondido por defeito para não ocupar célula do grid. */
.scrim { display: none; }

/* ---------- SIDEBAR ---------- */
.sidebar {
  background: var(--sidebar-fundo);
  color: var(--sidebar-texto);
  border-right: 1px solid var(--sidebar-linha);
  display: flex; flex-direction: column;
  padding: 14px 12px;
  gap: 4px;
  overflow: hidden;
}
.brand {
  display: flex; align-items: center; gap: 11px;
  padding: 8px 10px 16px;
  color: var(--sidebar-texto-ativo);
  white-space: nowrap;
}
.mark {
  width: 30px; height: 30px; flex: none;
  border-radius: var(--raio-sm);
  background: var(--acento-default);
  display: grid; place-items: center;
  color: var(--acento-contraste); font-weight: 700; font-size: 14px;
}
.brand .name { font-weight: 640; font-size: 15px; letter-spacing: -.01em; }
.brand .name small { display: block; font-weight: 450; font-size: 11px; color: var(--sidebar-texto); letter-spacing: .02em; }
.app.rail .brand .name, .app.rail .nav-label, .app.rail .navlink span,
.app.rail .side-foot .who, .app.rail .badge { display: none; }
.app.rail .navlink { justify-content: center; }

.nav-label {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .09em;
  color: var(--texto-tenue); padding: 14px 10px 6px; font-weight: 620;
}
.navlink {
  display: flex; align-items: center; gap: 11px;
  padding: 9px 10px; border-radius: var(--raio-md);
  color: var(--sidebar-texto); text-decoration: none;
  font-size: 13.5px; font-weight: 500;
  position: relative; white-space: nowrap;
  transition: background .12s, color .12s;
}
.navlink svg { width: 18px; height: 18px; flex: none; opacity: .85; }
.navlink:hover { background: var(--fundo-superficie-2); color: var(--sidebar-texto-ativo); }
/* Item ativo = pílula (fundo --acento-suave), sem barra lateral — o ícone
   fica na cor de acento, o texto na de sidebar-texto-ativo a 600. */
.navlink.active {
  background: var(--acento-suave);
  color: var(--sidebar-texto-ativo);
  font-weight: 600;
}
.navlink.active svg { color: var(--acento-default); opacity: 1; }
.badge {
  margin-left: auto; background: var(--acento-default); color: var(--acento-contraste);
  font-size: 11px; font-weight: 650; min-width: 19px; height: 19px;
  border-radius: var(--raio-pilula); display: grid; place-items: center; padding: 0 6px;
  font-variant-numeric: tabular-nums;
}
.side-foot {
  margin-top: auto; padding-top: 12px; border-top: 1px solid var(--sidebar-linha);
  display: flex; align-items: center; gap: 10px;
}
.avatar {
  width: 32px; height: 32px; border-radius: 50%; flex: none;
  background: var(--acento-default);
  color: var(--acento-contraste); display: grid; place-items: center; font-weight: 650; font-size: 12.5px;
}
.side-foot .who { line-height: 1.25; overflow: hidden; }
.side-foot .who b { color: var(--sidebar-texto-ativo); font-size: 13px; font-weight: 580; display: block; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; }
.side-foot .who span { font-size: 11.5px; color: var(--sidebar-texto); }

/* ---------- MAIN ---------- */
.main { display: flex; flex-direction: column; overflow: hidden; }
.topbar {
  height: 60px; flex: none;
  background: var(--fundo-pagina);
  border-bottom: 1px solid var(--linha-suave);
  display: flex; align-items: center; gap: 16px;
  padding: 0 22px;
}
.icon-btn {
  width: 36px; height: 36px; border-radius: var(--raio-sm);
  border: 1px solid transparent; background: transparent; color: var(--texto-suave);
  display: grid; place-items: center; cursor: pointer;
  transition: background .12s, color .12s;
}
.icon-btn:hover { background: var(--fundo-superficie-2); color: var(--texto-principal); }
/* max-width:none — o reset do base.css (img,svg,video{max-width:100%}) colapsa a 0px
   a largura de um svg só-com-viewBox dentro de um contentor display:grid (percentagem
   cíclica sem tamanho intrínseco). Foi o que «apagou» os ícones da topbar (tema/sair/
   recolher) sem os tirar do DOM — medido no browser a 2026-08-12. Os .navlink svg
   escapam por o pai ser flex. */
.icon-btn svg { width: 19px; height: 19px; max-width: none; }
.page-title { font-size: 17px; font-weight: 680; letter-spacing: -.01em; }
.page-title small { display: block; font-size: 12px; font-weight: 450; color: var(--texto-tenue); }
.top-right { margin-left: auto; display: flex; align-items: center; gap: 6px; }
.top-right form { margin: 0; }

.content { flex: 1; overflow-y: auto; padding: 24px; }
/* Só no Técnico: a barra vertical aparece quando um bloco expande
   (detalhe do erro nas Execuções) e rouba 15px ao conteúdo, redistribuindo
   as colunas da tabela (medido 2026-09-02 a 1920x1260: as 11 colunas
   mudavam ao abrir, ex. «Erro» 429,45→425,47px). Reservar o gutter sempre
   custa uma faixa de 15px permanente à direita quando não há barra — não
   se quer isso nas páginas de trabalho, por isso fica scoped a esta página. */
.content.gutter-estavel { scrollbar-gutter: stable; }
/* .content-inner fluido a 100% (decisão de 2026-08-12): sem max-width nem
   margin:0 auto — o conteúdo ocupa toda a largura disponível menos o padding
   do .content. Não repor um teto aqui por engano. */

/* ---------- TOASTS / MENSAGENS ---------- */
.toasts { display: flex; flex-direction: column; gap: 8px; margin-bottom: 18px; }
.toast {
  border: 1px solid var(--linha-default); border-left-width: 3px;
  background: var(--fundo-superficie); color: var(--texto-principal);
  border-radius: var(--raio-sm); padding: 10px 14px; font-size: 13px;
  box-shadow: var(--shadow);
}
.toast.success { border-left-color: var(--semaforo-ok); }
.toast.error { border-left-color: var(--semaforo-perigo); }
.toast.warning { border-left-color: var(--aviso-borda); }
.toast.info { border-left-color: var(--acento-default); }

/* ---------- ERROS DE FORMULÁRIO ---------- */
/* O Django 5.2 renderiza os erros num <ul class="errorlist"> — os de campo com
   id="id_<campo>_error", os de formulário inteiro (a adesão duplicada) com
   class="errorlist nonfield". Estilo igual aos toasts de erro: barra
   --semaforo-perigo à esquerda.
   --semaforo-perigo tem valor POR TEMA (hex herdados 1:1 do antigo --danger,
   já medidos): claro #c2453f dá 4,98:1 sobre #ffffff (--fundo-superficie) e
   4,73:1 sobre #f8f9fb (--fundo-pagina); escuro #d0716c dá 5,04:1 sobre
   #161d29 e 5,54:1 sobre #0e131d — cumpre o 4,5:1 do WCAG AA para texto
   normal nos dois temas (um valor único não cumpriria: para a mesma família
   de matiz o conjunto de luminâncias que serve os dois fundos é vazio). O
   texto do erro fica a --texto-principal por consistência com o .toast — não
   por contraste; a barra é que usa --semaforo-perigo.
   Serve a casca do painel (base.html) e a do login (login.html). */
.errorlist {
  margin: 0 0 12px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
/* O ``list-style`` tem de ter o <li> como alvo explícito do seletor: sem o
   Pico já não há regra concorrente, mas mantém-se por clareza e para não
   depender do valor por omissão do agente de utilizador. */
.errorlist li {
  list-style: none;
  margin: 0;
  border: 1px solid var(--linha-default);
  border-left: 3px solid var(--semaforo-perigo);
  background: var(--fundo-superficie);
  color: var(--texto-principal);
  border-radius: var(--raio-sm);
  padding: 10px 14px;
  font-size: 13px;
  line-height: 1.45;
}

/* ---------- STAT TILES ---------- */
/* Uma coluna por cartão, sem os contar no CSS: o Início do ADMIN/COORDENADOR
   tem CINCO KPIs desde o fluxo novo de estados (2026-08-29, «Propostas · mês»)
   e o do CONSULTOR mantém QUATRO. Com `repeat(5, 1fr)` fixo, a linha do
   consultor ficaria com um buraco à direita; `grid-auto-flow: column` +
   `grid-auto-columns` dá N colunas iguais para N cartões. O `minmax(0, 1fr)`
   (e não `1fr`) impede que um número/rótulo largo estique a sua coluna. */
.tiles {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
  gap: 14px; margin-bottom: 22px;
}
.tile {
  background: var(--fundo-superficie); border: 1px solid var(--linha-default);
  border-radius: var(--raio-lg); padding: var(--espaco-xl); box-shadow: var(--shadow);
}
/* Cards clicáveis (links): filtram a lista. */
a.tile { text-decoration: none; color: inherit; display: block; transition: border-color .12s, box-shadow .12s; }
a.tile:hover { border-color: var(--acento-default); }
a.tile.active { border-color: var(--acento-default); box-shadow: 0 0 0 1px var(--acento-default) inset, var(--shadow); }
.tile .lbl { font-size: 12.5px; color: var(--texto-suave); font-weight: 500; display: flex; align-items: center; gap: 7px; }
.tile .lbl .dot { width: 8px; height: 8px; border-radius: 50%; }
.tile .val { font-size: 29px; font-weight: 680; letter-spacing: -.02em; margin-top: 8px; font-variant-numeric: tabular-nums; font-family: var(--font-num); color: var(--texto-principal); }
.tile .sub { font-size: 11.5px; color: var(--texto-tenue); margin-top: 2px; }
.tile .sub b { color: var(--semaforo-ok); font-weight: 600; }

/* ---------- LISTA COM SCROLL PRÓPRIO + THEAD FIXO ---------- */
/* Nesta página a .content não rola: o cartão preenche a altura e só a lista
   (.table-wrap) tem scroll, com o thead sticky. */
.content.fill { overflow: hidden; display: flex; flex-direction: column; }
/* Fluido a 100% (decisão de 2026-08-12): sem teto — com o margin:0 auto já fora do
   .content-inner base, o stretch por omissão do flex do .content.fill estica-o à
   largura total (sem isso o item flex encolhia ao conteúdo — shrink-to-fit). */
.content-inner.fill { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.card.fill { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.card.fill .card-head { flex: none; }
.card.fill .table-wrap { flex: 1; min-height: 120px; overflow-y: auto; }
.card.fill .pag { flex: none; }
.card .table-wrap thead th { position: sticky; top: 0; z-index: 1; }
.pag { padding: 12px 18px; border-top: 1px solid var(--linha-suave); }
.pag .count { font-size: 12px; color: var(--texto-tenue); }
.pag-nav { display: flex; align-items: center; gap: 14px; }
.pag-nav .count { margin: 0 auto; text-align: center; }
.pag-btn {
  font-size: 12.5px; font-weight: 550; color: var(--texto-principal); text-decoration: none;
  background: var(--fundo-superficie-2); border: 1px solid var(--linha-default); border-radius: var(--raio-sm);
  padding: 7px 13px; cursor: pointer; white-space: nowrap; transition: background .12s, border-color .12s;
}
.pag-btn:hover { background: var(--fundo-superficie); border-color: var(--acento-default); color: var(--acento-default); }
.pag-btn.disabled { color: var(--texto-tenue); background: transparent; cursor: default; opacity: .6; }
.pag-btn.disabled:hover { border-color: var(--linha-default); color: var(--texto-tenue); background: transparent; }

/* ---------- CARD + TABLE ---------- */
.card {
  background: var(--fundo-superficie); border: 1px solid var(--linha-default);
  border-radius: var(--raio-lg); box-shadow: var(--shadow); overflow: hidden;
  margin-bottom: 22px;
}
.card-head {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: var(--espaco-lg) var(--espaco-xl); border-bottom: 1px solid var(--linha-suave);
}
.card-head h2 { margin: 0; font-size: 14.5px; font-weight: 630; letter-spacing: -.01em; }
.card-head .count { font-size: 12px; color: var(--texto-tenue); font-weight: 500; }
.filters { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.chip-select {
  font: inherit; font-size: 12.5px; color: var(--texto-principal);
  background: var(--fundo-superficie-2); border: 1px solid var(--linha-default);
  border-radius: var(--raio-sm); padding: 7px 11px; cursor: pointer;
}
/* Controlos reais dos filtros: linha compacta, pequenos, sem largura total
   nem margens do input/select genérico de base.css. */
.card-head .filters select {
  font: inherit; font-size: 12.5px; color: var(--texto-principal);
  appearance: auto;
  background-color: var(--fundo-superficie-2);
  border: 1px solid var(--linha-default); border-radius: var(--raio-sm);
  padding: 7px 26px 7px 11px; margin: 0;
  width: auto; height: auto; min-width: 0; cursor: pointer;
}
.filter-search {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--fundo-superficie-2); border: 1px solid var(--linha-default);
  border-radius: var(--raio-sm); padding: 0 10px; color: var(--texto-tenue);
}
.filter-search svg { width: 15px; height: 15px; flex: none; }
.filter-search input {
  font: inherit; font-size: 12.5px; color: var(--texto-principal);
  border: 0; background: transparent; outline: none; box-shadow: none;
  padding: 7px 0; margin: 0; width: 200px; max-width: 42vw; height: auto;
}
.card .table-wrap { overflow-x: auto; }
.card table { width: 100%; border-collapse: collapse; font-size: 13px; margin: 0; }
.card thead th {
  text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--texto-tenue); font-weight: 600; padding: 11px 18px; border-bottom: 1px solid var(--linha-suave);
  white-space: nowrap; background: var(--fundo-superficie);
}
.card tbody td { padding: 12px 18px; border-bottom: 1px solid var(--linha-suave); vertical-align: middle; }
.card tbody tr:last-child td { border-bottom: 0; }
.card tbody tr { transition: background .1s; }
.card tbody tr:hover { background: var(--fundo-superficie-2); }
.tel { font-family: var(--font-num); font-size: 12.5px; font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.muted { color: var(--texto-suave); }
.num { font-family: var(--font-num); font-variant-numeric: tabular-nums; }

/* ---------- CHIPS DE ESTADO ---------- */
.st { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 560; padding: 3px 9px 3px 8px; border-radius: var(--raio-pilula); white-space: nowrap; }
.st::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.st.novo { color: var(--estado-novo-texto); background: var(--estado-novo-fundo); }
.st.contactado { color: var(--estado-contactado-texto); background: var(--estado-contactado-fundo); }
/* A classe de PRIMEIRA_VISITA é `visita` e não `1visita` como o token
   --st-1visita: um seletor de classe não pode começar por dígito (`.1visita`
   é inválido, teria de vir escapado `.\31 visita`). Nos custom properties o
   dígito é legal, e aí o nome fica junto da etiqueta «1.ª visita». */
.st.visita { color: var(--estado-1visita-texto); background: var(--estado-1visita-fundo); }
.st.proposta { color: var(--estado-proposta-texto); background: var(--estado-proposta-fundo); }
.st.seguimento { color: var(--estado-seguimento-texto); background: var(--estado-seguimento-fundo); }
.st.entregue { color: var(--estado-entregue-texto); background: var(--estado-entregue-fundo); }
.st.descartado { color: var(--estado-descartado-texto); background: var(--estado-descartado-fundo); }
.st.fundida { color: var(--estado-fundida-texto); background: var(--estado-fundida-fundo); }

/* ---------- GLOSSÁRIO DOS ESTADOS (hover/foco) ----------
   Decisão do Vítor de 2026-08-28 (spec §3): pairar — ou focar com Tab, ou
   tocar no telemóvel — num chip/card de estado abre a explicação do estado.
   CSS/HTML próprio, sem bibliotecas (política zero-CDN) e sem `title=` nativo
   (lento, não estilizável, invisível ao teclado).

   `visibility: hidden` (e não `display: none`) mantém a caixa no DOM: o texto
   é o alvo do `aria-describedby` do chip, e a descrição acessível de um nó
   referenciado explicitamente conta mesmo escondida.

   Limitação assumida: é posicionamento absoluto, logo a caixa fica cortada
   quando o chip está na última linha visível de um contentor com scroll
   próprio (`.card.fill .table-wrap`). Abrir para BAIXO é o que minimiza o
   caso — nas duas tabelas o Estado é coluna do meio e a caixa cabe na
   largura. Corrigir a fundo pedia JS de posicionamento; não compensa.

   Ancorada à DIREITA do chip (`right: 0`), logo cresce para a ESQUERDA —
   achado de browser de 2026-08-30: centrada (`left: 50%`) transbordava o ecrã
   e o texto ficava cortado nos chips encostados à margem direita, que são as
   linhas do «Precisa de ação» do Início (o chip é o último elemento da
   linha). Vale para TODOS os sítios com `{% chip_estado %}`: o chip está
   sempre à direita do seu contentor (Início, cartões de «As minhas leads») ou
   numa coluna do meio das tabelas (bolsa, transferir carteira) — nenhum
   encosta à esquerda, portanto crescer para a esquerda nunca transborda desse
   lado. As DUAS exceções, cada uma junto do seu componente mais abaixo: a
   linha de cards da bolsa (tem cards nas duas margens) e o badge da ficha da
   lead (esse, sim, encostado à esquerda do seu card). */
.gloss { position: relative; display: inline-flex; }
.gloss > .st { cursor: help; }
.gloss > .st:focus-visible { outline: 2px solid var(--acento-default); outline-offset: 2px; }
.gloss-caixa {
  position: absolute; z-index: 50; top: calc(100% + 7px); right: 0;
  width: max-content; max-width: 260px;
  padding: 9px 11px; text-align: left; white-space: normal;
  font-size: 12px; font-weight: 450; line-height: 1.45;
  color: var(--texto-principal); background: var(--fundo-superficie);
  border: 1px solid var(--linha-default); border-radius: var(--raio-sm);
  box-shadow: var(--shadow);
  opacity: 0; visibility: hidden; pointer-events: none; transition: opacity .12s;
}
.gloss:hover > .gloss-caixa,
.gloss:focus-within > .gloss-caixa { opacity: 1; visibility: visible; }
@media (prefers-reduced-motion: reduce) { .gloss-caixa { transition: none; } }

.pricedrop { color: var(--estado-descartado-texto); font-weight: 600; font-size: 11.5px; display: inline-flex; align-items: center; gap: 3px; }
.pricedrop svg { width: 12px; height: 12px; }

.hint {
  margin-top: 18px; font-size: 12.5px; color: var(--texto-tenue);
  display: flex; align-items: center; gap: 8px;
}

/* Conteúdo funcional das páginas antigas (forms/artigos ainda por redesenhar)
   vive dentro de .content; garante uma hierarquia tipográfica mais compacta
   do que a de base.css (pensada para uma UI densa de gestão). */
.content h1 { font-size: 18px; font-weight: 640; letter-spacing: -.01em; margin: 0 0 14px; }
.content h2 { font-size: 15px; font-weight: 620; margin: 22px 0 10px; }
.content h3 { font-size: 13.5px; font-weight: 600; margin: 16px 0 8px; }

/* ---------- LOGIN (standalone, sem sidebar) ---------- */
.auth {
  min-height: 100vh; display: grid; place-items: center; padding: 24px;
  font-family: var(--font-ui); color: var(--texto-principal); background: var(--fundo-pagina);
}
.auth-card {
  background: var(--fundo-superficie); border: 1px solid var(--linha-default);
  border-radius: var(--raio-lg); box-shadow: var(--shadow);
  padding: var(--espaco-2xl); width: 100%; max-width: 400px;
}
.auth-head { text-align: center; margin-bottom: var(--espaco-xl); }
.auth-head .mark {
  width: 48px; height: 48px; border-radius: var(--raio-md); font-size: 16px;
  margin: 0 auto var(--espaco-md);
}
.auth-title { font-size: 18px; font-weight: 680; letter-spacing: -.01em; margin: 0 0 4px; }
.auth-subtitle { font-size: 13px; color: var(--texto-suave); margin: 0; }
.auth-card form button[type="submit"] { width: 100%; margin-top: var(--espaco-sm); }
.auth-foot { margin: var(--espaco-lg) 0 0; font-size: 12.5px; color: var(--texto-tenue); text-align: center; }

/* ---------- responsivo ---------- */
@media (max-width: 900px) {
  .app, .app.rail { grid-template-columns: 1fr; }
  .sidebar {
    position: fixed; inset: 0 auto 0 0; width: 248px; z-index: 40;
    transform: translateX(-100%); transition: transform .22s;
  }
  .app.open .sidebar { transform: none; box-shadow: 0 0 40px rgba(0, 0, 0, .4); }
  .scrim { display: none; position: fixed; inset: 0; background: rgba(0, 0, 0, .45); z-index: 30; }
  .app.open .scrim { display: block; }
  .hamb { display: grid !important; }
  /* Em ecrã estreito volta a fluir por LINHAS (o `grid-auto-flow: column` da
     regra base espremeria os 4/5 cartões numa só linha) — duas colunas. */
  .tiles { grid-auto-flow: row; grid-template-columns: repeat(2, 1fr); }
}
.hamb { display: none; }

/* Em ecrã estreito ou baixo não aprisiones o scroll: a página volta a rolar
   normalmente e a lista mostra-se por inteiro (sem caixa interna nem sticky). */
@media (max-width: 900px), (max-height: 560px) {
  .content.fill { overflow-y: auto; display: block; }
  .content-inner.fill, .card.fill { display: block; min-height: 0; }
  .card.fill .table-wrap { overflow-y: visible; min-height: 0; }
  .card .table-wrap thead th { position: static; }
}

/* ---------- acessibilidade ---------- */
:focus-visible { outline: 2px solid var(--acento-default); outline-offset: 2px; border-radius: 4px; }
.navlink:focus-visible { outline-offset: -2px; }

/* Universal de propósito (como o Pico fazia): há transições no base.css
   (inputs, botões) e neste ficheiro (tiles, paginação, sidebar móvel) — uma
   lista de seletores aqui esquecia-se de metade e voltava a encolher o
   contrato à primeira classe nova. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

/* ---------- badge «investiu no anúncio» (sinais comerciais pagos) ---------- */
.badge-investiu {
  display: inline-block;
  margin-left: .4rem;
  padding: .05rem .4rem;
  font-size: .72rem;
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
  color: #7a4b00;
  background: #ffe9c7;
  border: 1px solid #f2c992;
  border-radius: .5rem;
}
.badge-investiu.grande { font-size: .85rem; padding: .15rem .55rem; }

/* ---------- badge «grupo do portal» (lead sem freguesia, com candidatas) ---------- */
.badge-grupo {
  display: inline-block;
  margin-left: .4rem;
  padding: .05rem .4rem;
  font-size: .72rem;
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
  color: #3a4a63;
  background: #e9eefb;
  border: 1px solid #c3d0ea;
  border-radius: .5rem;
}

/* ---------- badge «sem telefone» (opção A, spec de leads sem telefone) -----
   Tom neutro/cinzento, distinto de --investiu (âmbar) e --grupo (azul) — a
   lead ainda não perdeu prioridade nem tem ambiguidade, só falta o telefone.
   Ao contrário dos dois badges acima (hex fixo), usa os TOKENS de tema
   (`--texto-suave`/`--fundo-superficie-2`/`--linha-default`, já definidos e
   emparelhados nos três blocos de cor — ver `test_tokens_css.py`): não
   declara nenhum token novo, por isso o gate de paridade não é afetado. ---- */
.badge-sem-telefone {
  display: inline-block;
  margin-left: .4rem;
  padding: .05rem .4rem;
  font-size: .72rem;
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
  color: var(--texto-suave);
  background: var(--fundo-superficie-2);
  border: 1px solid var(--linha-default);
  border-radius: .5rem;
}

/* ---------- Início · dashboard (fase 5, frente 2) ---------- */
/* Fila dos dois cartões (atividade 60% / precisa de ação 40%). Só ganha a
   classe quando os DOIS cartões existem no contexto (ver inicio.html) — com
   um só, o `div` fica sem grid e o cartão ocupa a largura toda sozinho. */
.ini-fila { display: grid; grid-template-columns: 3fr 2fr; gap: var(--espaco-lg); align-items: start; }
@media (max-width: 900px) { .ini-fila { grid-template-columns: 1fr; } }

/* Link «Ver bolsa →» / «Ver todas →» / «Painel técnico →» no `card-head`. */
.ini-link { margin-left: auto; font-size: 12.5px; font-weight: 600; color: var(--acento-default); text-decoration: none; white-space: nowrap; }
.ini-link:hover { text-decoration: underline; }

/* Atividade por consultor: linha = nome | barra | «contactadas/recebidas». */
.ini-atividade-corpo { padding: var(--espaco-md) var(--espaco-xl); display: flex; flex-direction: column; gap: var(--espaco-md); }
.ini-atividade-linha { display: grid; grid-template-columns: 112px 1fr 46px; align-items: center; gap: var(--espaco-md); }
.ini-atividade-nome { font-size: 12.5px; font-weight: 550; color: var(--texto-principal); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ini-atividade-num { font-family: var(--font-num); font-variant-numeric: tabular-nums; font-size: 12.5px; color: var(--texto-suave); text-align: right; }
.ini-barra-fundo { background: var(--acento-suave); border-radius: var(--raio-pilula); height: 8px; overflow: hidden; }
.ini-barra-preenchida { background: var(--acento-default); border-radius: var(--raio-pilula); height: 100%; }
.ini-atividade-legenda { display: flex; align-items: center; gap: var(--espaco-lg); padding: var(--espaco-sm) var(--espaco-xl) var(--espaco-lg); font-size: 11.5px; color: var(--texto-tenue); }
.ini-legenda-item { display: inline-flex; align-items: center; gap: 6px; }
.ini-legenda-ponto { width: 8px; height: 8px; border-radius: 50%; }
.ini-legenda-ponto.ini-legenda-contactadas { background: var(--acento-default); }
.ini-legenda-ponto.ini-legenda-recebidas { background: var(--acento-suave); }

/* Precisa de ação: lista de linhas-link (título+subtítulo à esquerda, chip
   de estado à direita — reutiliza `.st.*`, já existente). */
.ini-acao-corpo { display: flex; flex-direction: column; }
.ini-acao-linha {
  display: flex; align-items: center; justify-content: space-between; gap: var(--espaco-md);
  padding: var(--espaco-md) var(--espaco-xl); text-decoration: none; color: inherit;
  border-bottom: 1px solid var(--linha-suave); transition: background .1s;
}
.ini-acao-linha:last-child { border-bottom: 0; }
.ini-acao-linha:hover { background: var(--fundo-superficie-2); }
.ini-acao-titulo { font-size: 13px; font-weight: 580; color: var(--texto-principal); }
.ini-acao-subtitulo { font-size: 11.5px; color: var(--texto-tenue); margin-top: 2px; }
.ini-acao-vazio { padding: var(--espaco-lg) var(--espaco-xl); }

/* Varrimento desta noite: chip de saúde no card-head + mini-tiles full-width
   em --fundo-superficie-2 (um nível abaixo do --fundo-superficie do cartão). */
.ini-chip { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; padding: 4px 10px 4px 9px; border-radius: var(--raio-pilula); border: 1px solid var(--linha-default); background: var(--fundo-superficie-2); white-space: nowrap; }
.ini-chip::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.ini-chip-ok { color: var(--semaforo-ok); }
.ini-chip-perigo { color: var(--semaforo-perigo); }
.ini-mini-tiles { display: grid; grid-template-columns: repeat(5, 1fr); gap: var(--espaco-md); padding: var(--espaco-lg) var(--espaco-xl) var(--espaco-xl); }
.ini-mini-tile { background: var(--fundo-superficie-2); border-radius: var(--raio-md); padding: var(--espaco-md) var(--espaco-lg); }
.ini-mini-tile .val { font-size: 19px; font-weight: 660; letter-spacing: -.01em; font-variant-numeric: tabular-nums; font-family: var(--font-num); color: var(--texto-principal); }
.ini-mini-tile .lbl { font-size: 11.5px; color: var(--texto-tenue); margin-top: 3px; }
.ini-varrimento-vazio { padding: var(--espaco-lg) var(--espaco-xl) var(--espaco-xl); margin: 0; }

/* Duas filas «Varrimento»/«Revisita» no mesmo cartão (spec de 2026-09-03,
   «Gate: só depois do varrimento») — rótulo pequeno em maiúsculas acima de
   cada fila, mesma linguagem do `.ini-acao-apodrecer-titulo`. A fila da
   revisita tem 4 tiles (não 5) — por isso a query de 900px abaixo lista as
   DUAS classes explicitamente (achado M-3 da revisão de 2026-09-03: a
   `.ini-mini-tiles-revisita` vinha DEPOIS da query, e com a mesma
   especificidade ganhava sempre ela, deixando a revisita a 4 colunas a
   900px em vez de 2 — um comentário que afirma um invariante é uma
   promessa). */
.ini-varrimento-fila-rotulo { display: block; padding: var(--espaco-md) var(--espaco-xl) 0; margin: 0; font-size: 10.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--texto-tenue); }
.ini-varrimento-fila:first-child .ini-varrimento-fila-rotulo { padding-top: var(--espaco-sm); }
.ini-mini-tiles-revisita { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 900px) {
  .ini-mini-tiles, .ini-mini-tiles-revisita { grid-template-columns: repeat(2, 1fr); }
}

/* Cartão de atalhos simples (só TECNICO — os outros papéis já têm a
   navegação inteira na sidebar). */
.ini-atalhos { display: flex; flex-wrap: wrap; gap: var(--espaco-sm); padding: var(--espaco-lg) var(--espaco-xl); }
.ini-atalhos a {
  font-size: 12.5px; font-weight: 550; color: var(--texto-principal); text-decoration: none;
  background: var(--fundo-superficie-2); border: 1px solid var(--linha-default); border-radius: var(--raio-sm);
  padding: 8px 14px;
}
.ini-atalhos a:hover { border-color: var(--acento-default); color: var(--acento-default); }

/* Variação semanal negativa no tile de leads novas: o .tile .sub b pinta a
   verde de «boa notícia» (o caso original, descida de preço na bolsa); uma
   queda de leads não é boa notícia — leva a cor de perigo. */
.tile .sub b.ini-variacao-neg { color: var(--semaforo-perigo); }

/* ============================================================================
   Fase 5, lote A — re-pele Bolsa · Detalhe do alvo · As minhas leads.
   Só acrescentos (nunca edições ao que já existe acima); classes prefixadas
   por página: .bl- (bolsa), .det- (detalhe do alvo), .ml- (minhas leads).
   ============================================================================ */

/* ---------- .bl- (Bolsa de leads) ---------- */

/* Chips dos filtros: pílula em vez do raio-sm por omissão de
   `.card-head .filters select`/`.filter-search`. Especificidade mais alta
   (3 classes + tipo) do que a regra original (2 classes + tipo) — vence sem
   precisar de !important nem de tocar na regra de cima. */
.card-head .filters select.bl-chip {
  border-radius: var(--raio-pilula);
  padding: 7px 28px 7px 14px;
}
.card-head .filters .filter-search.bl-chip {
  border-radius: var(--raio-pilula);
  padding-left: 14px;
}
/* Estado ativo do chip (tem valor escolhido): acento, como o tile ativo. */
.card-head .filters select.bl-chip.bl-chip-ativo {
  background-color: var(--acento-suave);
  color: var(--acento-default);
  border-color: var(--acento-default);
  font-weight: 620;
}
.bl-limpar {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--acento-default);
  text-decoration: none;
  white-space: nowrap;
  margin-left: 4px;
}
.bl-limpar:hover { text-decoration: underline; }

/* Linhas mais altas/espaçadas (Figma): acrescenta ao padding de `.card tbody
   td` sem o substituir — a regra de cima fica como o piso comum de todas as
   tabelas em `.card` (fusões, técnico, etc.), esta só se aplica à bolsa. */
.bl-tabela th, .bl-tabela td { padding-top: 15px; padding-bottom: 15px; }

/* Linhas clicáveis: cursor pointer indica interatividade (2026-08-30).
   O hover subtil já vem do `.card tbody tr:hover` acima (background em
   --fundo-superficie-2 com transição 0.1s). */
.bl-tabela tr[data-href] { cursor: pointer; }

/* Paginação em botões pílula, só na bolsa (o resto do painel — técnico,
   transferência de carteira — continua com o `.pag-btn` raio-sm). */
.bl-pag .pag-btn { border-radius: var(--raio-pilula); padding: 8px 16px; }

/* ---------- .det- (Detalhe do alvo, redesign «Detalhe da Lead v2»,
   2026-08-12, bloco PAINEL-LAYOUT) ----------
   Layout L-A: `.det-topo` (ficha Z1-B + card Ação Z2-A) e `.det-linha2`
   (Timeline do consultor + Vida do imóvel, Z3-A) lado a lado na primeira
   dobra; `.det-anuncios` (Z4-A) em grelha no fundo. */

.det-breadcrumb a { color: inherit; }

.det-topo, .det-linha2 {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
  gap: var(--espaco-lg);
  align-items: start;
  margin-bottom: var(--espaco-lg);
}
.det-topo .card, .det-linha2 .card { margin-bottom: 0; }
@media (max-width: 900px) { .det-topo, .det-linha2 { grid-template-columns: 1fr; } }

/* ---- Z1-B: ficha do imóvel ---- */
.det-imovel-preco { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; padding: var(--espaco-xl) var(--espaco-xl) 0; font-size: 27px; font-weight: 680; letter-spacing: -.01em; font-variant-numeric: tabular-nums; font-family: var(--font-num); }
.det-eurm2 { font-size: 13px; font-weight: 500; color: var(--texto-suave); }
.det-chips { display: flex; flex-wrap: wrap; gap: 8px; padding: var(--espaco-md) var(--espaco-xl) 0; }
.det-chip {
  background: var(--fundo-superficie-2);
  border: 1px solid var(--linha-default);
  border-radius: var(--raio-pilula);
  padding: 4px 12px;
  font-size: 12.5px;
  color: var(--texto-suave);
  /* Sem nowrap: os extras da ficha do Idealista trazem frases (58 chars,
     ex. acessibilidade) que num ecrã de 375px eram CORTADAS sem reticências
     na borda do card (achado W4, 2026-08-30). Um chip curto nunca quebra;
     o comprido vira pílula de 2 linhas em vez de texto amputado. */
  max-width: 100%;
}
.det-chip.det-chip-hl { background: var(--realce-chip-fundo); border-color: var(--realce-chip-fundo); color: var(--realce-chip-texto); }
.det-chip.det-chip-sm { padding: 2px 9px; font-size: 11px; }
.det-metarow { display: flex; flex-wrap: wrap; gap: 14px; margin: var(--espaco-md) var(--espaco-xl) 0; padding-top: var(--espaco-md); border-top: 1px solid var(--linha-suave); font-size: 12.5px; color: var(--texto-suave); }
.det-metarow b { font-weight: 620; color: var(--texto-principal); }
.det-metarow-morada { margin-top: var(--espaco-sm); border-top: 0; padding-top: 0; }
.det-fotos { display: flex; gap: 6px; flex-wrap: wrap; margin: var(--espaco-md) var(--espaco-xl) 0; }
.det-foto { width: 84px; height: 58px; border-radius: var(--raio-sm); object-fit: cover; background: var(--fundo-superficie-2); }
.det-foto-slot {
  display: inline-flex;
  /* Neutraliza herança de button, [role="button"] (base.css:207):
     background, border, padding, border-radius e hover opacity. */
  background: transparent;
  border: none;
  padding: 0;
  border-radius: initial;
}
.det-foto-slot:hover { opacity: 1; }
/* Regras de foco (verificadas no browser): foco programático (após clique)
   fica transparente; navegação por teclado (Tab) mantém outline azul. */
.det-foto-slot:focus { outline: transparent; }
.det-foto-slot:focus-visible { outline: 2px solid var(--acento-default); outline-offset: 2px; }
/* Foto morta (URL de CDN do portal que já não responde): o `onerror` do
   template marca o slot com `.morta` em vez de deixar uma faixa branca
   invisível — placeholder discreto com os mesmos tokens do resto da ficha. */
.det-foto-slot.morta {
  width: 84px; height: 58px; border-radius: var(--raio-sm);
  background: var(--fundo-superficie-2); border: 1px dashed var(--linha-default);
  align-items: center; justify-content: center;
  color: var(--texto-tenue); font-size: 9.5px; line-height: 1.2; text-align: center;
}
.det-foto-slot.morta::after { content: "📷 foto indisponível"; padding: 0 4px; }
/* Benchmark de preços (Z1-B, bloco PAINEL-FICHA): gradiente com as tintas de
   estado já existentes (entregue→agendado→descartado), sem tokens novos —
   o gate de paridade claro/escuro (`test_tokens_css`) só vigia os `--`
   definidos nos três blocos de tema, e esta barra só os LÊ. */
.det-bench { margin: var(--espaco-md) var(--espaco-xl) 0; font-size: 12px; color: var(--texto-suave); }
.det-bench-titulo { margin: 0 0 6px; }
.det-bench-bar {
  position: relative; height: 6px; border-radius: var(--raio-sm);
  background: linear-gradient(90deg, var(--estado-entregue-fundo), var(--estado-proposta-fundo), var(--estado-descartado-fundo));
}
.det-bench-dot {
  position: absolute; top: -3px; width: 12px; height: 12px; border-radius: 50%;
  background: var(--acento-default); border: 2px solid var(--fundo-superficie);
  box-shadow: 0 0 0 1px var(--acento-default); transform: translateX(-50%);
}
.det-bench-lbls { display: flex; justify-content: space-between; margin-top: 4px; font-variant-numeric: tabular-nums; }
.det-desc { margin: var(--espaco-md) var(--espaco-xl) 0; font-size: 12.5px; color: var(--texto-suave); border-left: 3px solid var(--linha-default); padding: 2px 0 2px 10px; font-style: italic; }
.det-desc-completa { margin-top: 6px; font-style: normal; }
.det-desc-completa summary { cursor: pointer; color: var(--acento-default); font-size: 11.5px; font-weight: 600; }
.det-desc-completa p { margin: 6px 0 0; }
.det-links { display: flex; flex-wrap: wrap; gap: var(--espaco-lg); padding: var(--espaco-md) var(--espaco-xl) var(--espaco-xl); font-size: 12.5px; font-weight: 600; }
.det-grupo { margin: 0; padding: 0 var(--espaco-xl) var(--espaco-xl); font-size: 12px; }
.det-linkzinho { color: var(--acento-default); font-size: 12px; text-decoration: none; white-space: nowrap; }
.det-linkzinho:hover { text-decoration: underline; }

/* ---- Z2-A v2: card Ação — 3 linhas espaçadas, rótulo por secção ---- */
.det-acao-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: var(--espaco-lg) var(--espaco-xl); border-bottom: 1px solid var(--linha-suave); }
.det-acao-row:last-child { border-bottom: 0; }
.det-acao-rotulo { flex-basis: 100%; font-size: 10.5px; font-weight: 650; letter-spacing: .09em; text-transform: uppercase; color: var(--texto-tenue); }
/* Badge de estado da ficha (glossário desde 2026-08-30): abre para a DIREITA,
   ao contrário de todos os outros chips. É o único encostado à ESQUERDA do
   seu contentor — o rótulo «ESTADO» tem `flex-basis: 100%`, portanto o badge
   abre linha na margem esquerda do card. Com a âncora à direita (a base) a
   caixa crescia ~170px para FORA do `.det-acao`, que é um `.card` com
   `overflow: hidden`: o texto sairia cortado, o mesmo achado de browser que
   as pontas dos cards da bolsa. Para dentro cabe — a coluna do card Ação (o
   `1fr` de `1.6fr/1fr`) dá ~330px de interior já a 1280px, contra os 260px da
   caixa. */
.det-acao-row > .gloss > .gloss-caixa { left: 0; right: auto; transform: none; }
.det-acao-rodape { flex-basis: 100%; font-size: 11.5px; }
.det-acao-transicoes { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; }
.det-pill {
  font-size: 11.5px; font-weight: 550; color: var(--texto-principal);
  background: var(--fundo-superficie-2); border: 1px solid var(--linha-default);
  border-radius: var(--raio-pilula); padding: 5px 12px; cursor: pointer; white-space: nowrap;
}
.det-pill:hover { border-color: var(--acento-default); color: var(--acento-default); }
.det-pill-perigo { background: var(--estado-descartado-fundo); color: var(--estado-descartado-texto); border-color: var(--estado-descartado-fundo); }
.det-acao-contacto { flex-basis: 100%; display: flex; flex-direction: column; gap: 8px; }
.det-acao-contacto-linha { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.det-tel { font-family: var(--font-num); font-size: 15px; font-variant-numeric: tabular-nums; }
.det-btn-whatsapp { background: var(--estado-entregue-fundo); color: var(--estado-entregue-texto); border-color: var(--estado-entregue-fundo); }
.det-contacto-nota { margin: 0; font-size: 12px; }
.det-btn-descartar { background: var(--estado-descartado-fundo); color: var(--estado-descartado-texto); border-color: var(--estado-descartado-fundo); }

/* Aviso «este proprietário tem mais imóveis» (B3, spec de dedup-fase-b-um-
   alvo-por-imovel §5, mock Figma 161:3): logo abaixo da faixa CONTACTO.
   Tokens --aviso-* (mesmo padrão do .vc-banner) — fundo+texto âmbar,
   NUNCA cor hardcoded. Um <li> por cenário presente (própria/agência/
   fora) — o bullet é o marcador de lista por omissão. */
.det-aviso-imoveis {
  margin-top: 4px;
  padding: .55rem .85rem;
  border-radius: .4rem;
  background: var(--aviso-fundo);
  color: var(--aviso-texto);
  font-size: 12.5px;
  font-weight: 550;
}
.det-aviso-imoveis ul { margin: 0; padding-left: 1.15em; list-style: disc; }
.det-aviso-imoveis li + li { margin-top: 4px; }
.det-aviso-imoveis a { color: inherit; font-weight: 700; text-decoration: underline; }

.det-acao-atribuicao { flex-basis: 100%; display: flex; flex-direction: column; gap: 10px; }
.det-atrib-atual { display: flex; align-items: center; gap: 12px; }
.det-atrib-nome { font-size: 13.5px; font-weight: 620; color: var(--texto-principal); }
.det-atrib-zona { font-size: 12px; margin-top: 1px; }
.det-atrib-vazio { margin: 0; }
.det-atrib-form summary { font-size: 12.5px; font-weight: 620; color: var(--acento-default); cursor: pointer; }
.det-atrib-form form { margin-top: 12px; }

/* ---- Z3-A: as duas timelines (consultor e imóvel) partilham `.det-tl` ---- */
.det-tl { list-style: none; margin: 0; padding: var(--espaco-md) var(--espaco-xl) var(--espaco-lg); display: flex; flex-direction: column; gap: var(--espaco-md); }
.det-tl-item { display: flex; align-items: flex-start; gap: 10px; }
.det-tl-dot { width: 8px; height: 8px; margin-top: 6px; flex: none; border-radius: 50%; background: var(--texto-tenue); }
.det-tl-item.det-tl-first .det-tl-dot { background: var(--acento-default); }
.det-tl-dot-im { background: var(--texto-tenue); }
.det-tl-texto { font-size: 13px; font-weight: 550; color: var(--texto-principal); }
.det-tl-tempo { font-size: 11.5px; margin-top: 1px; }
.det-tl-vazio { padding: 0 var(--espaco-xl) var(--espaco-lg); margin: 0; }
.det-tl-chip { display: inline-block; margin-left: 6px; font-size: 10.5px; font-weight: 600; background: var(--fundo-superficie-2); border: 1px solid var(--linha-default); border-radius: var(--raio-pilula); padding: 1px 8px; color: var(--texto-suave); }
.det-tl-desce .det-tl-texto { color: var(--semaforo-ok); font-weight: 620; }
.det-tl-auditoria { padding: 0 var(--espaco-xl) var(--espaco-lg); }
.det-tl-auditoria summary { font-size: 11.5px; font-weight: 600; color: var(--acento-default); cursor: pointer; }
.det-tl-auditoria table { margin-top: var(--espaco-md); }

.det-imovel-bloco { padding: 0 var(--espaco-xl) var(--espaco-lg); }
.det-imovel-bloco + .det-imovel-bloco { padding-top: var(--espaco-lg); border-top: 1px solid var(--linha-suave); }
.det-imovel-sub { font-size: 13px; color: var(--texto-suave); display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: var(--espaco-sm); }
.det-imovel-sub strong { color: var(--texto-principal); }
.det-imovel-vazio { padding: var(--espaco-lg) var(--espaco-xl); margin: 0; }
.det-tl-imovel { padding: var(--espaco-sm) 0 0; }
.det-sugestoes { padding: var(--espaco-lg) var(--espaco-xl); border-top: 1px solid var(--linha-suave); }
.det-sugestoes h4 { margin: 0 0 4px; font-size: 13px; }
.det-sugestoes-nota { margin: 0 0 var(--espaco-sm); font-size: 11.5px; }
.det-sugestoes ul { margin: 0; padding-left: 18px; font-size: 12.5px; }

/* Mercado: faixa «No mercado há N» (realce de 2026-08-12), agora no topo do
   bloco «Vida do imóvel» — a variante --observado (só visto_primeira_vez,
   sem data do portal) é deliberadamente mais neutra.
   Correção de 2026-08-13 (exercício de browser do Detalhe da Lead v2, tema
   escuro): o preenchimento total a --estado-proposta-fundo resolvia bem por
   token em cada tema, mas destoava dentro de um card escuro — mesmo padrão
   de `.mz-aviso`/`.tc-aviso` (borda esquerda de acento sobre
   --fundo-superficie-2 neutro) em vez de um bloco de cor cheio. Higiene
   2026-08-30: passou de --estado-proposta-* para --aviso-* (mesmos valores,
   token próprio — é aviso, não o estado «Com proposta»). */
.det-mercado {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px;
  background: var(--fundo-superficie-2);
  border-left: 3px solid var(--aviso-borda);
  border-radius: var(--raio-sm);
  padding: 10px 14px; margin: 0 0 var(--espaco-md);
  font-size: 13.5px; color: var(--texto-suave);
}
.det-mercado-tempo { font-weight: 680; font-size: 15px; color: var(--aviso-texto); }
.det-mercado--observado { border-left-color: var(--linha-default); }
.det-mercado--observado .det-mercado-tempo { color: var(--texto-principal); }

/* ---- Z4-A: anúncios ligados, cartões de grelha ---- */
.det-anuncios-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: var(--espaco-md); padding: var(--espaco-lg) var(--espaco-xl) var(--espaco-xl); }
.det-an { background: var(--fundo-superficie-2); border: 1px solid var(--linha-default); border-radius: var(--raio-md); padding: 14px 16px; font-size: 13px; }
.det-an-top { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.det-an-portal { font-weight: 620; color: var(--texto-principal); }
.det-an-ref { font-family: var(--font-num); font-size: 11px; color: var(--texto-tenue); }
.det-an-badge { margin-left: auto; font-size: 10.5px; font-weight: 700; border-radius: var(--raio-pilula); padding: 1px 9px; white-space: nowrap; }
.det-an-badge.ativo { color: var(--estado-entregue-texto); background: var(--estado-entregue-fundo); }
.det-an-badge.inativo { color: var(--texto-tenue); background: var(--fundo-superficie); }
/* Badge «Retirado do <Portal> · visto pela última vez dd/mm» (spec de
   2026-09-03-c21-lead-imovel-desaparecido §3.6): SÓ no bloco «Vida do
   imóvel». Reutiliza a base `.det-an-badge` — muda cor e o `margin-left`
   automático, que aqui empurraria os badges para a direita numa faixa
   própria em vez de os alinhar à esquerda uns a seguir aos outros. */
.det-an-badge.retirado { margin-left: 0; color: var(--estado-descartado-texto); background: var(--estado-descartado-fundo); font-weight: 620; }
.det-imovel-retirados { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
/* Pílula da marca no cabeçalho da ficha (§3.6): a mesma informação das
   listas do bloco B. `RETIRADO`/`FORA_TERRITORIO` em tom de alerta;
   `VOLTOU` é rasto de um episódio fechado (decisão 8) — neutro, nunca
   alarmante. */
.det-situacao { display: inline-flex; align-items: center; margin-left: 10px; font-size: 12px; font-weight: 620; border-radius: var(--raio-pilula); padding: 2px 10px; white-space: nowrap; vertical-align: middle; }
.det-situacao-retirado, .det-situacao-fora-territorio { color: var(--estado-descartado-texto); background: var(--estado-descartado-fundo); }
.det-situacao-voltou { color: var(--texto-suave); background: var(--fundo-superficie-2); }
.det-an-tit { color: var(--texto-suave); }
.det-an-tit a { color: inherit; }
.det-an-preco { font-weight: 680; font-variant-numeric: tabular-nums; margin-top: 6px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.det-an-var { font-size: 11.5px; font-weight: 600; color: var(--semaforo-ok); }
.det-an-meta { font-size: 11.5px; margin-top: 6px; }
.det-an-ligado { font-size: 11px; margin-top: 8px; }
.det-an-ligado b { color: var(--texto-principal); font-weight: 620; }
.det-an-historico { margin-top: 8px; }
.det-an-historico summary { font-size: 11.5px; font-weight: 600; color: var(--acento-default); cursor: pointer; }
.det-an-historico table { margin-top: 8px; }

/* ---------- .ml- (As minhas leads) ---------- */

.ml-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--espaco-lg); }
@media (max-width: 900px) { .ml-grid { grid-template-columns: 1fr; } }
.ml-vazio { grid-column: 1 / -1; }

.ml-card {
  background: var(--fundo-superficie);
  border: 1px solid var(--linha-default);
  border-radius: var(--raio-lg);
  box-shadow: var(--shadow);
  padding: var(--espaco-lg) var(--espaco-xl);
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* Leads em NOVO: borda acentuada (Figma) — reusa o mesmo par cor/sombra do
   tile/tab ativos, nunca um azul novo. */
.ml-card.is-novo { border-color: var(--acento-default); box-shadow: 0 0 0 1px var(--acento-default) inset, var(--shadow); }
.ml-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.ml-titulo { font-size: 14.5px; font-weight: 630; color: var(--texto-principal); }
.ml-sub { font-size: 12.5px; color: var(--texto-suave); margin-top: 2px; }
.ml-contexto { font-size: 12.5px; color: var(--texto-tenue); }
.ml-acoes { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 2px; }
.ml-acoes [role="button"], .ml-acoes button { font-size: 12.5px; padding: 8px 14px; }
.ml-btn-whatsapp { background: var(--estado-entregue-fundo); color: var(--estado-entregue-texto); border-color: var(--estado-entregue-fundo); }
.ml-pag .pag-btn { border-radius: var(--raio-pilula); padding: 8px 16px; }

/* ---------- Gestão (fase 5, lote B) — Contas, Agências, Mover zona,
   Transferir carteira, seletor de zona ------------------------------------
   Re-pele das páginas de Gestão (design v1 aprovado no Figma). Os `<style>`
   locais que estas páginas tinham (agencia_form, mover_zona,
   transferir_carteira, _seletor_zona) mudam-se para aqui, com os prefixos que
   os templates já usavam (.mz-/.tc-/.z-) — só o território da agência, que
   usava `.t-`, passa a `.ges-t-` (a agência não tinha prefixo dedicado; entra
   na família geral `.ges-` desta secção). */

/* --- chip de freguesia, partilhado por .z- (conta), .mz- (mover zona) e
   .ges-t- (território de agência): três árvores estruturalmente idênticas,
   um único par de regras. O `:has()` troca o visual ao marcar/desmarcar SEM
   UMA linha de JS novo — o mesmo recurso que já sustenta
   `label:has(> input[type="checkbox"])` em base.css. O checkbox nativo fica
   visualmente escondido (técnica «sr-only»: continua no DOM, continua a
   receber foco/tab, só não ocupa espaço) — o que se vê é só o fundo do chip e
   o anel de foco.

   As duas primeiras regras (com `:has(> input...)` repetido) existem para
   ganhar a especificidade a `label:has(> input[type="checkbox"])` de
   base.css (0,1,2): sem isso, o `display:flex` genérico dessa regra vencia o
   `inline-flex` daqui e os chips empilhavam a toda a largura em vez de fluir
   em linha. */
.chip-freguesia,
label.chip-freguesia:has(> input[type="checkbox"]) {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0;
  padding: 6px 12px;
  margin: 0;
  border: 1px solid var(--linha-default);
  border-radius: var(--raio-pilula);
  background: var(--fundo-superficie);
  color: var(--texto-principal);
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.2;
  cursor: pointer;
  transition: background .12s, border-color .12s, color .12s;
}
.chip-freguesia:hover { border-color: var(--acento-default); }
.chip-freguesia input[type="checkbox"] {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.chip-freguesia:has(input:checked) {
  background: var(--acento-default);
  border-color: var(--acento-default);
  color: var(--acento-contraste);
}
.chip-freguesia:has(input:focus-visible) { outline: 2px solid var(--acento-default); outline-offset: 2px; }
/* Rede de segurança para browsers sem :has() (achado da revisão do lote B):
   sem isto, o checkbox estava sr-only e o estado marcado era invisível — o
   utilizador não conseguia VER a seleção da zona. Com :has() indisponível,
   o checkbox nativo volta a mostrar-se dentro do chip. */
@supports not selector(:has(a)) {
  .chip-freguesia input[type="checkbox"] {
    position: static;
    width: auto; height: auto;
    margin: 0 6px 0 0;
    clip: auto;
    overflow: visible;
  }
}

/* --- .ges- : Contas & equipas, Agências --------------------------------- */
.ges-form-duas-colunas { display: grid; grid-template-columns: minmax(280px, 400px) 1fr; gap: var(--espaco-lg); align-items: start; }
@media (max-width: 900px) { .ges-form-duas-colunas { grid-template-columns: 1fr; } }

.ges-card-pad { padding: var(--espaco-xl); }
.ges-card-pad > h2:first-child { margin-top: 0; }

.ges-static { margin-bottom: var(--espaco-md); }
.ges-static label { margin-bottom: 2px; }
.ges-static p { margin: 0 0 var(--espaco-md); font-size: 14px; color: var(--texto-principal); }

/* Nota discreta sob um campo — mesmo padrão do `.mz-nota`/`.tc-nota`.
   Não reutiliza `.hint`: é `display:flex; gap:8px` (pensada para ícone +
   texto) e cada `<b>` passaria a item de flex, com buraco de 8px de cada
   lado — o mesmo defeito já documentado nas páginas de mover zona e
   transferência de carteira. */
.ges-nota { margin-top: 14px; font-size: 12.5px; color: var(--texto-tenue); }
.ges-nota b { color: var(--texto-suave); font-weight: 640; }

.ges-campo-nome { max-width: 28rem; }

/* Linha «avatar + nome/email» na tabela de contas. */
.ges-conta { display: flex; align-items: center; gap: 10px; }
.ges-conta .avatar { width: 34px; height: 34px; font-size: 12px; flex: none; }
.ges-conta-info { line-height: 1.3; overflow: hidden; }
.ges-conta-info b { display: block; font-size: 13px; font-weight: 620; color: var(--texto-principal); }
.ges-conta-info span { font-size: 11.5px; color: var(--texto-tenue); }
.ges-desativada { margin-left: 6px; font-size: 10.5px; font-weight: 650; color: var(--semaforo-perigo); text-transform: uppercase; letter-spacing: .03em; }

.ges-chip-papel {
  display: inline-block; font-size: 10.5px; font-weight: 650;
  letter-spacing: .04em; text-transform: uppercase;
  color: var(--texto-suave); background: var(--fundo-superficie-2);
  border: 1px solid var(--linha-default); border-radius: var(--raio-sm);
  padding: 3px 8px;
}

.ges-sem-zona { color: var(--semaforo-perigo); font-weight: 600; }

.ges-adesoes { display: flex; flex-direction: column; gap: 6px; }
.ges-adesao-linha { display: flex; flex-direction: column; gap: 1px; }
.ges-adesao-linha .muted { font-size: 11px; }

.ges-acoes { display: flex; gap: 6px; flex-wrap: wrap; }
/* Ação primária de linha (Editar): pílula com o acento, mais discreta do que
   o botão cheio — a tabela é densa e várias pílulas cheias competiam entre
   si. Reutiliza `.pag-btn` (já existente) como base. */
.pag-btn.ges-acao-primaria { background: var(--acento-suave); border-color: transparent; color: var(--acento-default); }
.pag-btn.ges-acao-primaria:hover { background: var(--acento-suave); border-color: var(--acento-default); }

/* Território da agência (agencia_form.html) — mesma árvore distrito → concelho
   → freguesia que `.z-`/`.mz-` abaixo, prefixo `.ges-t-` por não ter prefixo
   próprio antes do redesenho. */
.ges-t-distrito { margin: 0 0 1rem 0; padding: 0; border: 0; }
.ges-t-distrito-head { display: flex; align-items: center; gap: .4rem; margin: 0 0 .4rem 0; }
.ges-t-concelhos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: .75rem;
  padding-left: 1rem;
}
.ges-t-concelho { margin: 0; padding: .5rem .6rem; border: 1px solid var(--linha-default); border-radius: .4rem; }
.ges-t-concelho-head { display: flex; align-items: center; gap: .4rem; margin: 0 0 .3rem 0; font-weight: 600; }
.ges-t-freguesias { display: flex; flex-wrap: wrap; gap: 6px; max-height: 14rem; overflow-y: auto; padding: 2px; }
.ges-t-freguesias input, .ges-t-concelho-head input, .ges-t-distrito-head input { margin: 0; }

/* --- .z- : seletor de zona da conta (_seletor_zona.html) ----------------- */
.z-distrito { margin: 0 0 1rem 0; padding: 0; border: 0; }
.z-distrito-head { display: flex; align-items: center; gap: .4rem; margin: 0 0 .4rem 0; }
.z-concelhos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: .75rem;
  padding-left: 1rem;
}
/* Dívida registada duas vezes (2026-08-12): `var(--muted-border-color)` é o
   nome do Pico v1 — o classless vendorizado nunca definiu essa custom
   property sem o prefixo `--pico-`, por isso a borda caía em `currentColor`.
   Token novo: `--linha-default`. */
.z-concelho { margin: 0; padding: .5rem .6rem; border: 1px solid var(--linha-default); border-radius: .4rem; }
.z-concelho-head { display: flex; align-items: center; gap: .4rem; margin: 0 0 .3rem 0; font-weight: 600; }
.z-freguesias { display: flex; flex-wrap: wrap; gap: 6px; max-height: 14rem; overflow-y: auto; padding: 2px; }
.z-freguesias input, .z-concelho-head input, .z-distrito-head input { margin: 0; }

/* --- .mz- : mover a zona (mover_zona.html) -------------------------------- */
.mz-cab { display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem 1.2rem; }
.mz-cab .val { font-size: 22px; font-weight: 680; font-family: var(--font-num); }
.mz-nota { margin-top: 14px; font-size: 12.5px; color: var(--texto-tenue); }
.mz-nota b { color: var(--texto-suave); font-weight: 640; }
.mz-destino { max-width: 32rem; }
.mz-aviso {
  border-left: 3px solid var(--aviso-borda);
  background: var(--fundo-superficie-2);
  padding: .6rem .9rem;
  border-radius: .3rem;
  margin: .8rem 0;
  font-size: 13px;
}
.mz-aviso b { font-weight: 640; }
.mz-barra { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; margin: 1rem 0; }
.mz-distrito { margin: 0 0 1rem 0; padding: 0; border: 0; }
.mz-distrito-head { display: flex; align-items: center; gap: .4rem; margin: 0 0 .4rem 0; }
.mz-concelhos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: .75rem;
  padding-left: 1rem;
}
/* Mesma dívida do `.z-concelho` acima — corrigida aqui também. */
.mz-concelho { margin: 0; padding: .5rem .6rem; border: 1px solid var(--linha-default); border-radius: .4rem; }
.mz-concelho-head { display: flex; align-items: center; gap: .4rem; margin: 0 0 .3rem 0; font-weight: 600; }
.mz-freguesias { display: flex; flex-wrap: wrap; gap: 6px; max-height: 14rem; overflow-y: auto; padding: 2px; }
.mz-freguesias input, .mz-concelho-head input, .mz-distrito-head input { margin: 0; }

/* --- .tc- : transferir carteira (transferir_carteira.html) ---------------- */
.tc-cab { display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem 1.2rem; }
.tc-cab .val { font-size: 22px; font-weight: 680; font-family: var(--font-num); }
.tc-nota { margin-top: 14px; font-size: 12.5px; color: var(--texto-tenue); }
.tc-nota b { color: var(--texto-suave); font-weight: 640; }
.tc-destino { max-width: 32rem; }
.tc-aviso {
  border-left: 3px solid var(--aviso-borda);
  background: var(--fundo-superficie-2);
  padding: .6rem .9rem;
  border-radius: .3rem;
  margin: .8rem 0;
  font-size: 13px;
}
.tc-aviso b { font-weight: 640; }
.tc-tabela td.marca, .tc-tabela th.marca { width: 2.5rem; text-align: center; }
.tc-barra { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; margin: 1rem 0; }

/* --- .vc- : banner do modo «ver como» (base.html, spec 2026-08-30) --------
   Faixa de largura total entre a .topbar e a .content (fora do scroll —
   permanente enquanto o modo está ativo). Mesmo padrão de acento do
   .mz-aviso/.tc-aviso (borda + fundo do token de aviso), mas em faixa e mais
   forte (cor do texto também no token de aviso, não só a borda) — o Sair tem
   de ser impossível de não ver. Tokens de aviso próprios (higiene
   2026-08-30) — eram --estado-proposta-*, mesmos valores. */
.vc-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .5rem 1rem;
  padding: .5rem 1.2rem;
  border-bottom: 3px solid var(--semaforo-perigo);
  background: var(--aviso-fundo);
  color: var(--aviso-texto);
  font-size: 13px;
  font-weight: 600;
}
.vc-banner b { font-weight: 700; }
.vc-banner form { margin: 0; }
.vc-banner button {
  border: 1px solid var(--semaforo-perigo);
  background: transparent;
  color: var(--semaforo-perigo);
  border-radius: var(--raio-pilula);
  padding: .25rem .9rem;
  font-size: 12.5px;
  font-weight: 650;
  cursor: pointer;
}
.vc-banner button:hover { background: var(--semaforo-perigo); color: var(--fundo-superficie); }

/* ================================================================
   Painel técnico · Rasto · Fusões · Agendamentos · A minha mensagem
   (fase 5, lote C). Prefixos .tec- / .fus- / .agd- / .msg-. Re-pele
   só — nenhuma classe aqui muda comportamento (forms/urls/hx-* ficam
   exatamente como estavam nos templates).
   ================================================================ */

/* ---------- Painel técnico: tabs por âncoras --------------------------- */
/* Barra sticky em pílulas que faz scroll para as secções (`.tec-section`);
   NÃO esconde nada por :target — ver a nota no template sobre a armadilha
   de um POST/redirect sem fragment deixar a página vazia. */
.tec-tabs {
  position: sticky; top: 0; z-index: 5;
  display: flex; flex-wrap: wrap; gap: 6px;
  background: var(--fundo-pagina);
  padding: 10px 0 16px;
}
.tec-tab {
  font-size: 12.5px; font-weight: 600; color: var(--texto-suave); text-decoration: none;
  background: var(--fundo-superficie); border: 1px solid var(--linha-default);
  border-radius: var(--raio-pilula); padding: 7px 15px; white-space: nowrap;
  transition: background .12s, border-color .12s, color .12s;
}
.tec-tab:hover { border-color: var(--acento-default); color: var(--acento-default); text-decoration: none; }

/* scroll-margin-top compensa a barra sticky ao saltar para a âncora. */
.tec-section { scroll-margin-top: 64px; margin-bottom: var(--espaco-2xl); }
.tec-section .card:last-child { margin-bottom: 0; }
.tec-card-body { padding: var(--espaco-lg) var(--espaco-xl) var(--espaco-xl); }
.tec-card-body table { margin-top: var(--espaco-sm); }

/* Form de lançar varrimento: linha em vez do `.grid` do Pico (já não existe
   nesta base) — os dois selects lado a lado, o botão alinhado ao fundo. */
.tec-form-row { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--espaco-md); margin: 0 0 var(--espaco-md); }
.tec-form-row label { flex: 1 1 200px; margin: 0; }
.tec-form-row select { margin: 0; }
.tec-form-row button { flex: none; }
.tec-form-secundario { margin: 0; }

/* Saúde por portal: cartões (mock) em vez da tabela original — mesmos dados
   (`saude` do contexto), mesmos forms/urls de disjuntor e toggle de portal. */
.tec-saude-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--espaco-lg); padding: var(--espaco-lg) var(--espaco-xl) var(--espaco-xl);
}
.tec-saude-card {
  background: var(--fundo-superficie-2); border: 1px solid var(--linha-default);
  border-radius: var(--raio-md); padding: var(--espaco-lg);
}
.tec-saude-head { display: flex; align-items: center; justify-content: space-between; gap: var(--espaco-sm); margin-bottom: 4px; }
.tec-saude-linha { margin: 0 0 6px; font-size: 12.5px; }
.tec-saude-form { margin: 8px 0 0; }
.tec-saude-form button { padding: 6px 13px; font-size: 12.5px; }

.tec-chip { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; font-weight: 620; padding: 3px 9px 3px 8px; border-radius: var(--raio-pilula); white-space: nowrap; }
.tec-chip::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.tec-chip-ok { color: var(--semaforo-ok); background: var(--estado-entregue-fundo); }
.tec-chip-perigo { color: var(--semaforo-perigo); background: var(--estado-descartado-fundo); }
.tec-chip-aviso { color: var(--aviso-texto); background: var(--aviso-fundo); }
.tec-chip-inativo { color: var(--texto-tenue); background: var(--fundo-superficie); }

/* Concelhos com varrimento ativo — grade de checkboxes por distrito (era
   `.concelhos-grid`/`.concelhos-distrito` no <style> local do template). */
.tec-concelhos-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--espaco-lg); margin: 0 0 var(--espaco-lg); }
.tec-concelhos-distrito { margin: 0; padding: 0; border: 0; }
.tec-concelhos-distrito h4 { margin: 0 0 6px; font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: var(--texto-tenue); font-weight: 620; }
.tec-concelhos-distrito label { display: flex; align-items: center; gap: 8px; margin: 0 0 4px; font-size: 13px; font-weight: 450; }
.tec-concelhos-distrito input[type="checkbox"] { margin: 0; }
.tec-concelhos-guardar { margin-top: var(--espaco-sm); }

/* «Localizações por mapear» (fechado por defeito) e «Grupos repartidos»
   (aberto): era `details.mapeamento` no <style> local. Os grupos repartidos
   vêm alinhados ao topo — um grupo com muitas leads presas faz uma linha
   alta, e ao centro (o default de `.card tbody td`) o id do portal e os
   donos ficavam a meio da lista, fora do ecrã. */
.tec-mapeamento { margin: 0 0 var(--espaco-md); }
.tec-mapeamento:last-child { margin-bottom: 0; }
table.tec-repartidos td { vertical-align: top; }
.tec-repartido-lista { margin: 0; padding-left: 1.1em; font-size: .9em; }
.tec-repartido-lista li { line-height: 1.5; margin-bottom: 0; }

/* ---------- Fusões de imóveis ------------------------------------------- */
.fus-card { margin-bottom: var(--espaco-lg); }
.fus-par { display: grid; grid-template-columns: 1fr 1fr; gap: var(--espaco-lg); padding: var(--espaco-xl) var(--espaco-xl) var(--espaco-md); }
.fus-par > div { background: var(--fundo-superficie-2); border: 1px solid var(--linha-default); border-radius: var(--raio-md); padding: var(--espaco-lg); }
.fus-par h3 { margin: 0 0 8px; font-size: 14px; }
.fus-par ul { margin: 0; padding-left: 1.1em; font-size: 12.5px; color: var(--texto-suave); }
.fus-par li { margin-bottom: 4px; }
@media (max-width: 700px) { .fus-par { grid-template-columns: 1fr; } }

.fus-porque { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 0 var(--espaco-xl) var(--espaco-lg); }
.fus-porque-label { font-size: 12px; color: var(--texto-tenue); }
.fus-chip {
  font-size: 11.5px; font-weight: 600; color: var(--texto-suave);
  background: var(--fundo-superficie-2); border: 1px solid var(--linha-default);
  border-radius: var(--raio-pilula); padding: 3px 10px;
}
/* I7 da revisão da B4: aviso «toca leads ativas» no card-head da lista —
   tokens --aviso-* (mesmo âmbar do resto da casa), nunca uma cor nova. */
.fus-chip-leads { color: var(--aviso-texto); background: var(--aviso-fundo); border-color: var(--aviso-borda); }

.fus-acoes { display: flex; gap: 10px; padding: 0 var(--espaco-xl) var(--espaco-xl); margin: 0; }
/* Verde/vermelho suave (tokens de estado já existentes — entregue/descartado). */
.fus-btn-aceitar { background: var(--estado-entregue-fundo); color: var(--estado-entregue-texto); border-color: var(--estado-entregue-fundo); }
.fus-btn-aceitar:hover { opacity: .85; }
.fus-btn-recusar { background: var(--estado-descartado-fundo); color: var(--estado-descartado-texto); border-color: var(--estado-descartado-fundo); }
.fus-btn-recusar:hover { opacity: .85; }

/* ---------- Fusões de imóveis: passo de arbitragem (spec B4 §2, mock 174:3)
   Botões: os DEFAULT da base (`button` = primário azul; `.secondary.outline`
   = "Cancelar") — nenhuma classe nova de botão, só o layout dos dois
   cartões e o destaque do escolhido, pelo mesmo `:has()` já usado em
   `.chip-freguesia` acima (sem JS).
   Estrutura (nit N5 da revisão): o CARTÃO é um `<div>`, não um `<label>` —
   `{% chip_estado %}` (gate `test_nenhum_template_renderiza_um_chip_de_
   estado_cru`, TODOS os chips passam pela tag, sem exceção) traz o seu
   próprio glossário interativo, e um clique nele dentro de um `<label>`
   marcava o rádio por engano. O gesto de escolha vive só em `.fus-arb-
   escolher` (rádio + título) — daí não precisar do truque de
   especificidade `label.X:has(> input)` que `.chip-freguesia` usa: não há
   conflito nenhum a resolver aqui, o `<label>` é mesmo pequeno. */
.fus-arb-par { display: grid; grid-template-columns: 1fr 1fr; gap: var(--espaco-lg); margin: var(--espaco-lg) 0; }
@media (max-width: 700px) { .fus-arb-par { grid-template-columns: 1fr; } }
.fus-arb-cartao {
  display: flex; flex-direction: column; gap: var(--espaco-sm);
  background: var(--fundo-superficie); border: 1px solid var(--linha-default);
  border-radius: var(--raio-md); padding: var(--espaco-lg);
  transition: border-color .12s, box-shadow .12s;
}
.fus-arb-cartao:has(input:checked) { border-color: var(--acento-default); box-shadow: 0 0 0 1px var(--acento-default) inset; }
/* `label:has(> input[type="radio"])` de base.css (0,1,2) ainda vence uma
   `.fus-arb-escolher` sozinha (0,1,0) no `gap` — mesmo truque de
   especificidade do `.chip-freguesia`, só que aqui o ganho é cosmético
   (gap correto, não um `align-items` errado). */
.fus-arb-escolher,
label.fus-arb-escolher:has(> input[type="radio"]) {
  display: flex; align-items: center; gap: var(--espaco-sm); cursor: pointer; margin: 0;
}
.fus-arb-escolher:hover .fus-arb-titulo { color: var(--acento-default); }
.fus-arb-radio { margin-top: 0; flex: none; }
.fus-arb-cartao-corpo { display: flex; flex-direction: column; gap: 4px; font-size: 13px; }
.fus-arb-titulo { font-size: 15px; }
.fus-arb-linha { color: var(--texto-suave); }
.fus-arb-acoes { display: flex; gap: 10px; align-items: center; }
.fus-arb-nota { margin: var(--espaco-sm) 0 0; font-size: 12px; }

/* ---------- Agendamentos ------------------------------------------------- */
.agd-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: var(--espaco-lg); }
.agd-card {
  background: var(--fundo-superficie); border: 1px solid var(--linha-default);
  border-radius: var(--raio-lg); box-shadow: var(--shadow); padding: var(--espaco-xl);
}
.agd-card-head { display: flex; align-items: center; justify-content: space-between; gap: var(--espaco-sm); margin-bottom: 4px; }
.agd-card-head strong { font-size: 15px; font-weight: 620; }
.agd-descricao { color: var(--texto-suave); font-size: 12.5px; margin: 0 0 var(--espaco-lg); }
.agd-card form { margin: 0; }
.agd-linha { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-bottom: var(--espaco-md); }
.agd-linha select { width: auto; margin: 0; }
.agd-interruptor { display: flex; align-items: center; gap: 8px; margin: 0 0 var(--espaco-md); font-weight: 550; }
.agd-nota { font-size: 12px; color: var(--texto-tenue); margin: 4px 0 var(--espaco-md); }
.agd-meta { font-size: 12px; color: var(--texto-tenue); margin: 0 0 var(--espaco-md); }

/* Chip de estado: reaproveita a família de tokens de aviso (era
   `background: var(--pico-mark-background-color, #f2e5b5)` — o fallback
   hardcoded deixou de fazer sentido sem o Pico). Tokens próprios (--aviso-*)
   desde a higiene de 2026-08-30 — mesmos valores de --estado-proposta-*. */
.agd-badge { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 620; text-transform: uppercase; letter-spacing: .03em; padding: 3px 10px 3px 9px; border-radius: var(--raio-pilula); white-space: nowrap; }
.agd-badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.agd-badge-aviso { color: var(--aviso-texto); background: var(--aviso-fundo); }
.agd-badge-ok { color: var(--semaforo-ok); background: var(--estado-entregue-fundo); }
.agd-badge-off { color: var(--texto-tenue); background: var(--fundo-superficie-2); }
.agd-foot { margin-top: var(--espaco-lg); font-size: 12.5px; color: var(--texto-suave); }

/* ---------- A minha mensagem --------------------------------------------- */
.msg-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--espaco-lg); align-items: start; }
@media (max-width: 900px) { .msg-grid { grid-template-columns: 1fr; } }
.msg-body { padding: var(--espaco-lg) var(--espaco-xl) var(--espaco-xl); }
.msg-body textarea { min-height: 130px; }
.msg-variaveis { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin: -4px 0 var(--espaco-md); }
.msg-variaveis-label { font-size: 12px; color: var(--texto-tenue); }
.msg-chip { font-family: var(--font-num); font-size: 11.5px; font-weight: 600; color: var(--acento-default); background: var(--acento-suave); border-radius: var(--raio-pilula); padding: 3px 10px; }
.msg-ajuda { font-size: 12px; color: var(--texto-tenue); margin: 0 0 var(--espaco-lg); }
.msg-acoes { display: flex; gap: 10px; }
/* Bolha estilo WhatsApp: fundo verde suave (token de estado «entregue»), um
   canto reto a lembrar a seta do balão de conversa. */
.msg-bolha {
  background: var(--estado-entregue-fundo); color: var(--texto-principal);
  border-radius: var(--raio-md) var(--raio-md) var(--raio-md) 4px;
  padding: var(--espaco-md) var(--espaco-lg); font-size: 13.5px; line-height: 1.5;
  white-space: pre-wrap;
}
.msg-exemplo { margin: 0 0 var(--espaco-md); font-size: 12px; }

/* ---------- Agendamentos — afinação à densidade do mock (Figma) ----------
   Substitui a grelha de cartões gordos por linhas-cartão horizontais e
   densas. Reaproveita os seletores .agd-badge / .agd-descricao / .agd-linha /
   .agd-interruptor / .agd-nota / .agd-meta já definidos acima (mesma
   especificidade — a cascata dá a estas regras, por virem depois no
   ficheiro, a palavra final); as antigas .agd-grid / .agd-card / .agd-card-head
   ficam por usar neste template mas não se tocam, por serem só acrescentos
   no fim. */
.agd-lista { display: flex; flex-direction: column; gap: var(--espaco-sm); }

.agd-item {
  background: var(--fundo-superficie); border: 1px solid var(--linha-default);
  border-radius: var(--raio-md); box-shadow: var(--shadow);
  padding: var(--espaco-sm) var(--espaco-lg);
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--espaco-xs) var(--espaco-xl);
}

.agd-item-info { flex: 1 1 220px; min-width: 200px; }
.agd-item-titulo { display: flex; align-items: center; gap: var(--espaco-sm); }
.agd-item-titulo strong { font-size: 14px; font-weight: 620; }
.agd-descricao { margin: 1px 0 0; }

.agd-item-form { flex: 2 1 440px; margin: 0; }
.agd-item-controlos { display: flex; flex-wrap: wrap; align-items: center; gap: var(--espaco-xs) var(--espaco-lg); }
.agd-interruptor { margin: 0; font-weight: 500; }
.agd-linha { margin: 0; }
.agd-nota-fixa { margin: 0; }
.agd-meta { margin: 0; white-space: nowrap; }
.agd-item-form > .agd-nota { margin: 4px 0 0; }

.agd-guardar { margin-left: auto; padding: 6px 16px; font-size: 13px; }

@media (max-width: 900px) {
  .agd-item { flex-direction: column; align-items: stretch; }
  .agd-guardar { margin-left: 0; }
}
/* ============================================================================
   Bolsa: linha imóvel-cêntrica (re-pele aprovada 2026-08-12, mock Figma).
   Colunas viram Imóvel/Preço/Portal/Estado/Consultor/Ações — uma linha
   continua a ser uma lead, só a identidade visual muda para o anúncio
   representativo. Só acrescentos, prefixo .bl- (já usado pelo lote A).
   ============================================================================ */

/* Título a negrito (o próprio <b> já basta; a regra só afina a cor para o
   token de texto principal, igual ao resto da tabela). */
.bl-imovel b { color: var(--texto-principal); }
/* Subtítulo: concelho · telefone mascarado · "atual. há N dias" (+ outros
   anúncios), com os badges (.badge-investiu/.badge-grupo, tal e qual) a
   seguir — inline, como já eram na tabela anterior. */
.bl-sub { margin-top: 3px; font-size: 12px; color: var(--texto-tenue); }
.bl-preco { font-family: var(--font-num); font-variant-numeric: tabular-nums; font-weight: 620; white-space: nowrap; color: var(--texto-principal); }
/* Botão «Abrir» (Ações): reutiliza .pag-btn (base.css) — só o raio muda para
   pílula dentro da tabela da bolsa, o mesmo truque de .bl-pag .pag-btn acima
   para a paginação. */
.bl-tabela .bl-acoes .pag-btn { border-radius: var(--raio-pilula); padding: 8px 16px; }

/* ============================================================================
   Perfil próprio (frente PERFIL, 2026-08-12): drawer no rodapé da sidebar
   («Editar perfil» / «Sair») + página /perfil/. Só acrescentos, prefixo
   .perfil-.
   ============================================================================ */

/* Drawer do rodapé: <details class="perfil-menu"> — o <summary> reaproveita
   .avatar/.who tal e qual (sem classe nova nesses dois). O menu abre PARA
   CIMA (bottom: 100%): o rodapé é o último elemento da sidebar, não há
   espaço por baixo. */
.perfil-menu { position: relative; width: 100%; }
.perfil-menu-toggle {
  display: flex; align-items: center; gap: 10px; cursor: pointer;
  list-style: none; padding: 4px; margin: -4px; border-radius: var(--raio-md);
  -webkit-tap-highlight-color: transparent;
}
.perfil-menu-toggle::-webkit-details-marker { display: none; }
.perfil-menu-toggle:hover, .perfil-menu[open] .perfil-menu-toggle { background: var(--fundo-superficie-2); }
.perfil-menu-toggle:focus-visible { outline: 2px solid var(--acento-default); outline-offset: 2px; }

/* .sidebar tem overflow:hidden (é o que trava o resto do scroll) — sem esta
   classe o menu, que é position:absolute dentro dela, ficaria clipado.
   perfil-menu.js liga/desliga .perfil-aberto ao abrir/fechar o <details>. */
.sidebar.perfil-aberto { overflow: visible; }

.perfil-menu-painel {
  position: absolute; bottom: calc(100% + 8px); left: 0; z-index: 50;
  min-width: 200px; display: flex; flex-direction: column; gap: 2px;
  padding: 6px; background: var(--fundo-superficie);
  border: 1px solid var(--linha-default); border-radius: var(--raio-md);
  box-shadow: var(--shadow);
}
.perfil-menu-painel a, .perfil-menu-painel button {
  display: block; width: 100%; text-align: left; padding: 8px 10px;
  border: none; border-radius: var(--raio-sm); background: transparent;
  color: var(--texto-principal); font-family: inherit; font-size: 13px;
  font-weight: 500; text-decoration: none; cursor: pointer;
}
.perfil-menu-painel a:hover, .perfil-menu-painel button:hover { background: var(--fundo-superficie-2); }
.perfil-menu-painel form { margin: 0; }
.app.rail .perfil-menu-painel { left: -4px; }

/* Página /perfil/: cartões empilhados, largura de leitura (não a largura toda
   do conteúdo — é um formulário curto, não uma tabela). */
.perfil-pilha { display: flex; flex-direction: column; gap: var(--espaco-lg); max-width: 520px; }
.perfil-pilha .card > p:last-child { margin-bottom: 0; }

/* ============================================================================
   Painel técnico: tabs a sério + Visão geral (mock Figma 2026-08-12, lote D).
   As regras `.tec-*` mais acima (tabs por âncoras, saúde por portal,
   concelhos, mapeamentos) continuam a servir a pele destas secções, só
   reorganizadas por `tecnico.html`/`tecnico_rasto.html` — aqui só o que é
   mesmo novo: a tab ativa e o layout da Visão geral/Concelhos.
   ============================================================================ */

/* Tab ativa (`tecnico-tabs.js` alterna a classe; na página do rasto o
   servidor marca-a via `tab_ativa`): mesma pílula da sidebar
   (`.navlink.active`) — fundo --acento-suave, texto na cor de acento. Sem
   JS nenhuma tab fica marcada — progressive enhancement, a barra continua a
   funcionar como âncoras simples. */
.tec-tab.active { background: var(--acento-suave); border-color: transparent; color: var(--acento-default); }
.tec-tab.active:hover { color: var(--acento-default); }

/* Visão geral: «Execuções recentes» e «Funil da última noite» lado a lado
   (2fr/1fr, como o mock); a Saúde por portal fica de largura total acima. */
.tec-visao-grid { display: grid; grid-template-columns: 2fr 1fr; gap: var(--espaco-lg); align-items: start; }
@media (max-width: 900px) { .tec-visao-grid { grid-template-columns: 1fr; } }

/* «Ver todas →» no cabeçalho do cartão de execuções recentes — mesmo padrão
   do `.ini-link` do Início. */
.tec-ver-todas { margin-left: auto; font-size: 12.5px; font-weight: 600; color: var(--acento-default); text-decoration: none; white-space: nowrap; }
.tec-ver-todas:hover { text-decoration: underline; }

/* Funil da última noite: lista label/valor, número alinhado à direita. */
.tec-funil-noite-lista { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--espaco-sm); }
.tec-funil-noite-lista li { display: flex; align-items: baseline; justify-content: space-between; gap: var(--espaco-md); font-size: 13px; color: var(--texto-suave); }
.tec-funil-noite-lista strong { font-family: var(--font-num); font-variant-numeric: tabular-nums; color: var(--texto-principal); }
.tec-funil-noite-nota { margin: var(--espaco-md) 0 0; font-size: 11.5px; }
/* Duas filas «Varrimento»/«Revisita» dentro do mesmo card (spec de
   2026-09-03) — mesmo rótulo pequeno do `.ini-varrimento-fila-rotulo`. */
.tec-funil-noite-rotulo { margin: var(--espaco-md) 0 var(--espaco-sm); font-size: 10.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; }
.tec-funil-noite-rotulo:first-child { margin-top: 0; }

/* Tab «Portais» (secção própria desde 2026-08-12, antes vivia dentro de
   Concelhos): «Portais ativos» — grade de cartões compacta (nome + estado +
   toggle), o mesmo toggle que morava na Saúde por portal antes desta
   re-pele. */
.tec-portais-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--espaco-md); }
.tec-portais-item { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; background: var(--fundo-superficie-2); border: 1px solid var(--linha-default); border-radius: var(--raio-md); padding: var(--espaco-md) var(--espaco-lg); }
.tec-portais-item form { margin: 0; }

/* ---------- Início v2 (frame Figma aprovado 2026-08-12, ADMIN/COORDENADOR):
   sparkline do tile "Leads novas", tile "1.º contacto (mediana)", órfãs no
   tile "Por contactar", cartão Funil do mês, cartão Sinais de angariação,
   equipa com badge "parado"/link "N por contactar" e Precisa de ação com
   "A apodrecer no funil" + rodapé de opt-outs. Só tokens — zero hex; o
   sparkline usa --acento-default (regra da spec). ---------- */

/* Tile "Leads novas": número + sparkline lado a lado. */
.ini-tile-num-spark { display: flex; align-items: center; gap: var(--espaco-md); margin-top: 8px; }
.ini-tile-num-spark .val { margin-top: 0; }
.ini-spark { width: 72px; height: 28px; flex: none; }

/* Sub-linha âmbar (órfãs no tile "Por contactar"): mesma família de tokens
   de aviso já usada em `.tec-chip-aviso`/`.agd-badge-aviso`. */
.ini-sub-aviso a { color: var(--aviso-texto); text-decoration: none; font-weight: 600; }
.ini-sub-aviso a:hover { text-decoration: underline; }

/* Cartão "Funil do mês": 6 colunas, barra com trilho cinza e preenchimento
   proporcional ao 1.º degrau (altura calculada no template via `widthratio`
   — sem JS). */
.ini-funil-corpo { display: grid; grid-template-columns: repeat(6, 1fr); gap: var(--espaco-md); padding: var(--espaco-lg) var(--espaco-xl) var(--espaco-md); }
.ini-funil-col { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.ini-funil-num { font-family: var(--font-num); font-variant-numeric: tabular-nums; font-size: 15px; font-weight: 660; color: var(--texto-principal); }
.ini-funil-barra-track { width: 100%; height: 96px; background: var(--fundo-superficie-2); border-radius: var(--raio-sm); display: flex; align-items: flex-end; overflow: hidden; }
.ini-funil-barra-fill { width: 100%; height: 0; background: var(--acento-default); border-radius: var(--raio-sm) var(--raio-sm) 0 0; }
.ini-funil-nome { font-size: 11.5px; color: var(--texto-tenue); text-align: center; }
.ini-funil-taxas { display: flex; justify-content: space-around; padding: 0 var(--espaco-xl); font-size: 12px; color: var(--texto-suave); font-weight: 550; }
.ini-funil-tempos { padding: var(--espaco-md) var(--espaco-xl) var(--espaco-xl); margin-top: var(--espaco-md); border-top: 1px solid var(--linha-suave); font-size: 11.5px; color: var(--texto-tenue); }

/* Cartão "Sinais de angariação": 4 linhas, só a 1.ª clicável (com hover). */
.ini-sinais-corpo { display: flex; flex-direction: column; }
.ini-sinais-linha { display: flex; align-items: center; justify-content: space-between; padding: var(--espaco-md) var(--espaco-xl); border-bottom: 1px solid var(--linha-suave); font-size: 13px; color: var(--texto-principal); text-decoration: none; }
.ini-sinais-linha:last-child { border-bottom: 0; }
a.ini-sinais-linha-link:hover { background: var(--fundo-superficie-2); }
.ini-sinais-rotulo { display: inline-flex; align-items: center; gap: 8px; }
.ini-sinais-ponto { width: 6px; height: 6px; border-radius: 50%; background: var(--acento-default); flex: none; }
.ini-sinais-valor { font-family: var(--font-num); font-variant-numeric: tabular-nums; font-weight: 660; color: var(--texto-principal); }
.ini-sinais-rodape { padding: var(--espaco-md) var(--espaco-xl) var(--espaco-lg); }

/* Equipa: 4.ª coluna "N por contactar" — override deliberado só de
   `grid-template-columns` (as outras propriedades da regra original em
   `.ini-atividade-linha`, acima, mantêm-se). */
.ini-atividade-linha { grid-template-columns: 112px 1fr 46px 96px; }
.ini-atividade-nome-col { display: flex; flex-direction: column; gap: 3px; overflow: hidden; }
.ini-chip-parado { align-self: flex-start; font-size: 10.5px; font-weight: 600; padding: 2px 7px; border-radius: var(--raio-pilula); color: var(--aviso-texto); background: var(--aviso-fundo); white-space: nowrap; }
.ini-atividade-porcontactar { font-size: 11.5px; font-weight: 600; color: var(--acento-default); text-decoration: none; text-align: right; white-space: nowrap; }
.ini-atividade-porcontactar:hover { text-decoration: underline; }

/* Precisa de ação: sub-secção "A apodrecer no funil" e rodapé de opt-outs. */
.ini-acao-apodrecer-titulo { padding: var(--espaco-md) var(--espaco-xl) var(--espaco-xs); margin-top: var(--espaco-xs); border-top: 1px solid var(--linha-suave); font-size: 10.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--texto-tenue); }
.ini-acao-optouts { padding: var(--espaco-md) var(--espaco-xl); border-top: 1px solid var(--linha-suave); font-size: 12px; font-weight: 600; color: var(--semaforo-perigo); }

/* Varrimento: "Top concelhos da semana" no cabeçalho, ao lado do chip de saúde. */
.ini-varrimento-concelhos { font-size: 12px; color: var(--texto-suave); font-weight: 500; }

/* Bolsa: cards de resumo/filtro (re-pele 2026-08-12 — duas linhas de 6,
   substituem os 5 `.tile` largos de antes). Os elementos MANTÊM a classe
   `tile` (compatibilidade com `tema.js`: `ligarFiltrosBolsa` limpa o
   destaque via o seletor `.tile.active` quando o select Estado muda — não é
   editável nesta tarefa), só ficam mais densos por cima dela — cerca de
   metade da altura dos `.tile` do Início, que continuam com o visual
   original. Prefixo `.bl-` nas classes novas, para não colidir com o resto
   do painel. */
.bl-cards { display: flex; flex-direction: column; gap: var(--espaco-sm); margin-bottom: 22px; }
.bl-cards-linha { display: grid; grid-template-columns: repeat(6, 1fr); gap: var(--espaco-sm); }
.bl-card { padding: 10px var(--espaco-md); }
.bl-card .lbl { font-size: 11px; gap: 5px; }
.bl-card .lbl .dot { width: 7px; height: 7px; flex: 0 0 auto; }
.bl-card .val { font-size: 20px; margin-top: 4px; }
.bl-card .sub { margin-top: 1px; }
.bl-card-estado .lbl { display: flex; align-items: center; }
.bl-card-estado .linha-valor { display: flex; align-items: baseline; gap: 7px; margin-top: 4px; }
.bl-card-estado .val { font-size: 20px; margin-top: 0; }
.bl-card-estado .pct { font-size: 11.5px; color: var(--texto-tenue); font-variant-numeric: tabular-nums; }
/* O card de estado é embrulhado num `.gloss` (glossário em hover): o item da
   grelha passa a ser o embrulho, e é ele que tem de esticar — daí o `display:
   grid`, que faz o link ocupar a célula toda e mantém a altura igual entre
   cards. */
.bl-card-slot { display: grid; }
/* EXCEÇÃO ao alinhamento à direita da `.gloss-caixa` (a outra é o badge da
   ficha da lead): esta linha tem cards nas DUAS margens, portanto nenhum dos
   dois lados serve de âncora para todos. Os do MEIO ficam centrados; as
   PONTAS ancoram para dentro — o card da esquerda alinha à esquerda, o da
   direita alinha à direita (achado de browser de
   2026-08-30: a ~1280px o card é mais estreito que a caixa e o «Novo»,
   centrado, cortava contra a sidebar).

   As pontas mudam com o breakpoint, porque a linha reflui de 6 para 3 e para
   2 colunas — daí o `nth-child` por largura em vez de só `:first/:last-child`
   (a 1100px o «Com proposta» passa a abrir linha, a 640px alternam todos). As
   regras seguem por ordem de especificidade igual: ganha a última que casar,
   que é sempre a do layout em vigor. */
.bl-card-slot > .gloss-caixa { right: auto; left: 50%; transform: translateX(-50%); }
.bl-cards-linha > .bl-card-slot:first-child > .gloss-caixa { left: 0; right: auto; transform: none; }
.bl-cards-linha > .bl-card-slot:last-child > .gloss-caixa { left: auto; right: 0; transform: none; }
@media (max-width: 1100px) {
  .bl-cards-linha { grid-template-columns: repeat(3, 1fr); }
  .bl-cards-linha > .bl-card-slot:nth-child(3n+1) > .gloss-caixa { left: 0; right: auto; transform: none; }
  .bl-cards-linha > .bl-card-slot:nth-child(3n) > .gloss-caixa { left: auto; right: 0; transform: none; }
}
@media (max-width: 640px) {
  .bl-cards-linha { grid-template-columns: repeat(2, 1fr); }
  .bl-cards-linha > .bl-card-slot:nth-child(2n+1) > .gloss-caixa { left: 0; right: auto; transform: none; }
  .bl-cards-linha > .bl-card-slot:nth-child(2n) > .gloss-caixa { left: auto; right: 0; transform: none; }
}

/* ============================================================================
   Lightbox · galeria.js (2026-08-13)
   Modal para expandir as fotos da ficha do imóvel. Padrão: animação de entrada
   com a imagem, navegação por setas e teclado, contador visível, fallback
   gracioso para fotos mortas (mesma placeholder do template), foco restrito
   ao modal enquanto está aberto.
   ============================================================================ */

/* O modal não aparece por defeito (display: none). A classe `.aberto`
   (aplicada por galeria.js) torna-o visível com fade-in rápido. */
.gal-modal {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 100;
  font-family: var(--font-ui);
}

/* Quando aberto, mostra o modal. */
.gal-modal.aberto {
  display: flex;
  align-items: center;
  justify-content: center;
  animation: gal-fade-in 0.15s ease-out;
}

@keyframes gal-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* Fundo semi-transparente (responde a cliques para fechar). */
.gal-modal-fundo {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.8);
}

/* Contentor de conteúdo: centrado, com posição relativa para os botões. */
.gal-modal-conteudo {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--espaco-lg);
  padding: var(--espaco-lg);
  max-width: 90vw;
  max-height: 90vh;
}

/* Imagem grande. */
.gal-modal-imagem {
  max-width: 100%;
  max-height: 80vh;
  object-fit: contain;
  border-radius: var(--raio-md);
  background: var(--fundo-superficie);
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
}

/* Placeholder para fotos mortas (fallback gracioso). */
.gal-modal-morta {
  display: none;
  width: 300px;
  height: 400px;
  border-radius: var(--raio-md);
  background: var(--fundo-superficie);
  border: 1px dashed var(--linha-default);
  color: var(--texto-tenue);
  font-size: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--espaco-lg);
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
}

/* Contentor da imagem (para aplicar estilos à imagem quando o fallback está
   ativo). */
.gal-modal-imagem-container {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Botões de navegação (anterior/próxima) — pílulas com o acento. */
.gal-modal-botao {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 40px;
  height: 40px;
  padding: 0;
  border-radius: var(--raio-pilula);
  background: var(--acento-default);
  color: var(--acento-contraste);
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 26px;
  font-weight: 300;
  transition: background 0.2s, transform 0.2s;
  z-index: 2;
}

.gal-modal-botao:hover {
  background: var(--acento-suave);
  color: var(--acento-default);
  transform: translateY(-50%) scale(1.1);
}

.gal-modal-botao:active {
  transform: translateY(-50%) scale(0.95);
}

/* Posicionamento específico. */
.gal-modal-prev {
  left: -60px;
}

.gal-modal-next {
  right: -60px;
}

/* Botão de fechar (canto superior direito). */
.gal-modal-fechar {
  position: absolute;
  top: var(--espaco-lg);
  right: var(--espaco-lg);
  width: 40px;
  height: 40px;
  padding: 0;
  border-radius: var(--raio-pilula);
  background: rgba(0, 0, 0, 0.5);
  color: white;
  border: none;
  cursor: pointer;
  font-size: 28px;
  font-weight: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.2s;
  z-index: 3;
}

.gal-modal-fechar:hover {
  background: rgba(0, 0, 0, 0.7);
}

/* Contador (canto inferior central). */
.gal-modal-contador {
  position: absolute;
  bottom: var(--espaco-lg);
  left: 50%;
  transform: translateX(-50%);
  background: rgba(0, 0, 0, 0.7);
  color: white;
  padding: 6px 14px;
  border-radius: var(--raio-pilula);
  font-size: 13px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  z-index: 3;
}

/* Responsivo em ecrãs pequenos: botões posicionados perto da imagem,
   swipe ativado, gap reduzido. */
@media (max-width: 640px) {
  .gal-modal-conteudo {
    gap: var(--espaco-md);
    padding: var(--espaco-md);
  }

  .gal-modal-prev {
    left: var(--espaco-md);
  }

  .gal-modal-next {
    right: var(--espaco-md);
  }

  .gal-modal-imagem {
    max-height: 70vh;
  }
}

/* Respeita a preferência do utilizador por animações reduzidas. */
@media (prefers-reduced-motion: reduce) {
  .gal-modal.aberto {
    animation: none;
  }

  .gal-modal-botao,
  .gal-modal-fechar {
    transition: none;
  }
}

/* ---------- coluna «Erro» da tabela de Execuções (Técnico) ---------- */
/* Pedido do Vítor (2026-09-02): abrir o <details> com o erro completo não pode
   mexer na largura de nenhuma coluna; o layout FECHADO fica como em produção.
   Porquê mexia: com table-layout:auto e `.card table { width: 100% }`, o
   espaço excedente distribui-se em proporção à max-content de cada coluna.
   Com `max-width: 60ch` o <pre> aberto pedia ≈414px contra os 347-384px do
   <summary> de 60 chars: abrir aumentava o peso da coluna «Erro» e encolhia
   TODAS as outras. Medido (Chromium 151 / Firefox 153, layout real): com o
   CSS de produção, viewport >= 1728px, «Erro» +16 a +34px e as outras -1,3 a
   -4,6px; abaixo de 1600px a tabela já está no min-content e o efeito é nulo.
   Correção: `width: 0; min-width: 100%` só no <pre> — deixa de contribuir
   para a largura intrínseca da coluna e recebe, já com a coluna decidida
   pelo <summary>, a largura real da célula; diferença 0,00px em todas as
   colunas de 1280 a 2560px, nos dois motores. NÃO tocar no <summary> nem no
   <details> (mudam o min-content da coluna fechada) e NÃO usar
   `table-layout: fixed` (muda todas as colunas fechadas). */
.exec-erro { margin: 0; }
.exec-erro summary { cursor: pointer; color: var(--acento-default); font-size: 11.5px; font-weight: 600; }
.exec-erro-texto {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  max-height: 16em;
  overflow: auto;
  width: 0;
  min-width: 100%;
  box-sizing: border-box;
  font-size: 11.5px;
  margin: var(--espaco-xs) 0 0;
  padding: var(--espaco-xs);
  border: 1px solid var(--linha-default);
}

/* ============================================================================
   Lead com imóvel desaparecido — a marca nas LISTAS (spec de
   2026-09-03-c21-lead-imovel-desaparecido §3.7, Proposta B do mock).
   Bolsa (.bl-) e As minhas leads (.ml-). Só acrescentos; zero tokens novos
   (o gate de paridade de `test_tokens_css.py` não é afetado) e as MESMAS
   cores da pílula da ficha (`.det-situacao*`, bloco A): alerta para
   RETIRADO/FORA_TERRITORIO, neutro para VOLTOU.
   ============================================================================ */

/* Pílula/chip de filtro em forma de LINK (a dos selects é `select.bl-chip`,
   com regras próprias mais acima). Mesma altura, raio e cores. */
.bl-chip-link {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12.5px; font-weight: 500; line-height: 1;
  color: var(--texto-principal); text-decoration: none; white-space: nowrap;
  background: var(--fundo-superficie-2); border: 1px solid var(--linha-default);
  border-radius: var(--raio-pilula); padding: 8px 14px;
}
.bl-chip-link:hover { border-color: var(--acento-default); }
.bl-chip-link.bl-chip-ativo {
  background: var(--acento-suave); color: var(--acento-default);
  border-color: var(--acento-default); font-weight: 620;
}
.bl-chip-n { font-variant-numeric: tabular-nums; font-weight: 620; color: var(--texto-suave); }
.bl-chip-link.bl-chip-ativo .bl-chip-n { color: inherit; }

/* Sub-linha da marca, por baixo do subtítulo do imóvel (Bolsa). */
.bl-marca {
  display: flex; align-items: center; gap: 5px;
  margin-top: 4px; font-size: 12px; font-weight: 620;
  color: var(--estado-descartado-texto);
}
.bl-marca svg { width: 13px; height: 13px; flex: none; }
/* `VOLTOU` é rasto de um episódio FECHADO (decisão 8): informa, não alarma. */
.bl-marca-voltou { color: var(--texto-suave); font-weight: 600; }

/* Linha apagada: só as MARCADAS (RETIRADO/FORA_TERRITORIO) — nunca a VOLTOU,
   que mantém a linha normal. Apaga preço, portal, estado e consultor; o
   TÍTULO e as AÇÕES ficam intactos (a lead continua a trabalhar-se, e a
   sub-linha da marca tem de continuar a saltar à vista).

   O cinza é `--texto-suave` e não `--texto-tenue`: apagar não é esconder —
   este é o mesmo tom dos subtítulos legíveis da app, com contraste bastante
   sobre o fundo dos dois temas. */
tr.bl-apagada { background: var(--fundo-superficie-2); }
tr.bl-apagada .bl-preco,
tr.bl-apagada .bl-portal,
tr.bl-apagada td[data-consultor] { color: var(--texto-suave); font-weight: 500; }
tr.bl-apagada .bl-estado .st { opacity: .72; }
/* O hover herdado (`.card tbody tr:hover`) usa o MESMO token do fundo da
   linha apagada — sem mais nada, o hover não muda nada de visível. O
   `filter: brightness()` distingue-o sem introduzir token novo (gate
   `test_tokens_css`): nos dois temas continua legível — o texto claro/
   escuro já está calibrado sobre `--fundo-superficie-2` nos outros usos da
   casa (ex. `.ini-chip`), e uma linha marcada só ganha o "acender" extra do
   hover, nunca perde contraste. */
tr.bl-apagada:hover { filter: brightness(.97); }

/* ---------- .ml- (As minhas leads) ---------- */

/* Fila dos chips de filtro: «Todas» + os 4 grupos de estado (decisão do
   dono, 2026-09-04) + «Imóvel retirado» (já existia). */
.ml-filtros { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: var(--espaco-lg); }

/* Faixa no topo do cartão, a toda a largura do conteúdo. */
.ml-marca {
  display: flex; align-items: center; gap: 6px;
  font-size: 12.5px; font-weight: 620;
  border-radius: var(--raio-sm); padding: 7px 10px;
  color: var(--estado-descartado-texto); background: var(--estado-descartado-fundo);
}
.ml-marca svg { width: 14px; height: 14px; flex: none; }
.ml-marca-voltou { color: var(--texto-suave); background: var(--fundo-superficie-2); font-weight: 600; }

/* «Contactar no portal» desativado: continua a parecer um botão (o gesto
   existe, o destino é que já não), sem cursor de link e sem cor de ação. */
.ml-btn-desativado {
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12.5px; font-weight: 600; padding: 8px 14px;
  border-radius: var(--raio-sm); cursor: not-allowed;
  color: var(--texto-suave); background: var(--fundo-superficie-2);
  border: 1px solid var(--linha-default);
}
