/* ---------------------------------------------------------------------------
   casaradar — radar de anúncios na Área Metropolitana do Porto

   Os tokens de cor vêm do casometro, onde já foram validados para daltonismo
   (deuteranopia/protanopia/tritanopia). Copiados em vez de importados: os dois
   projectos são independentes e um não deve partir quando o outro muda.

   Acrescentam-se aqui as cores das bandas fiscais (verde/âmbar/vermelho/fora),
   que são a linguagem visual própria deste painel.
   --------------------------------------------------------------------------- */
:root {
  color-scheme: light;
  --surface-1:      #fcfcfb;
  --surface-2:      #f3f3f0;
  --page:           #f9f9f7;
  --text-primary:   #0b0b0b;
  --text-secondary: #52514e;
  --text-muted:     #898781;
  --grid:           #e1e0d9;
  --baseline:       #c3c2b7;
  --border:         rgba(11,11,11,0.10);
  --good:           #006300;
  --warning:        #fab219;
  --critical:       #d03b3b;

  --series-1: #2a78d6;
  --series-2: #eb6834;
  --series-3: #1baf7a;
  --series-4: #eda100;
  --series-5: #e87ba4;
  --series-6: #008300;
  --series-ctx: #898781;

  --div-pos: #2a78d6;
  --div-neg: #e34948;
  --div-mid: #f0efec;

  /* Rampa sequencial do mapa: turquesa -> ciano -> azul -> índigo.
     Multi-tom por tons vizinhos (todos frios), não arco-íris. Gerada em OKLCH
     com lightness estritamente monótona; ver o cabeçalho deste ficheiro. */
  --seq-1: #95f4f9; --seq-2: #4acfee; --seq-3: #16a4df;
  --seq-4: #2a78c2; --seq-5: #384e96; --seq-6: #322c61;
  --seq-vazio: #e6e5e0;

  /* Rampa divergente para o mapa de variação (azul <-> vermelho, cinzento ao centro) */
  --dv-neg-3: #a02726; --dv-neg-2: #d0403f; --dv-neg-1: #eb9695;
  --dv-zero:  #f0efec;
  --dv-pos-1: #a8caf4; --dv-pos-2: #4a8fdd; --dv-pos-3: #17518f;

  /* Forma, não cor. Estavam escritos à mão em cada folha — 12 px aqui, 10 px
     ali, uma sombra no popover e outra parecida no painel do Radar — e é
     assim que três vistas ficam com três desenhos. Um bloco tem `--raio-bloco`
     e a sombra do site; um controlo tem `--raio-ctrl`; o que é pílula é
     redondo. */
  --raio-bloco:  12px;
  --raio-ctrl:   8px;
  --raio-pilula: 999px;
  --sombra: 0 14px 36px rgba(11,11,11,0.20);
}
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) {
    color-scheme: dark;
    --surface-1:      #1a1a19;
    --surface-2:      #232322;
    --page:           #0d0d0d;
    --text-primary:   #ffffff;
    --text-secondary: #c3c2b7;
    --text-muted:     #898781;
    --grid:           #2c2c2a;
    --baseline:       #383835;
    --border:         rgba(255,255,255,0.10);
    --good:           #0ca30c;

    --series-1: #3987e5;
    --series-2: #d95926;
    --series-3: #199e70;
    --series-4: #c98500;
    --series-5: #d55181;
    --series-6: #008300;

    --div-pos: #3987e5;
    --div-neg: #e66767;
    --div-mid: #383835;

    --seq-1: #2f2961; --seq-2: #324b98; --seq-3: #1675c4;
    --seq-4: #11a1d9; --seq-5: #30cded; --seq-6: #8bf2f5;
    --seq-vazio: #2c2c2a;

    --dv-neg-3: #f4b4b3; --dv-neg-2: #e66767; --dv-neg-1: #8e3433;
    --dv-zero:  #383835;
    --dv-pos-1: #244a75; --dv-pos-2: #3987e5; --dv-pos-3: #9ec5f4;
    --sombra: 0 14px 36px rgba(0,0,0,0.5);
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --surface-1:      #1a1a19;
  --surface-2:      #232322;
  --page:           #0d0d0d;
  --text-primary:   #ffffff;
  --text-secondary: #c3c2b7;
  --text-muted:     #898781;
  --grid:           #2c2c2a;
  --baseline:       #383835;
  --border:         rgba(255,255,255,0.10);
  --good:           #0ca30c;

  --series-1: #3987e5;
  --series-2: #d95926;
  --series-3: #199e70;
  --series-4: #c98500;
  --series-5: #d55181;
  --series-6: #008300;

  --div-pos: #3987e5;
  --div-neg: #e66767;
  --div-mid: #383835;

  --seq-1: #2f2961; --seq-2: #324b98; --seq-3: #1675c4;
  --seq-4: #11a1d9; --seq-5: #30cded; --seq-6: #8bf2f5;
  --seq-vazio: #2c2c2a;

  --dv-neg-3: #f4b4b3; --dv-neg-2: #e66767; --dv-neg-1: #8e3433;
  --dv-zero:  #383835;
  --dv-pos-1: #244a75; --dv-pos-2: #3987e5; --dv-pos-3: #9ec5f4;
  --sombra: 0 14px 36px rgba(0,0,0,0.5);
}


/* --- bandas fiscais: a linguagem visual deste painel ----------------------
   Verde  = isento de IMT e Selo (até 330.539 €)
   Âmbar  = isenção parcial: paga imposto sobre o excedente
   Vermelho = acima do tecto de 360k, ainda dentro da Garantia Pública
   Fora   = acima de 450k: sem financiamento a 100%
   A banda é só fiscal. "O dinheiro chega?" é outra pergunta e tem ícone próprio. */
/* Os tons de texto são um passo mais escuros (claro) ou mais claros (escuro)
   do que os de preenchimento: o distintivo escreve texto pequeno a negrito
   sobre o seu próprio fundo tingido, e nesse par o âmbar original dava 3,3:1,
   o vermelho 3,9:1 e o cinzento 3,1:1 — abaixo dos 4,5:1 do AA. A matiz é a
   mesma; muda só a luminosidade, por isso a separação para deuteranopia e
   protanopia mantém-se, e o rótulo continua a dizer em texto o que a cor diz. */
:root {
  --banda-verde:    #006300;
  --banda-ambar:    #8a5f00;
  --banda-vermelho: #b52d2d;
  --banda-fora:     #63615d;
  --banda-verde-bg:    rgba(0,99,0,0.10);
  --banda-ambar-bg:    rgba(250,178,25,0.16);
  --banda-vermelho-bg: rgba(208,59,59,0.12);
  --banda-fora-bg:     rgba(137,135,129,0.12);
}
:root[data-theme="dark"], :root:where(:not([data-theme="light"])) {
  --banda-verde:    #0ca30c;
  --banda-ambar:    #eda100;
  --banda-vermelho: #e66767;
  --banda-fora:     #a5a39a;
}

/* --- superfície de instrumento --------------------------------------------
   O ecrã do Radar é escuro nos dois temas, e é a única coisa no site que o é.
   A razão não é gosto: as marcas do ecrã — os pontos das bandas, os ecos
   cinzentos do que os filtros cortam, o que pisca — só existem como luz sobre
   fundo escuro, e num fundo claro a leitura invertia-se a meio da página.

   Não é um segundo tema, e por isso não há aqui um único valor novo: são os
   mesmos nomes de token com os mesmos valores do tema escuro que está acima,
   escritos num âmbito em vez de na raiz. Quem lá dentro escreve `--series-1`
   está a escrever o azul do site, e não um azul só do Radar. A moldura — a
   borda, o raio e a sombra — é a dos outros blocos da página, para o ecrã ler
   como um bloco do site com uma superfície própria e não como um buraco. */
.instrumento {
  color-scheme: dark;
  --page:           #0d0d0d;
  --surface-1:      #1a1a19;
  --surface-2:      #232322;
  --text-primary:   #ffffff;
  --text-secondary: #c3c2b7;
  --text-muted:     #898781;
  --grid:           #2c2c2a;
  --baseline:       #383835;
  --border:         rgba(255,255,255,0.10);
  --good:           #0ca30c;
  --warning:        #eda100;
  --critical:       #e66767;

  --series-1: #3987e5;
  --series-2: #d95926;
  --series-3: #199e70;
  --series-4: #c98500;
  --series-5: #d55181;
  --series-6: #008300;
  --series-ctx: #898781;

  --banda-verde:    #0ca30c;
  --banda-ambar:    #eda100;
  --banda-vermelho: #e66767;
  --banda-fora:     #a5a39a;

  color: var(--text-primary);
}


* { box-sizing: border-box; }
html, body {
  margin: 0; padding: 0;
  background: var(--page);
  color: var(--text-primary);
  font: 15px/1.45 system-ui, -apple-system, "Segoe UI", sans-serif;
  font-variant-numeric: tabular-nums;
}
main { max-width: 1400px; margin: 0 auto; padding: 0 16px 64px; }
h1 { font-size: 1.5rem; margin: 24px 0 4px; }
h2 { font-size: 1.05rem; margin: 28px 0 10px; }
p.lede { color: var(--text-secondary); margin: 0 0 20px; max-width: 70ch; }
a { color: var(--series-1); }

/* Utilitários. Existem porque a CSP proíbe `style=` na marcação. */
.oculto { display: none !important; }
.mono { font-variant-numeric: tabular-nums; }
.dir { text-align: right; }
.esq { text-align: left; }
.esbatido { color: var(--text-muted); }


/* ===========================================================================
   Estrutura da página
   ===========================================================================
   Tudo o que se segue é classe. Não há um único `style=` na marcação, porque
   a CSP publicada (ver web/_headers) proíbe `style-src 'unsafe-inline'` — e é
   isso que garante que um bug de injecção não consegue desenhar nada. Onde um
   valor tem de ser dinâmico (o minigráfico), usam-se atributos de SVG, que
   não são estilo.
   =========================================================================== */

.saltar {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--surface-1); color: var(--text-primary);
  border: 1px solid var(--border); border-radius: 0 0 8px 0; padding: 8px 14px;
}
.saltar:focus { left: 0; }

.topo { padding: 4px 0 10px; }
/* A mesma linha nas duas páginas: marca à esquerda, navegação e comutador de
   tema à direita. Antes os Anúncios punham o `lede` dentro desta linha e o
   Radar tinha um cabeçalho só dele; agora a linha é a mesma e o que cada
   página tem de próprio vem por baixo dela. */
.topo-linha {
  display: flex; justify-content: space-between; align-items: center;
  gap: 12px 16px; flex-wrap: wrap; padding: 14px 0 8px;
}

/* A marca: o ícone do favicon e o nome, iguais nas duas páginas. Nasceu no
   Radar, que era a única com ícone; ficou, porque uma marca que muda de
   página em página não é uma marca. O desenho é o de `icon.svg` e as suas
   cores são as da rampa sequencial do site — não seguem o tema porque o
   ícone tem fundo próprio, tal como o separador do browser. */
.marca {
  display: inline-flex; align-items: center; gap: 9px; min-width: 0;
  margin: 0; font-size: 1.4rem; font-weight: 700; line-height: 1.1;
  color: var(--text-primary); text-decoration: none;
}
.marca-icone { width: 27px; height: 27px; flex: none; }
/* Navegação entre as páginas do site (Anúncios, Radar). Discreta: duas
   cápsulas ao lado do comutador de tema, a da página actual com fundo. Vive em
   styles.css e não na folha de cada página porque tem de ser igual nas duas. */
.topo-accoes { flex: none; display: flex; align-items: center; gap: 8px; }
.navegacao { display: flex; gap: 4px; }
.navegacao a {
  font-size: 0.78rem; padding: 5px 12px; border-radius: 999px; text-decoration: none;
  color: var(--text-secondary); border: 1px solid transparent;
}
.navegacao a:hover { color: var(--text-primary); border-color: var(--border); }
.navegacao a[aria-current="page"] {
  color: var(--text-primary); background: var(--surface-2); border-color: var(--border);
}

.tema {
  flex: none;
  background: var(--surface-1); border: 1px solid var(--border); border-radius: 999px;
  padding: 5px 13px; font: inherit; font-size: 0.78rem;
  color: var(--text-secondary); cursor: pointer;
}
.tema:hover { color: var(--text-primary); border-color: var(--text-secondary); }

/* ------------------------- a linha de leitura ------------------------------
   Nasceu no Radar: em vez de um parágrafo a dizer o que a página tem, uma fila
   de números grandes com o rótulo pequeno por baixo — quantos estão
   carregados, quantos passam, quantos ficam de fora. Lê-se de relance e não
   ocupa altura.

   Veio para os Anúncios em vez de ser cortada, e é a mesma regra nas duas
   páginas: no Radar diz o que o ecrã está a mostrar, nos Anúncios diz o que a
   tabela por baixo está a mostrar.

   `.leit` e não `> span`: nesta linha há também distintivos de banda e botões,
   que não são leituras e não querem este desenho. */
.leitura { display: flex; gap: 6px 20px; flex-wrap: wrap; align-items: baseline; min-width: 0; }
.leitura .leit {
  font-size: 0.68rem; color: var(--text-muted); font-weight: 400;
  text-transform: uppercase; letter-spacing: 0.08em; white-space: nowrap;
}
.leitura .leit b {
  display: block; font: 700 1.2rem/1.15 inherit; letter-spacing: 0;
  text-transform: none; color: var(--series-1); font-variant-numeric: tabular-nums;
}
/* O que já lá estava e o que ficou de fora não são leituras vivas: dizem-se
   com o mesmo desenho, sem a cor que chama. */
.leitura .n-total b { color: var(--text-primary); }
.leitura .n-fora b { color: var(--text-muted); }

.pills { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 4px; }
.pill {
  display: inline-block; font-size: 0.72rem; padding: 3px 9px; border-radius: 999px;
  background: var(--surface-2); color: var(--text-secondary); border: 1px solid var(--border);
}
.pill b { color: var(--text-primary); font-weight: 600; }
.pill-aviso { border-color: var(--banda-ambar); color: var(--banda-ambar); }

button, input, select { font: inherit; }
.btn {
  font-size: 0.82rem; padding: 6px 12px; cursor: pointer;
  background: var(--surface-1); color: var(--text-secondary);
  border: 1px solid var(--border); border-radius: 7px;
}
.btn:hover { color: var(--text-primary); border-color: var(--text-secondary); }
.btn-pequeno { font-size: 0.76rem; padding: 3px 9px; }
:focus-visible { outline: 2px solid var(--series-1); outline-offset: 1px; }

/* ------------------------------ barra de filtros ---------------------------
   Uma linha de pílulas em vez de um painel: cada critério diz o seu valor em
   texto curto, realça-se quando sai do valor por omissão, e abre um popover
   ancorado com o controlo lá dentro. Por baixo, o funil: um troço por filtro,
   do tamanho do que ele corta. */
.barra-filtros {
  position: sticky; top: 0; z-index: 30;
  background: var(--page); border-bottom: 1px solid var(--border);
  padding: 8px 0 10px; margin-bottom: 10px;
}
.filtros-int { position: relative; }

.fila { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.procura { position: relative; flex: 1 1 300px; max-width: 460px; }
.procura-cx {
  width: 100%; height: 34px; padding: 0 10px 0 32px;
  border: 1px solid var(--border); border-radius: 9px;
  background: var(--surface-1); color: var(--text-primary); font-size: 0.85rem;
}
.procura-cx::placeholder { color: var(--text-muted); }
.procura-lupa {
  position: absolute; left: 10px; top: 9px; width: 15px; height: 15px;
  fill: none; stroke: var(--text-muted); stroke-width: 2; pointer-events: none;
}
.fila-accoes { display: flex; gap: 8px; margin-left: auto; }

/* Sugestões de município e freguesia. A última é sempre "procurar no texto",
   e é a que o Enter escolhe quando ninguém andou nas setas. */
.sug {
  position: absolute; left: 0; right: 0; top: 38px; z-index: 40;
  margin: 0; padding: 5px; list-style: none;
  background: var(--surface-1); border: 1px solid var(--border);
  border-radius: var(--raio-ctrl); box-shadow: var(--sombra);
}
.sug li {
  display: flex; justify-content: space-between; gap: 10px; cursor: pointer;
  padding: 6px 9px; border-radius: 6px; font-size: 0.85rem;
}
.sug li:hover, .sug li.activo { background: var(--surface-2); }
.sug .tipo {
  color: var(--text-muted); font-size: 0.68rem;
  letter-spacing: 0.05em; text-transform: uppercase; flex: none;
}

/* --- pílulas --- */
.pilulas { display: flex; gap: 7px; flex-wrap: wrap; align-items: center; margin-top: 9px; }
.pil {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  height: 30px; padding: 0 10px; white-space: nowrap;
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--surface-1); color: var(--text-secondary); font-size: 0.82rem;
}
.pil:hover { border-color: var(--series-1); color: var(--text-primary); }
.pil .rot {
  font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--text-muted); font-weight: 600;
}
.pil .val { font-weight: 600; }
.pil .seta {
  width: 7px; height: 7px; opacity: 0.55;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
}
/* Fora do valor por omissão: o realce é o que diz, de relance, o que se mexeu. */
.pil.alterada {
  border-color: var(--series-1); color: var(--series-1);
  background: color-mix(in srgb, var(--series-1) 9%, var(--surface-1));
}
.pil.alterada .rot { color: inherit; opacity: 0.75; }
.pil.aberta { box-shadow: 0 0 0 2px var(--page), 0 0 0 3px var(--series-1); }
.pil .x {
  display: inline-grid; place-items: center; width: 17px; height: 17px;
  margin: 0 -4px 0 1px; border-radius: 50%; font-size: 0.95rem; line-height: 1;
}
.pil .x:hover { background: var(--critical); color: var(--surface-1); }
.pil.mais { border-style: dashed; color: var(--text-muted); }
.pil.mais .n { color: inherit; }

/* --- funil --- */
.funil { margin-top: 10px; }
.funil-barra {
  display: flex; gap: 2px; height: 12px; border-radius: 6px;
  overflow: hidden; background: var(--surface-2);
}
.funil-barra .seg { border: 0; padding: 0; min-width: 3px; background: var(--baseline); cursor: pointer; }
.funil-barra .seg:hover { filter: brightness(0.82); }
.funil-barra .resto { background: var(--series-1); min-width: 5px; cursor: default; }
.funil-leg {
  display: flex; flex-wrap: wrap; gap: 3px 14px; margin-top: 5px;
  font-size: 0.76rem; color: var(--text-muted);
}
.funil-leg b { color: var(--text-secondary); font-weight: 600; }
.funil-leg .fim b { color: var(--series-1); }
.funil-leg button {
  border: 0; background: none; padding: 0; color: inherit; font: inherit; cursor: pointer;
  text-decoration: underline dotted; text-underline-offset: 3px;
}
.funil-leg button:hover { color: var(--text-primary); }

/* --- popover --- */
.pop {
  position: absolute; z-index: 40; width: min(440px, 100%);
  background: var(--surface-1); border: 1px solid var(--border); border-radius: var(--raio-bloco);
  box-shadow: var(--sombra); padding: 12px 14px 10px;
}
.pop h3 {
  margin: 0 0 8px; font-size: 0.95rem; font-weight: 700;
  display: flex; justify-content: space-between; align-items: baseline; gap: 10px;
}
.pop h3 .repor {
  border: 0; background: none; padding: 0; cursor: pointer;
  font-size: 0.76rem; font-weight: 500; color: var(--text-muted);
  text-decoration: underline; text-underline-offset: 3px;
}
.pop h3 .repor:hover { color: var(--critical); }
.pop .nota { margin-top: 8px; max-width: none; }
.pop .linha { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 9px; }
.pop .linha .direita { margin-left: auto; }
.pop label { display: inline-flex; align-items: center; gap: 5px; }
/* Um `<select>` dentro de um `<label>` em flex cresce até ao seu conteúdo mais
   largo — o nome da freguesia mais comprido — e sai do popover. */
.pop .linha > label { min-width: 0; max-width: 100%; }
.pop .linha > label > select { flex: 1 1 auto; min-width: 0; }
/* Os campos: o mesmo desenho no popover dos Anúncios, na coluna do Radar e nos
   números da janela dos Gráficos. Estavam escritos três vezes, com três
   alturas e três raios. */
.pop input[type="number"], .pop input[type="text"], .pop select, .pop .mini-procura,
.instr input[type="text"], .instr input[type="number"], .instr select,
.mercado-campo-input {
  height: 30px; padding: 0 8px; min-width: 0; font: inherit; font-size: 0.85rem;
  border: 1px solid var(--border); border-radius: var(--raio-ctrl);
  background: var(--surface-1); color: var(--text-primary);
}
.pop input[type="number"] { width: 10ch; text-align: right; }
.pop input[type="number"].curto { width: 7.5ch; }
.pop select { max-width: 100%; }
.pop .mini-procura { width: 100%; margin-bottom: 6px; }
.pop .distritos { margin-bottom: 8px; }
.pop .distritos .chips { margin-top: 3px; }

/* Listas de opções com a contagem à direita: é sempre o que fica à vista se
   for essa a escolha, medido no que já passa todos os *outros* filtros. */
.lista-op {
  list-style: none; margin: 0; padding: 0; max-height: 220px; overflow: auto;
  border: 1px solid var(--border); border-radius: 8px;
}
.lista-op li label {
  display: flex; justify-content: space-between; align-items: center; gap: 10px;
  padding: 5px 9px; cursor: pointer; border-bottom: 1px solid var(--border);
}
.lista-op li:last-child label { border-bottom: 0; }
.lista-op li label:hover { background: var(--surface-2); }
.lista-op .esq { display: flex; align-items: center; gap: 7px; }
.pop .n { color: var(--text-muted); font-size: 0.76rem; font-variant-numeric: tabular-nums; }
.pop .n.zero { opacity: 0.45; }

.radios { display: flex; flex-direction: column; gap: 2px; margin-top: 2px; }
.radios label {
  display: flex; justify-content: space-between; align-items: center; gap: 10px;
  padding: 5px 7px; border-radius: 7px; cursor: pointer; font-size: 0.85rem;
}
.radios label:hover { background: var(--surface-2); }
.radios label > span:first-child { display: flex; gap: 7px; align-items: center; }
.radios input { accent-color: var(--series-1); }

/* ------------------------- a família dos controlos -------------------------
   Quatro nomes para o mesmo gesto — carregar para ligar e desligar um
   critério: `.op` no popover dos Anúncios, `.chip` nas listas de distrito,
   `.tecla` na coluna do Radar, `.mercado-opc` na legenda do Plano. Eram quatro desenhos; a regra passa a ser uma só, e os nomes ficam
   onde estão porque são o que o JS de cada vista escreve.

   O que os distingue são as medidas, e essas ficam junto de cada um: quem
   liga e desliga tem sempre o mesmo contorno, a mesma superfície, o mesmo
   passar-por-cima e o mesmo realce, esteja na tabela, no ecrã ou no plano.

   O realce é tingido — contorno e texto no azul, fundo com 9 % dele — e não
   um bloco cheio: com o azul do site, texto branco por cima dá 3,6:1 e não
   passa o AA. É o mesmo realce do `.pil.alterada`. */
.op, .chip, .tecla, .mercado-opc {
  display: inline-flex; align-items: center; cursor: pointer;
  font: inherit; font-size: 0.8rem; font-weight: 600; white-space: nowrap;
  border: 1px solid var(--border); border-radius: var(--raio-ctrl);
  background: var(--surface-1); color: var(--text-secondary);
}
.op:hover, .chip:hover, .tecla:hover, .mercado-opc:hover {
  border-color: var(--text-secondary); color: var(--text-primary);
}
.op.on, .chip[aria-pressed="true"], .tecla.on, .mercado-opc-on {
  border-color: var(--series-1); color: var(--series-1); font-weight: 600;
  background: color-mix(in srgb, var(--series-1) 9%, var(--surface-1));
}
/* O número que cada um traz é «quantos ficam se carregares aqui»: acompanha o
   estado do botão em vez de ter cor própria. */
.op .n, .tecla .n, .chip-n, .mercado-opc-n {
  font-size: 0.72rem; color: var(--text-muted); font-variant-numeric: tabular-nums;
  font-weight: 500;
}
.op.on .n, .tecla.on .n, .chip[aria-pressed="true"] .chip-n,
.mercado-opc-on .mercado-opc-n { color: inherit; opacity: 0.8; }

/* medidas do `.op`: duas linhas, o rótulo em cima e a contagem em baixo */
.ops { display: flex; gap: 5px; flex-wrap: wrap; margin-top: 2px; }
.op {
  flex-direction: column; justify-content: center;
  min-width: 48px; padding: 5px 8px 4px; line-height: 1.15; font-size: 0.82rem;
}

.bandas-op { display: grid; grid-template-columns: 1fr 1fr; gap: 2px 10px; margin-top: 8px; }
.bandas-op label {
  display: flex; justify-content: space-between; align-items: center; gap: 8px;
  padding: 4px 6px; border-radius: 7px; cursor: pointer; font-size: 0.8rem;
}
.bandas-op label:hover { background: var(--surface-2); }
.bandas-op .esq { display: flex; align-items: center; gap: 6px; }

.mais-lista { list-style: none; margin: 0; padding: 0; }
.mais-lista li {
  display: flex; justify-content: space-between; gap: 12px; cursor: pointer;
  padding: 6px 6px; border-bottom: 1px solid var(--border); border-radius: 6px;
  font-size: 0.85rem;
}
.mais-lista li:last-child { border-bottom: 0; }
.mais-lista li:hover { background: var(--surface-2); }
.mais-lista .val { color: var(--text-muted); }

/* Dois cursores no mesmo trilho: o mínimo e o máximo do preço. Os `input`
   não recebem ponteiro (senão o de cima engolia o de baixo); só os botões.

   Era `.dual, .desl`: o `.desl` era o mesmo deslizador nos instrumentos do
   Radar, e desapareceu com eles — os filtros do Radar passaram a ser a barra
   do site, que usa o `.dual`. */
.dual { position: relative; height: 24px; margin: 4px 0 2px; }
.dual .trilho {
  position: absolute; left: 0; right: 0; top: 10px; height: 4px;
  border-radius: 2px; background: var(--grid);
}
.dual .janela { position: absolute; top: 10px; height: 4px; background: var(--series-1); }
.dual input[type="range"] {
  position: absolute; left: 0; right: 0; top: 5px; width: 100%; height: 14px;
  margin: 0; background: none; pointer-events: none;
  -webkit-appearance: none; appearance: none;
}
.dual input[type="range"]::-webkit-slider-runnable-track { height: 4px; background: transparent; }
.dual input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; pointer-events: auto; cursor: grab;
  width: 16px; height: 16px; margin-top: -6px; border-radius: 50%;
  background: var(--surface-1); border: 2px solid var(--series-1);
}
.dual input[type="range"]::-moz-range-track { height: 4px; background: transparent; }
.dual input[type="range"]::-moz-range-thumb {
  pointer-events: auto; cursor: grab; width: 14px; height: 14px; border-radius: 50%;
  background: var(--surface-1); border: 2px solid var(--series-1);
}

.hist { display: block; width: 100%; height: auto; color: var(--text-secondary); }
.hist text { font-size: 9px; fill: var(--text-muted); font-variant-numeric: tabular-nums; }

.nota { font-size: 0.72rem; color: var(--text-muted); margin: 2px 0 0; max-width: 48ch; }
.nota-aviso { color: var(--banda-vermelho); }

/* medidas do `.chip`: uma linha, pílula */
.chips { display: flex; flex-wrap: wrap; gap: 5px; }
.chip { gap: 6px; padding: 4px 10px; border-radius: var(--raio-pilula); font-weight: 500; }
.chip[aria-pressed="true"] { font-weight: 600; }
.campo-rot {
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--text-muted); font-weight: 600;
}

.aviso-linha {
  margin: 0 0 10px; padding: 7px 11px; border-radius: 8px; font-size: 0.83rem;
  background: var(--banda-ambar-bg); border: 1px solid var(--banda-ambar); color: var(--text-primary);
}

/* --------------------- o esqueleto das vistas de ecrã -----------------------
   O Radar e os Gráficos são a mesma página com um desenho diferente no meio:
   cabeçalho, barra de filtros, a coisa grande, uma lista, rodapé. O que aqui
   está é o que as duas usam; o que só uma usa fica na folha dela.
   --------------------------------------------------------------------------- */

.vista-pagina { max-width: 1500px; margin: 0 auto; padding: 0 16px 40px; }

/* A gaveta da ficha: nas duas o meio da página está ocupado pela coisa grande
   e não há coluna livre onde ela caiba. */
.vista-pagina .painel {
  position: fixed; top: 12px; right: 12px; bottom: 12px; z-index: 60;
  width: min(420px, calc(100vw - 24px)); overflow-y: auto; box-shadow: var(--sombra);
}

/* A lista de baixo: no Radar são os mais próximos, nos Gráficos os que estão
   mais abaixo da mediana do concelho. Mesma grelha, mesmo cartão; o que muda é
   o número da primeira coluna, e isso decide-se em cada página.

   `minmax(0, 1fr)` e não `1fr` no meio: um item de grelha tem `min-width:
   auto`, e o título de um anúncio é uma linha comprida — com `1fr` seco a
   coluna crescia até 600 px e empurrava a página inteira para fora do ecrã. */
.contactos { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 6px; }
.contacto {
  display: grid; grid-template-columns: 58px minmax(0, 1fr) auto;
  gap: 10px; align-items: center; padding: 8px 10px;
}
.contacto > span { min-width: 0; }
.contacto .d small { display: block; }
.contacto .t, .contacto .m {
  display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ------------------------------ distintivos -------------------------------
   Duas linguagens visuais que não se misturam:
   - a BANDA FISCAL é um distintivo cheio, com cor e texto. Diz o imposto.
   - o DINHEIRO é um contorno tracejado, sem preenchimento. Diz se chega.
   A forma distingue-os mesmo sem cor, que é o que se pede a quem não separa
   verde de vermelho. */
.distintivo {
  display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;
  font-size: 0.72rem; font-weight: 600; padding: 2px 8px; border-radius: 999px;
  border: 1px solid transparent;
}
.banda-verde    { color: var(--banda-verde);    background: var(--banda-verde-bg);    border-color: var(--banda-verde); }
.banda-ambar    { color: var(--banda-ambar);    background: var(--banda-ambar-bg);    border-color: var(--banda-ambar); }
.banda-vermelho { color: var(--banda-vermelho); background: var(--banda-vermelho-bg); border-color: var(--banda-vermelho); }
.banda-fora     { color: var(--banda-fora);     background: var(--banda-fora-bg);     border-color: var(--banda-fora); }
label .distintivo { cursor: pointer; }

.marca-cash {
  display: inline-block; white-space: nowrap;
  font-size: 0.71rem; padding: 1px 7px; border-radius: 5px;
  border: 1px dashed var(--baseline); background: transparent; color: var(--text-secondary);
}
.cash-ok { border-color: var(--good); color: var(--good); }
.cash-falta { border-color: var(--critical); color: var(--critical); }

.marca-jitter, .marca-rejeitada, .marca-estado, .marca-habit {
  display: block; margin-top: 3px; font-size: 0.68rem; line-height: 1.25;
}
.marca-jitter { color: var(--text-muted); font-style: italic; }
.marca-rejeitada { color: var(--banda-vermelho); }
.marca-estado { color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; }

/* Habitabilidade: o prazo é o critério que elimina, por isso a marca não é
   só cor — é uma barra à esquerda, que se lê sem distinguir vermelho de
   amarelo. Âmbar = "há data, confirma"; vermelho = "não serve" ou "em obra
   sem data", que para efeitos de decisão valem o mesmo: não se pode contar
   com nenhum dos dois para lá viver a tempo. */
.marca-habit {
  color: var(--banda-ambar); font-weight: 600;
  border-left: 3px solid var(--banda-ambar); padding-left: 5px;
}
.marca-habit-grave { color: var(--banda-vermelho); border-left-color: var(--banda-vermelho); }
.habit-grave { color: var(--banda-vermelho); font-weight: 600; }

/* --------------------------------- estrela --------------------------------
   Contorno vazio quando não está guardado, cheio quando está: a forma diz
   tanto como a cor. */
.estrela {
  background: none; border: 0; padding: 0 2px; margin: 0; cursor: pointer;
  font-size: 1rem; line-height: 1; color: var(--text-muted);
}
.estrela:hover { color: var(--banda-ambar); }
.estrela-on { color: var(--banda-ambar); }
.estrela-grande { font-size: 1.35rem; padding: 2px 6px; }
.bt-fav-resumo {
  cursor: pointer; font: inherit; font-size: 0.72rem; font-weight: 600;
  color: var(--banda-ambar); background: var(--banda-ambar-bg);
  border: 1px solid var(--banda-ambar);
}
.bt-fav-resumo.fav-activo { background: var(--banda-ambar); color: var(--surface-1); }

/* -------------------------------- resultados ------------------------------ */
.layout { display: grid; grid-template-columns: minmax(0, 1fr); gap: 18px; align-items: start; }
.col-resultados { min-width: 0; }
/* Não é pegajosa no ecrã grande: os filtros já estão presos ao topo e duas
   barras pegajosas empilhadas escondiam-se uma à outra (a altura dos filtros
   varia, por isso não há `top` fixo que sirva). No telemóvel volta a ser —
   ver o bloco dos 720 px. */
.barra {
  background: var(--page);
  display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center;
  justify-content: space-between; padding: 8px 0; border-bottom: 1px solid var(--border);
}
.barra h2 { margin: 0; font-size: 0.95rem; font-weight: 400; }
/* Os distintivos das bandas e o botão dos favoritos ficam à direita das
   leituras, na sua própria fila: são marcas, não números para ler. */
.resumo-marcas { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.barra-accoes { display: flex; gap: 8px; }
/* Duas mensagens possíveis, empilhadas: uma para as rejeições duras, outra
   para a habitabilidade. Cada uma diz quantos escondeu e traz o botão que os
   devolve — esconder em silêncio é indistinguível de não haver nada. */
.ocultos {
  margin: 8px 0 0; font-size: 0.82rem; color: var(--text-secondary);
  display: flex; flex-direction: column; gap: 6px; align-items: flex-start;
}
.ocultos-msg { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.ocultos-habit {
  border-left: 3px solid var(--banda-vermelho); padding-left: 8px;
}
.mais { margin-top: 12px; display: flex; gap: 10px; align-items: center; }
.mais p { margin: 0; font-size: 0.8rem; }
.vazio { color: var(--text-muted); padding: 40px 16px; text-align: center; }

/* --------------------------------- tabela --------------------------------- */
/* Caixa de scroll própria: o conteúdo largo rola aqui dentro e nunca faz a
   página rolar na horizontal. É também o que dá um cabeçalho pegajoso — com
   `top: 45px` num contentor que não rola verticalmente, o cabeçalho era
   *empurrado* 45 px para baixo e tapava a primeira linha. */
.tabela-caixa { overflow: auto; margin-top: 6px; max-height: 68vh; }
/* O selector de colunas mora dentro da caixa que rola, e por isso encosta-se à
   esquerda: numa tabela mais larga do que o ecrã, sem isto fugia para fora à
   primeira rolagem horizontal. */
.tabela-caixa > .ops { position: sticky; left: 0; width: fit-content; margin-bottom: 6px; }
/* `fixed` e larguras por coluna. Com o `table-layout` automático cada coluna
   pede o que o seu conteúdo mais longo pedir, e basta uma freguesia de nome
   comprido ou um preço com variação para esticar a tabela para lá do ecrã:
   eram 1.249 px de tabela dentro de uma caixa de 694. Fixas, o que não cabe é
   cortado com reticências em vez de empurrar as colunas todas para a direita.
   As larguras estão em `ch` e não em px de propósito: acompanham o tamanho de
   letra de quem lê a página com o texto aumentado. */
.tabela { width: 100%; border-collapse: collapse; font-size: 0.84rem; table-layout: fixed; }
.tabela th, .tabela td {
  padding: 5px 6px; text-align: right; vertical-align: top;
  border-bottom: 1px solid var(--border); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.tabela th.c-fav, .tabela td.c-fav { width: 3.4ch; }
.tabela th.c-banda, .tabela td.c-banda { width: 13ch; }
.tabela th.c-gap, .tabela td.c-gap { width: 9ch; }
.tabela th.c-municipio, .tabela td.c-municipio { width: 11ch; }
.tabela th.c-price, .tabela td.c-price { width: 9ch; }
.tabela th.c-eurM2, .tabela td.c-eurM2 { width: 6.5ch; }
.tabela th.c-prem, .tabela td.c-prem { width: 7.5ch; }
.tabela th.c-typ, .tabela td.c-typ { width: 3.5ch; }
.tabela th.c-area, .tabela td.c-area { width: 5.5ch; }
.tabela th.c-srcs, .tabela td.c-srcs { width: 11.5ch; }
.tabela th.c-floor, .tabela td.c-floor { width: 4.5ch; }
.tabela th.c-built, .tabela td.c-built { width: 5ch; }
.tabela th.c-garage, .tabela td.c-garage { width: 8ch; }
.tabela th.c-balc, .tabela td.c-balc { width: 7ch; }
.tabela th.c-energy, .tabela td.c-energy { width: 6ch; }
.tabela th.c-conclusao, .tabela td.c-conclusao { width: 10ch; }
.tabela th.c-first, .tabela td.c-first { width: 8ch; }
.tabela th.c-last, .tabela td.c-last { width: 8ch; }
.tabela th.c-dist, .tabela td.c-dist { width: 5.5ch; }
.tabela th.esq, .tabela td.esq { text-align: left; }
.tabela th {
  position: sticky; top: 0; z-index: 10; background: var(--surface-1);
  font-size: 0.68rem; font-weight: 600; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.03em; user-select: none;
  vertical-align: bottom;
}
.tabela th.ordenavel { cursor: pointer; }
.tabela th.ordenavel:hover { color: var(--text-primary); }
.tabela th.ordem-activa { color: var(--text-primary); }
.seta { font-size: 0.7rem; }
.tabela tbody tr { cursor: pointer; }
.tabela tbody tr:hover { background: rgba(128,128,128,0.07); }
.tabela tbody tr.seleccionada { background: rgba(42,120,214,0.12); }
.tabela tbody tr.rejeitada { background: var(--banda-vermelho-bg); }
.tabela tbody tr.desaparecida { opacity: 0.72; }
.tabela tbody tr.desaparecida .titulo-bt { text-decoration: line-through; }

/* Especificidade acima de `.tabela td`, que fixa white-space: nowrap. As
   marcas ("fora do critério", "rejeita: …") são frases e precisam de mudar de
   linha; a largura acima é que impede que cresçam para o lado. */
.tabela td.c-banda { white-space: normal; }
/* O título é a única coluna sem largura própria: fica com o que sobrar, que é
   o sítio certo para pôr o espaço a mais. O `min-width` impede que desapareça
   quando há muitas colunas ligadas, e as duas linhas cortam com reticências em
   vez de embrulhar — uma linha de altura previsível deixa comparar preços a
   correr o olho pela coluna, que é como esta tabela se lê. O nome inteiro fica
   no `title` do botão (ver `table.js`) e no painel. */
/* Largura própria, como as outras, e não `auto` nem `100%`. Em `table-layout:
   fixed` as células ignoram o `min-width`, e as duas alternativas colapsavam a
   coluna para zero assim que as outras já enchiam a caixa — que é o caso numa
   janela estreita com as 16 colunas ligadas. Quando sobra espaço, o layout
   fixo reparte-o por todas, e esta cresce com as outras. */
.tabela th.c-title, .tabela td.c-title { width: 22ch; }
.titulo-bt, .c-title .sub {
  display: block; max-width: 100%;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.titulo-bt {
  background: none; border: 0; padding: 0; margin: 0; cursor: pointer;
  color: var(--series-1); font-size: 0.86rem; font-weight: 600; text-align: left;
}
.titulo-bt:hover { text-decoration: underline; }
.c-title .sub { display: block; font-size: 0.73rem; color: var(--text-muted); margin-top: 2px; }
.preco { font-weight: 600; }
.delta { display: block; font-size: 0.7rem; margin-top: 2px; }
.delta.desceu, .pos { color: var(--good); }
.delta.subiu, .neg { color: var(--div-neg); }
td.pos span, td.neg span { color: inherit; }


.fontes { display: inline-flex; flex-wrap: wrap; gap: 3px; justify-content: flex-end; }
.sim { color: var(--good); font-weight: 600; }
.nao { color: var(--div-neg); }
.aviso-texto { color: var(--banda-ambar); font-weight: 600; }
.energia { font-weight: 600; }
.energia-Amais, .energia-A, .energia-B, .energia-Bmenos { color: var(--good); }
.energia-C { color: var(--text-primary); }
.energia-D, .energia-E, .energia-F { color: var(--banda-ambar); }

/* --------------------------------- o cartão --------------------------------
   O mesmo anúncio aparece em quatro sítios — a linha da tabela, a ficha, a
   lista dos mais próximos do Radar e a tira dos melhores €/m² do Plano — e
   dizia sempre as mesmas quatro coisas de quatro maneiras: o título, a linha
   de contexto (tipologia · área · sítio), o preço com a bolinha da banda, e o
   número que manda naquela vista (a distância, o €/m²).

   Passa a haver um desenho para cada uma dessas quatro coisas. O arranjo
   continua a ser de cada sítio — uma linha de tabela não é um cartão com
   fotografia — mas a língua é a mesma, e na dúvida é a dos Anúncios: o título
   é o azul do `.titulo-bt`, a linha de contexto é o cinzento do `.c-title
   .sub`, e o preço é o `.preco`. */
.contacto, .mercado-cartao {
  border: 1px solid var(--border); border-radius: var(--raio-bloco);
  background: var(--surface-1); cursor: pointer; text-align: left;
  font: inherit; color: inherit; padding: 0;
}
.contacto:hover, .mercado-cartao:hover { border-color: var(--series-1); }

/* o título */
.contacto .t, .mercado-cartao-tit {
  color: var(--series-1); font-size: 0.82rem; font-weight: 600;
}
.contacto:hover .t, .mercado-cartao:hover .mercado-cartao-tit { text-decoration: underline; }

/* a linha de contexto por baixo dele */
.contacto .m, .mercado-cartao-sub {
  font-size: 0.73rem; font-weight: 400; color: var(--text-muted);
}

/* o número que manda naquela vista: distância no Radar, €/m² no Plano */
.contacto .d, .mercado-cartao-m2 {
  font-size: 1rem; font-weight: 700; color: var(--text-primary);
  font-variant-numeric: tabular-nums; line-height: 1.1;
}
/* A unidade, ou o rumo: diz o que o número é, e não compete com ele. Sem
   maiúsculas forçadas — o rumo já vem em maiúsculas e o «€/m²» não as quer. */
.contacto .d small, .mercado-cartao-m2 small {
  font-size: 0.62rem; font-weight: 500; color: var(--text-muted); letter-spacing: 0.04em;
}

/* o preço, com a bolinha da banda à frente */
.contacto .p, .mercado-cartao-preco {
  display: flex; align-items: center; gap: 6px;
  font-size: 0.86rem; font-weight: 600; font-variant-numeric: tabular-nums;
}
.contacto .p i, .mercado-bolinha {
  width: 8px; height: 8px; border-radius: 50%; background: currentColor;
  display: inline-block; flex: none;
}

/* --------------------------------- painel --------------------------------- */
.painel {
  background: var(--surface-1); border: 1px solid var(--border); border-radius: 12px;
  padding: 14px 16px 20px; min-width: 0;
}
.painel:focus { outline: none; }
.painel:focus-visible { outline: 2px solid var(--series-1); outline-offset: 2px; }
.painel-topo { display: flex; gap: 10px; align-items: flex-start; justify-content: space-between; }
.painel-topo-txt { min-width: 0; }
.painel-accoes { display: flex; gap: 4px; align-items: center; flex: none; }
.painel-habit .frase { margin-top: 6px; }
.fav-linha { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.fav-linha .ctrl-rot { flex: none; }
.fav-linha select, .fav-nota {
  font: inherit; font-size: 0.85rem; background: var(--surface-2); color: var(--text-primary);
  border: 1px solid var(--border); border-radius: 7px; padding: 5px 8px;
}
.fav-nota { display: block; width: 100%; resize: vertical; }
.painel-marcas { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 6px; }
.painel-titulo { margin: 0; font-size: 1.05rem; line-height: 1.3; }
.painel-sub { margin: 3px 0 0; font-size: 0.8rem; color: var(--text-secondary); }
.painel-fechar {
  flex: none; background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 8px; width: 30px; height: 30px; font-size: 1.1rem; line-height: 1;
  color: var(--text-secondary); cursor: pointer;
}
.painel-fechar:hover { color: var(--text-primary); }
.frase {
  margin: 12px 0; padding: 10px 12px; border-radius: 9px; font-size: 0.86rem; line-height: 1.5;
  border: 1px solid var(--border); background: var(--surface-2);
}
.frase-verde { border-left: 4px solid var(--banda-verde); }
.frase-ambar { border-left: 4px solid var(--banda-ambar); }
.frase-vermelho { border-left: 4px solid var(--banda-vermelho); }
.frase-fora { border-left: 4px solid var(--banda-fora); }

.painel-bloco { margin: 16px 0 0; }
.painel-bloco h3 {
  margin: 0 0 6px; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--text-muted); border-bottom: 1px solid var(--border); padding-bottom: 4px;
}
.painel-bloco h4 { margin: 0 0 4px; font-size: 0.78rem; color: var(--text-secondary); }
.factos { display: grid; grid-template-columns: auto 1fr; gap: 2px 12px; margin: 0; font-size: 0.83rem; }
.factos dt { color: var(--text-secondary); }
.factos dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }

.historico { list-style: none; margin: 6px 0 0; padding: 0; font-size: 0.8rem; }
.historico li { display: flex; gap: 10px; justify-content: space-between; padding: 2px 0; }

.ctrls { display: grid; grid-template-columns: repeat(auto-fit, minmax(128px, 1fr)); gap: 8px 12px; margin-bottom: 12px; }
.ctrl { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.ctrl-largo { grid-column: 1 / -1; }
.ctrl-rot {
  font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted);
  display: flex; justify-content: space-between; gap: 8px; font-weight: 600;
}
.ctrl-rot b { color: var(--text-primary); font-size: 0.85rem; text-transform: none; letter-spacing: 0; }
.ctrl-linha { display: flex; align-items: center; gap: 5px; }
.ctrl input[type="number"] {
  width: 100%; min-width: 0; font-size: 0.84rem; text-align: right;
  background: var(--surface-2); color: var(--text-primary);
  border: 1px solid var(--border); border-radius: 6px; padding: 4px 7px;
}
.ctrl input[type="range"] { width: 100%; accent-color: var(--series-1); }
.financas-grelha { display: grid; grid-template-columns: 1fr; gap: 14px; }
.avisos-caixa { margin-top: 14px; }
.avisos { margin: 0; padding-left: 18px; font-size: 0.8rem; color: var(--text-secondary); }
.avisos li { margin-bottom: 3px; }

/* ------------------------------ minigráfico ------------------------------- */
.spark { display: block; width: 100%; height: 52px; margin: 4px 0; }
.spark-base { stroke: var(--baseline); stroke-width: 1; }
.spark-linha { stroke: var(--series-1); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.spark-ponto { fill: var(--series-1); }
.spark-ultimo { fill: var(--text-primary); }

.rodape {
  margin-top: 48px; padding-top: 16px; border-top: 1px solid var(--border);
  color: var(--text-muted); font-size: 0.76rem;
}
.rodape p { max-width: 90ch; }

/* ------------------------------ ecrã largo -------------------------------- */
@media (min-width: 1100px) {
  body.com-painel .layout { grid-template-columns: minmax(0, 1fr) 420px; }
  body.com-painel .painel { position: sticky; top: 12px; max-height: calc(100vh - 24px); overflow-y: auto; }
  body.com-painel .financas-grelha { grid-template-columns: 1fr; }
}
@media (min-width: 560px) and (max-width: 1099px) {
  .financas-grelha { grid-template-columns: 1fr 1fr; }
}

/* ------------------------------- telemóvel --------------------------------
   ≤720 px: as pílulas passam a rolar na horizontal em vez de partirem em
   quatro linhas, o popover ocupa a largura toda, cada linha da tabela vira
   cartão e o painel passa a folha de ecrã inteiro. O cabeçalho da tabela
   sobrevive como uma barra de botões de ordenação — perder a ordenação no
   telemóvel seria perder metade da ferramenta. */
@media (max-width: 720px) {
  main { padding: 0 12px 48px; }
  /* A marca encolhe para a navegação e o comutador caberem na mesma linha:
     três coisas em duas filas, num telemóvel, é o cabeçalho a ocupar um
     sétimo do ecrã antes de a página começar. */
  .topo-linha { padding: 10px 0 6px; }
  .marca { font-size: 1.15rem; gap: 7px; }
  .marca-icone { width: 22px; height: 22px; }
  .procura { max-width: none; }
  .pilulas {
    flex-wrap: nowrap; overflow-x: auto; padding-bottom: 4px;
    -webkit-mask-image: linear-gradient(90deg, #000 93%, transparent);
    mask-image: linear-gradient(90deg, #000 93%, transparent);
  }
  .pop { left: 0 !important; width: 100%; }
  .bandas-op { grid-template-columns: 1fr; }

  .tabela-caixa { overflow: visible; max-height: none; }
  .tabela, .tabela thead, .tabela tbody, .tabela tr, .tabela th, .tabela td { display: block; }
  .tabela thead tr {
    display: flex; flex-wrap: wrap; gap: 4px; padding: 6px 0;
    border-bottom: 1px solid var(--border);
  }
  .tabela th {
    position: static; padding: 3px 8px; border: 1px solid var(--border);
    border-radius: var(--raio-pilula); background: var(--surface-1); font-size: 0.66rem;
  }
  .tabela th.ordem-activa { border-color: var(--series-1); color: var(--series-1); }
  /* Em telemóvel a linha da tabela é mesmo um cartão, e é o cartão do site:
     a superfície, a borda e o raio dos outros. */
  .tabela tbody tr {
    border: 1px solid var(--border); border-radius: var(--raio-bloco); padding: 10px 12px;
    margin: 10px 0; background: var(--surface-1);
  }
  .tabela tbody tr:hover { background: var(--surface-1); }
  /* A barra de filtros é que fica no topo; esta encosta por baixo dela sem
     `top` fixo — a altura da outra muda com o número de pílulas. */
  .barra { position: sticky; top: 0; z-index: 20; }
  /* Em cartão não há colunas: as larguras, o corte e as reticências saem todos
     do caminho, senão um título comprido ficava cortado no sítio onde há ecrã
     inteiro para ele. As larguras lá de cima são por classe
     (`.tabela td.c-price`), portanto o que as desfaz precisa da mesma força —
     `[class]` iguala a especificidade sem ter de repetir as vinte e uma. */
  .tabela th[class], .tabela td[class] { width: auto; overflow: visible; text-overflow: clip; }
  .tabela td {
    display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
    padding: 2px 0; border: 0; text-align: right; white-space: normal;
  }
  .titulo-bt, .c-title .sub {
    white-space: normal; overflow: visible; text-overflow: clip;
    overflow-wrap: anywhere;
  }
  .tabela td::before {
    content: attr(data-rotulo);
    flex: none; font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.04em;
    color: var(--text-muted); font-weight: 600;
  }
  /* O cabeçalho da estrela não é ordenável, e uma pilha de botões de ordenação
     com um "★" morto lá no meio só confunde. A estrela em si fica, no topo do
     cartão, com alvo de toque maior. */
  .tabela th.c-fav { display: none; }
  .tabela td.c-fav { display: block; text-align: left; }
  .tabela td.c-fav::before { display: none; }
  .tabela td.c-fav .estrela { font-size: 1.4rem; padding: 2px 6px 2px 0; }
  .tabela td.c-title, .tabela td.c-banda { display: block; text-align: left; margin-bottom: 6px; }
  .tabela td.c-title::before, .tabela td.c-banda::before { display: none; }
  .c-banda, .c-title { max-width: none; }

  .painel {
    position: fixed; inset: 0; z-index: 60; border-radius: 0; border: 0;
    overflow-y: auto; padding: 14px 14px 60px;
  }
  .painel-topo { position: sticky; top: -14px; background: var(--surface-1); padding: 6px 0; }
  .ctrls { grid-template-columns: 1fr 1fr; }
}

@media print {
  .barra-filtros, .tema, .btn, .barra-accoes, .saltar { display: none !important; }
}

/* Estatísticas da pesquisa na barra de resumo: mediana, média, €/m².
   Menos peso do que a contagem, para ler como contexto e não como título. */


/* --- anúncios por portal: botões com o distintivo da marca ------------------
   Na tabela, só o distintivo (a coluna é estreita); no painel, o botão inteiro
   com nome, preço e data. As cores dos distintivos são das marcas e não do tema,
   por isso ficam iguais em claro e escuro. */
.logo-fonte { display: block; flex: none; border-radius: 6px; }

.fonte-btn {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 2px; border-radius: 8px; line-height: 0;
  border: 1px solid transparent;
  transition: transform 120ms ease, box-shadow 120ms ease, border-color 120ms ease;
}
.fonte-btn:hover, .fonte-btn:focus-visible {
  transform: translateY(-1px);
  border-color: var(--border);
  box-shadow: 0 2px 6px rgba(0,0,0,0.14);
  outline: none;
}
.fonte-btn.sem-link { opacity: 0.55; cursor: default; }

.anuncios-lista { display: flex; flex-direction: column; gap: 6px; }
.anuncio-btn {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px; border-radius: 10px;
  background: var(--surface-2); border: 1px solid var(--border);
  color: var(--text-primary); text-decoration: none;
  transition: transform 120ms ease, box-shadow 120ms ease, border-color 120ms ease;
}
.anuncio-btn:hover, .anuncio-btn:focus-visible {
  transform: translateY(-1px);
  border-color: var(--series-1);
  box-shadow: 0 3px 10px rgba(0,0,0,0.12);
  outline: none;
}
.anuncio-btn.sem-link { opacity: 0.7; cursor: default; }
.anuncio-txt { display: flex; flex-direction: column; min-width: 0; flex: 1; line-height: 1.25; }
.anuncio-nome { font-weight: 600; font-size: 0.9rem; }
.anuncio-sub { font-size: 0.74rem; }
.anuncio-preco { font-weight: 600; white-space: nowrap; }
.anuncio-seta { color: var(--text-muted); font-size: 0.95rem; }

/* ------------------------- o distrito escolhido ---------------------------
   Acrescentado pela ronda dos filtros vivos, sem tocar em nada acima.

   Os chips do distrito são `role="radio"` e por isso dizem-se com
   `aria-checked` — mas o realce da família dos controlos, lá em cima, só
   conhecia `[aria-pressed="true"]`. Resultado: o distrito escolhido não se
   distinguia dos outros a olho, e era metade da queixa («highlight the
   district's bubble, and remove the highlight from any different one»).

   Passar os chips a `aria-pressed` resolvia o desenho e estragava o resto: um
   grupo onde só um pode estar escolhido é um radiogroup, e `aria-pressed` é
   para interruptores. Fica a semântica certa, e o realce é o mesmo — o daqui
   é uma cópia do de `.op.on`, de propósito: tingido, não um bloco cheio.

   `aria-busy` é o distrito que se pediu e ainda não chegou (12 MB, no caso do
   Porto). Não se desliga, para não perder o foco de quem clicou com o teclado;
   os outros ficam desligados enquanto ele vem. */
.chip[aria-checked="true"] {
  border-color: var(--series-1); color: var(--series-1); font-weight: 600;
  background: color-mix(in srgb, var(--series-1) 9%, var(--surface-1));
}
.chip[aria-checked="true"] .chip-n { color: inherit; opacity: 0.8; }
.chip[aria-busy="true"] {
  border-style: dashed; border-color: var(--series-1); color: var(--series-1);
  cursor: progress;
}
.chip:disabled { opacity: 0.45; cursor: default; }
.chip:disabled:hover { border-color: var(--border); color: var(--text-secondary); }
