/* Sistema de diseño del CRM web: paleta del logo + síntesis Editorial,
   Banca privada y Emblema (design/paleta-deal-flow/SINTESIS.md).
   ------------------------------------------------------------------------
   Una sola hoja para todas las páginas (buscador, hoja de parámetros,
   ajustes, canje y privacidad). Nada inline, nada de CDN, nada de build:
   las tipografías viven en static/fuentes/ y todo lo demás son tokens en
   :root, los mismos valores que `app/src/tema.ts` (la fuente de verdad de
   la paleta; allí son un objeto plano porque React Native no tiene CSS
   vars).

   Criterio, en tres capas:
   - Emblema (marca): el caballo dorado y "DEAL FLOW" en versalitas
     espaciadas encabezan el buscador y el canje. El dorado del logo es el
     ÚNICO color de marca y solo aparece en la marca, en la decisión (la
     estrategia que gana), en el botón principal —uno relleno por página
     como mucho— y en los estados activos (foco).
   - Editorial (aire): nada de cajas. Las secciones se separan con espacio
     y un filete dorado al 30%; las filas dentro de una sección, con una
     línea neutra. Cormorant Garamond para precios, direcciones, títulos y
     preguntas de sección; Instrument Sans para todo lo demás; etiquetas
     pequeñas en versalita.
   - Banca privada (precisión): toda cifra es tabular y las de €/m² van en
     tres columnas alineadas. Los semáforos son un punto + versalita, nunca
     un chip relleno ("descartado" = anillo hueco), y siguen siendo
     funcionales: si un color aparece es porque codifica un dato.

   Mobile-first: todo lo de abajo describe el móvil; las media queries solo
   añaden lo que gana el escritorio. */

/* --- Tipografías propias (licencia OFL, auto-alojadas) -------------------
   Ficheros variables del subconjunto latino de Google Fonts, servidos
   desde nuestro dominio (sin CDN ni terceros; rutas exactas en
   crm/api.py::_ESTATICOS_EXACTOS). `font-display: swap` para que el texto
   se lea desde el primer frame con la pila de reserva, y el `unicode-range`
   del subconjunto: un glifo fuera de él cae a la reserva, nunca a un tofu. */
@font-face {
  font-family: "Cormorant Garamond";
  src: url("/static/fuentes/cormorant-garamond.woff2") format("woff2");
  font-weight: 500 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
    U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
    U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Cormorant Garamond";
  src: url("/static/fuentes/cormorant-garamond-italica.woff2") format("woff2");
  font-weight: 500;
  font-style: italic;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
    U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
    U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Instrument Sans";
  src: url("/static/fuentes/instrument-sans.woff2") format("woff2");
  font-weight: 400 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
    U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
    U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* Pizarra: fondo dominante, de más oscuro a más claro. Los nombres
     `marino-*` se conservan (los usa todo el sitio y los tests); ahora
     guardan la escala pizarra del logo. */
  --marino-950: #0E1825;  /* fondo de página y cabecera */
  --marino-900: #172537;  /* superficies base: campos, hover */
  --marino-800: #243346;  /* superficies elevadas */
  --marino-700: #36485E;  /* bordes de campos y botones */
  --marino-600: #495E78;  /* hover de bordes, subrayado del buscador */
  /* Texto: letras blancas sobre la pizarra. */
  --tinta:       #FFFFFF; /* texto principal */
  --tinta-suave: #C6D0DE; /* secundario, etiquetas, fuentes de datos */
  /* Acento: el dorado del logo. Marca, decisión, botón principal, foco. */
  --acento:       #EACD99;
  --acento-claro: #F7E6C7;
  /* Editorial: aire y filetes en vez de cajas. */
  --filete: rgba(234, 205, 153, 0.3); /* entre secciones */
  --linea:  #243346;                  /* entre filas de una sección */
  /* Semáforos (funcionales, no decorativos). El ámbar es naranja a
     propósito: el de antes (#E0B457) se confundía con el dorado. */
  --verde:  #3FBE8C;  /* bajo_precio / encaja */
  --ambar:  #F2994E;  /* en_precio / regular */
  --rojo:   #E0796A;  /* sobre_precio / no encaja */
  --morado: #8B7BB8;  /* KPI excepcional (regla F2 de la Sheet) */
  --sin-dato: #525F6F;

  /* Tipografías: serifa de display en marca, precios, direcciones,
     títulos y preguntas; sans en todo lo demás. */
  --fuente-display: "Cormorant Garamond", Georgia, "Times New Roman", serif;
  --fuente-cuerpo: "Instrument Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --fuente-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* Escala tipográfica (en rem para respetar el tamaño de fuente del
     usuario). La serifa necesita tamaño de display para lucir: por debajo
     de ~20px se usa la sans. */
  --txt-versalita: 0.75rem;   /* 12px, mayúsculas espaciadas */
  --txt-etiqueta:  0.8125rem; /* 13px */
  --txt-cuerpo:    0.9375rem; /* 15px */
  --txt-dato:      1.0625rem; /* 17px */
  --txt-pregunta:  1.3125rem; /* 21px, preguntas de sección en cursiva */
  --txt-h2:        1.625rem;  /* 26px, títulos y direcciones (serifa) */
  --txt-h1:        2rem;      /* 32px */
  --txt-cifra:     1.5rem;    /* 24px, cifras de €/m² (serifa) */
  --txt-precio:    2.5rem;    /* 40px, precio del piso (serifa) */

  /* Ritmo y formas. */
  --esp-xs:  0.375rem; /*  6px */
  --esp-s:   0.625rem; /* 10px */
  --esp-m:   1rem;     /* 16px */
  --esp-l:   1.5rem;   /* 24px */
  --esp-xl:  2rem;     /* 32px */
  --esp-xxl: 3rem;     /* 48px */
  --radio-fino: 2px;   /* botones y campos */
  --radio-chip: 999px;
  --toque: 2.75rem;    /* 44px: área mínima de toque */
  --ancho-texto: 45rem; /* 720px: longitud de línea legible */
  --transicion: 150ms ease;

  /* Iconos de CSS (trazos de Feather) para los <summary>, que el JS pinta
     como texto: se aplican como máscara, así toman el color del texto. */
  --ico-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  --ico-info: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' y1='16' x2='12' y2='12'/%3E%3Cline x1='12' y1='8' x2='12.01' y2='8'/%3E%3C/svg%3E");

  color-scheme: dark; /* barras de scroll y desplegables nativos en oscuro */
}

/* --- Reset mínimo -------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

body, h1, h2, h3, h4, p, ul, ol, dl, dd, figure, fieldset, legend {
  margin: 0;
  padding: 0;
}

ul, ol { list-style: none; }

fieldset { border: 0; min-width: 0; }

img, svg { max-width: 100%; display: block; }

input, select, textarea, button { font: inherit; color: inherit; }

/* --- Tipografía y superficie base ---------------------------------------- */
body {
  min-height: 100vh;
  font-family: var(--fuente-cuerpo);
  font-size: var(--txt-cuerpo);
  line-height: 1.55;
  color: var(--tinta);
  background: var(--marino-950);
  -webkit-font-smoothing: antialiased;
}

h1, h2 {
  font-family: var(--fuente-display);
  font-weight: 600;
  line-height: 1.15;
}
h1 { font-size: var(--txt-h1); }
h2 { font-size: var(--txt-h2); font-weight: 500; }
h3, h4 { font-size: var(--txt-dato); font-weight: 600; }

p + p { margin-top: var(--esp-s); }

/* Enlaces en tinta con subrayado de filete: el dorado se queda en el
   subrayado y solo se enciende al pasar por encima. */
a {
  color: var(--tinta);
  text-decoration-line: underline;
  text-decoration-color: var(--filete);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
  transition: text-decoration-color var(--transicion), color var(--transicion);
}
a:hover { text-decoration-color: var(--acento); }

strong { font-weight: 600; color: var(--tinta); }

::selection { background: var(--acento); color: var(--marino-950); }

/* Foco visible SIEMPRE, en cualquier control (requisito de accesibilidad):
   anillo dorado, que nunca se confunde con un semáforo. */
:focus-visible {
  outline: 2px solid var(--acento);
  outline-offset: 2px;
}

/* Las únicas transiciones del sitio son de 150ms; quien pida menos
   movimiento no ve ninguna. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}

/* --- Clases base --------------------------------------------------------- */

/* Solo para lectores de pantalla: el texto existe (nombre accesible) pero
   no ocupa sitio. */
.solo-lector {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Versalita: las etiquetas pequeñas de la dirección Editorial. `.eyebrow`
   y `.titulo` son las clases que ya pintan las plantillas. */
.versalita,
.eyebrow,
.titulo {
  font-family: var(--fuente-cuerpo);
  font-size: var(--txt-versalita);
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--tinta-suave);
}

/* Cifras: siempre tabulares para que las columnas de precios cuadren, y de
   caja alta: Cormorant trae por defecto cifras elzevirianas (con
   descendentes), que en un precio parecen más pequeñas de lo que son. */
.dato-numerico,
.precio,
.meta,
.cifras,
.kpi-lim,
.paginacion,
#meta-version,
input[type="number"] {
  font-variant-numeric: lining-nums tabular-nums;
}

/* Iconos SVG en línea (trazos de Feather): toman el color del texto. */
.icono {
  display: inline-block;
  flex: none;
  width: 1.125rem;
  height: 1.125rem;
  vertical-align: -0.2em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Marca (dirección Emblema): el caballo dorado + "DEAL FLOW" en versalitas
   espaciadas de la serifa. */
.marca {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--fuente-display);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--acento);
}
.marca img { height: 2.25rem; width: auto; }

/* --- Botones ------------------------------------------------------------- */
/* Base (= secundario): borde pizarra, sin relleno, tinta. El dorado se
   reserva para el principal. */
button,
.boton-secundario {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--esp-xs);
  min-height: var(--toque);
  padding: 0.5rem 1rem;
  border: 1px solid var(--marino-700);
  border-radius: var(--radio-fino);
  background: transparent;
  color: var(--tinta);
  font-size: var(--txt-cuerpo);
  font-weight: 500;
  line-height: 1.2;
  cursor: pointer;
  transition: background-color var(--transicion), border-color var(--transicion),
    color var(--transicion);
}
button:hover,
.boton-secundario:hover {
  background: var(--marino-900);
  border-color: var(--marino-600);
}

/* Primario: dorado macizo con tinta pizarra (11.6:1). Uno por página como
   mucho. `.primario` es la clase que ya usan las plantillas;
   `.boton-primario` es la del sistema. */
.boton-primario,
button.primario {
  background: var(--acento);
  border-color: var(--acento);
  color: var(--marino-950);
  font-weight: 600;
}
.boton-primario:hover,
button.primario:hover {
  background: var(--acento-claro);
  border-color: var(--acento-claro);
}

button:disabled,
button:disabled:hover {
  opacity: 0.4;
  cursor: default;
  background: transparent;
  border-color: var(--marino-700);
}

/* Terciario: solo texto (+ icono), sin borde. */
.boton-terciario,
.boton-icono {
  border-color: transparent;
  padding-inline: 0.25rem;
  color: var(--tinta-suave);
}
.boton-terciario:hover,
.boton-icono:hover {
  background: transparent;
  border-color: transparent;
  color: var(--tinta);
}
/* Icono solo (quitar, borrar): cuadrado de 44px para el dedo. */
.boton-icono { width: var(--toque); padding: 0; }

/* Botón que se comporta como enlace (Salir, Aplicar, …). */
.enlace-boton {
  min-height: 0;
  background: none;
  border: none;
  padding: 0;
  color: var(--tinta);
  text-decoration: underline;
  text-decoration-color: var(--filete);
  text-underline-offset: 0.22em;
}
.enlace-boton:hover {
  background: none;
  border-color: transparent;
  text-decoration-color: var(--acento);
}

/* --- Formularios --------------------------------------------------------- */
label {
  font-size: var(--txt-etiqueta);
  color: var(--tinta-suave);
}

input, select, textarea {
  width: 100%;
  min-height: var(--toque);
  padding: 0.5rem 0.75rem;
  background: var(--marino-900);
  border: 1px solid var(--marino-700);
  border-radius: var(--radio-fino);
  color: var(--tinta);
  font-size: 1rem; /* 16px: iOS no hace zoom al enfocar */
  transition: border-color var(--transicion), background-color var(--transicion);
}
textarea { min-height: 0; }
input:hover, select:hover, textarea:hover { border-color: var(--marino-600); }
/* Campo enfocado = estado activo: borde dorado, que ya es foco visible. */
input:focus, select:focus, textarea:focus,
input:focus-visible, select:focus-visible, textarea:focus-visible {
  border-color: var(--acento);
  outline: none;
}
input::placeholder, textarea::placeholder { color: var(--tinta-suave); opacity: 0.7; }
input:disabled, select:disabled, textarea:disabled {
  background: transparent;
  color: var(--tinta-suave);
  cursor: not-allowed;
}
input[type="checkbox"] {
  width: 1.1rem;
  height: 1.1rem;
  min-height: 0;
  padding: 0;
  accent-color: var(--acento);
}

.campo { display: flex; flex-direction: column; gap: 0.25rem; }
/* Dos campos por fila ya en el móvil (los filtros abiertos no pueden
   comerse una pantalla entera); una sola columna cuando no caben. */
.rejilla {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));
  gap: var(--esp-m) var(--esp-s);
}
.acciones {
  display: flex;
  gap: var(--esp-s);
  margin-top: var(--esp-l);
  flex-wrap: wrap;
}

/* --- Cabecera ------------------------------------------------------------ */
.barra {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--esp-s) var(--esp-m);
  flex-wrap: wrap;
  padding: var(--esp-s) var(--esp-m);
  background: var(--marino-950);
  border-bottom: 1px solid var(--filete);
}
.barra h1 { font-size: 1.5rem; }
.barra nav {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0 var(--esp-xs);
  font-size: var(--txt-etiqueta);
}
.barra nav a,
.barra nav .enlace-boton {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: var(--toque);
  min-width: var(--toque);
  justify-content: center;
  padding: 0 0.4rem;
  color: var(--tinta-suave);
  text-decoration: none;
}
.barra nav a:hover,
.barra nav .enlace-boton:hover { color: var(--tinta); }
.barra nav .icono { width: 1.25rem; height: 1.25rem; }
.barra nav #meta-version { color: var(--tinta-suave); margin-right: var(--esp-xs); }
/* Mismo tamaño que `.barra h1` y después: la marca manda en su cabecera. */
.barra h1.marca { font-size: 1.25rem; }

/* En el móvil la cabecera con marca solo enseña los iconos; el texto sigue
   ahí como nombre accesible (y como `title` al pasar el ratón). */
@media (max-width: 39.99rem) {
  .barra-marca .nav-texto {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* --- Contenedor principal ------------------------------------------------ */
main {
  max-width: 68rem;
  margin: 0 auto;
  padding: var(--esp-l) var(--esp-m) var(--esp-xxl);
}
/* Páginas de lectura y formulario: una columna de ~720px. */
main.columna-texto { max-width: calc(var(--ancho-texto) + 2 * var(--esp-m)); }

/* --- Pantallas de estado (acceso, pago pendiente, canje) ----------------- */
.acceso {
  max-width: 26rem;
  margin: 0 auto;
  padding: var(--esp-xxl) var(--esp-m);
}
/* `color` repetido a propósito: `.acceso p` pisaría el dorado de la marca. */
.acceso > .marca { margin-bottom: var(--esp-xxl); color: var(--acento); }
.acceso h1 { margin-bottom: var(--esp-s); }
.acceso p { color: var(--tinta-suave); }
.acceso .aviso { text-align: left; padding: var(--esp-s) 0 0; }
.acceso form {
  display: flex;
  flex-direction: column;
  gap: var(--esp-s);
  margin-top: var(--esp-l);
}
/* Canje: un momento de marca tranquilo, todo centrado. */
.acceso.centrado { text-align: center; padding-top: 18vh; }
.acceso.centrado .aviso { text-align: center; }
.marca-vertical {
  flex-direction: column;
  gap: var(--esp-m);
  font-size: 1.125rem;
}
.marca-vertical img { height: 4.5rem; }
/* Filete corto bajo la marca: separa sin encerrar. */
.marca-vertical::after {
  content: "";
  width: 1.5rem;
  height: 1px;
  background: var(--acento);
}

/* --- Buscador: disposición ------------------------------------------------
   Mobile-first: una sola columna, con la búsqueda, los filtros (plegables)
   y las búsquedas guardadas encima del listado. El escritorio los pasa a
   columna lateral. Las secciones de la columna se separan con filete. */
.disposicion {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--esp-xl);
}
.columna-lateral {
  display: flex;
  flex-direction: column;
  gap: var(--esp-l);
}
.columna-lateral > * + * {
  border-top: 1px solid var(--filete);
  padding-top: var(--esp-l);
}
.columna-resultados { min-width: 0; max-width: var(--ancho-texto); }

/* --- Buscador: caja de búsqueda libre (F10) -------------------------------
   Estilo Editorial: la zona escrita en serifa grande sobre una sola línea,
   sin caja; el botón de al lado es el único dorado relleno de la página. */
.buscador-texto { display: flex; flex-direction: column; gap: var(--esp-xs); }
.buscador-texto label,
.rejilla label {
  font-size: var(--txt-versalita);
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}
.buscador-texto-fila { display: flex; align-items: flex-end; gap: var(--esp-s); }
.buscador-texto-fila input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 3rem;
  padding: 0.25rem 0;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--marino-600);
  border-radius: 0;
  font-family: var(--fuente-display);
  font-size: 1.625rem;
  font-weight: 500;
}
.buscador-texto-fila input::placeholder {
  font-style: italic;
  font-size: 1.25rem;
}
.buscador-texto-fila input:focus { border-bottom-color: var(--acento); background: transparent; }

/* --- Pliegues (<details>) -------------------------------------------------
   Todos los summary llevan el mismo chevron de Feather (máscara de CSS,
   hereda el color) que gira al abrirse. Nada de esto lo toca el JS. */
.filtros > summary,
.desplegable > summary,
.onboarding-detalle > summary,
.veredicto-det summary {
  display: flex;
  align-items: center;
  gap: var(--esp-s);
  cursor: pointer;
  list-style: none; /* fuera el triángulo del navegador: ponemos el nuestro */
}
.filtros > summary::-webkit-details-marker,
.desplegable > summary::-webkit-details-marker,
.onboarding-detalle > summary::-webkit-details-marker,
.veredicto-det summary::-webkit-details-marker { display: none; }
.filtros > summary::after,
.desplegable > summary::after,
.veredicto-det summary::after {
  content: "";
  flex: none;
  width: 1.1rem;
  height: 1.1rem;
  background: var(--tinta-suave);
  -webkit-mask: var(--ico-chevron) center / contain no-repeat;
  mask: var(--ico-chevron) center / contain no-repeat;
  transition: transform var(--transicion);
}
.filtros[open] > summary::after,
.desplegable[open] > summary::after,
.veredicto-det details[open] summary::after { transform: rotate(180deg); }

/* --- Buscador: filtros y búsquedas guardadas ----------------------------- */
/* El panel de filtros es un <details>: en móvil se pliega con su summary; en
   escritorio el summary desaparece y queda siempre abierto (ver la media
   query de 900px). */
.filtros > summary {
  justify-content: space-between;
  min-height: var(--toque);
}
.filtros[open] > summary { margin-bottom: var(--esp-s); }

.campo-oculta-descartados { flex-direction: row; margin-top: var(--esp-m); }
.campo-oculta-descartados label {
  display: flex;
  align-items: center;
  gap: var(--esp-s);
  min-height: var(--toque);
  color: var(--tinta);
  font-size: var(--txt-cuerpo);
  cursor: pointer;
}

.umbrales { margin-top: var(--esp-l); }
.umbrales > .titulo { margin-bottom: var(--esp-xs); }
/* El campo ocupa su propia línea; operador + valor + quitar comparten la
   segunda (en 280px no caben los cuatro sin estrujar el campo). */
.umbral-fila {
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 1fr) auto;
  gap: var(--esp-xs);
  padding-block: var(--esp-s);
  border-bottom: 1px solid var(--linea);
}
.umbral-fila .u-campo { grid-column: 1 / -1; }

.guardadas > .titulo { margin-bottom: var(--esp-xs); }
.guardadas ul { display: flex; flex-direction: column; }
.guardadas li {
  display: flex;
  align-items: center;
  gap: var(--esp-s);
  min-height: var(--toque);
  border-top: 1px solid var(--linea);
}
.guardadas li:first-child { border-top: 0; }
.guardadas li .nombre { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.guardadas li .aplicar { flex: 0 0 auto; font-size: var(--txt-etiqueta); }
.guardadas li .borrar { flex: 0 0 auto; }
.guardadas li.aviso { padding: var(--esp-s) 0; text-align: left; font-size: var(--txt-etiqueta); }

/* --- Paginación ---------------------------------------------------------- */
.paginacion {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--esp-m);
  margin-top: var(--esp-l);
  padding-top: var(--esp-l);
  border-top: 1px solid var(--filete);
  font-size: var(--txt-etiqueta);
  color: var(--tinta-suave);
}

/* --- Avisos -------------------------------------------------------------- */
.aviso {
  text-align: center;
  color: var(--tinta-suave);
  padding: var(--esp-l) var(--esp-m);
}
.aviso.error { color: var(--rojo); }
.aviso.ok { color: var(--verde); }
#avisos .aviso { text-align: left; padding-inline: 0; }

/* --- Chips de semáforo ----------------------------------------------------
   Punto de 7px + versalita, nunca relleno (dirección Banca privada). El
   texto va en el color del semáforo cuando pasa AA sobre la pizarra
   (verde 7.9:1, ámbar 7.5:1, rojo 6.1:1, morado 4.8:1, dorado 11.6:1); los
   estados apagados (sin dato, nuevo, descartado) llevan tinta suave,
   porque --sin-dato como texto no llegaría (2.8:1).
   La base va ANTES que todos los modificadores: así un modificador de
   seguimiento nunca queda pisado por `.chip` (el fallo de "Sin marcar",
   que salía con tinta oscura sobre transparente). */
.chip {
  --punto: var(--sin-dato);
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-family: var(--fuente-cuerpo);
  font-size: var(--txt-versalita);
  font-weight: 600;
  font-style: normal;
  line-height: 1.4;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--tinta-suave);
  white-space: nowrap;
}
.chip::before {
  content: "";
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: var(--radio-chip);
  background: var(--punto);
}
/* Semáforo de precio (F1). */
.sp-bajo  { --punto: var(--verde); color: var(--verde); }
.sp-en    { --punto: var(--ambar); color: var(--ambar); }
.sp-sobre { --punto: var(--rojo);  color: var(--rojo); }
.sp-sindato { --punto: var(--sin-dato); }
/* Veredicto por estrategia. */
.v-verde { --punto: var(--verde); color: var(--verde); }
.v-ambar { --punto: var(--ambar); color: var(--ambar); }
.v-rojo  { --punto: var(--rojo);  color: var(--rojo); }
/* Embudo de seguimiento: una sola correspondencia en todo el producto
   (la de `SeguimientoBadge.infoEstado` en la app). */
.seg-nuevo     { --punto: var(--sin-dato); }
.seg-interesa  { --punto: var(--verde);  color: var(--verde); }
.seg-visitado  { --punto: var(--acento); color: var(--acento); }
.seg-ofertado  { --punto: var(--ambar);  color: var(--ambar); }
.seg-comprado  { --punto: var(--morado); color: var(--morado); }
/* Descartado = anillo hueco: está, pero apagado. */
.v-descartado::before,
.seg-descartado::before {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--sin-dato);
}
/* Verificar (`requiere_verificacion`): no es un descarte sino un requisito
   legal que el anuncio no declara. Anillo ámbar hueco: ni verde ni apagado. */
.v-verificar { --punto: var(--ambar); color: var(--ambar); }
.v-verificar::before {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--ambar);
}
/* Sin marcar = anillo discontinuo: todavía no hay estado. */
.seg-sin-marcar::before {
  background: transparent;
  border: 1px dashed var(--tinta-suave);
}

/* --- Onboarding del buscador (estado inicial, sin búsqueda oculta) -------- */
/* Se pinta en vez de una búsqueda con filtros vacíos: no hay "zonas por
   defecto", así que el hueco donde iban los resultados enseña qué hace la
   pantalla en vez de fingir un listado. */
.onboarding h2 { margin-bottom: var(--esp-m); font-style: italic; }
.onboarding p { color: var(--tinta-suave); }
.onboarding-detalle {
  margin-top: var(--esp-l);
  padding-top: var(--esp-s);
  border-top: 1px solid var(--linea);
}
/* Ayuda = icono de información + texto en tinta suave. */
.onboarding-detalle > summary {
  min-height: var(--toque);
  color: var(--tinta-suave);
}
.onboarding-detalle > summary::before {
  content: "";
  flex: none;
  width: 1.1rem;
  height: 1.1rem;
  background: currentColor;
  -webkit-mask: var(--ico-info) center / contain no-repeat;
  mask: var(--ico-info) center / contain no-repeat;
}
.onboarding-detalle > summary:hover { color: var(--tinta); }
.onboarding-detalle p { margin-top: var(--esp-s); }

/* --- Umbrales que no filtran como se espera (`avisos_umbrales`) ----------- */
.aviso-umbrales {
  padding-bottom: var(--esp-m);
  color: var(--ambar);
  font-size: var(--txt-etiqueta);
}
.aviso-umbrales ul { margin: var(--esp-s) 0 0; padding-left: 1.2em; color: var(--tinta-suave); }

/* --- Aviso de descartados ocultos (F10) ----------------------------------- */
.aviso-ocultos {
  display: flex;
  gap: var(--esp-s);
  padding-bottom: var(--esp-m);
  color: var(--tinta-suave);
  font-size: var(--txt-etiqueta);
}
.aviso-ocultos::before {
  content: "";
  flex: none;
  width: 1rem;
  height: 1rem;
  margin-top: 0.15em;
  background: currentColor;
  -webkit-mask: var(--ico-info) center / contain no-repeat;
  mask: var(--ico-info) center / contain no-repeat;
}

/* --- Ficha de piso --------------------------------------------------------
   Sin caja: cada ficha empieza con un filete dorado y respira. Orden de
   lectura: semáforo de precio, precio, dirección, las tres cifras de €/m²
   y la decisión. */
.tarjeta {
  padding-block: var(--esp-xl);
  border-top: 1px solid var(--filete);
}
.tarjeta-cabecera {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--esp-xs) var(--esp-m);
  flex-wrap: wrap;
}
.tarjeta-cabecera .eyebrow { overflow-wrap: anywhere; }
.tarjeta .precio {
  margin-top: var(--esp-m);
  font-family: var(--fuente-display);
  font-size: var(--txt-precio);
  font-weight: 500;
  line-height: 1;
  color: var(--tinta);
}
/* La unidad acompaña, no compite: más pequeña y en tinta suave. */
.unidad {
  font-size: 0.6em;
  color: var(--tinta-suave);
}
.tarjeta .direccion {
  margin-top: var(--esp-s);
  font-family: var(--fuente-display);
  font-size: var(--txt-h2);
  font-weight: 500;
  line-height: 1.2;
  overflow-wrap: break-word;
}
.tarjeta .meta {
  margin-top: var(--esp-xs);
  color: var(--tinta-suave);
  font-size: var(--txt-etiqueta);
}

/* €/m² en tres columnas alineadas (Banca privada): este piso · se pide ·
   se firma. Regla de producto F5: la fuente y la fecha de cada cifra de
   referencia siguen a la vista, como nota bajo la cifra. */
.cifras {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--esp-m);
  margin-top: var(--esp-l);
  padding-top: var(--esp-m);
  border-top: 1px solid var(--linea);
}
.cifras dt {
  font-size: var(--txt-versalita);
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--tinta-suave);
}
.cifras .cifra {
  margin-top: 0.2rem;
  font-family: var(--fuente-display);
  font-size: var(--txt-cifra);
  font-weight: 500;
  line-height: 1.15;
}
.cifras .cifra-nota {
  font-size: var(--txt-etiqueta);
  line-height: 1.35;
  color: var(--tinta-suave);
  overflow-wrap: anywhere;
}

/* La decisión: el único dorado de la ficha. Filete corto + versalita +
   el nombre de la estrategia en serifa. */
.decision { margin-top: var(--esp-l); }
.decision-rotulo {
  display: flex;
  align-items: center;
  gap: var(--esp-s);
  font-size: var(--txt-versalita);
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--acento);
}
.decision-rotulo::before {
  content: "";
  width: 1.5rem;
  height: 1px;
  background: currentColor;
}
.decision-nombre {
  margin-top: 0.15rem;
  font-family: var(--fuente-display);
  font-size: var(--txt-h2);
  font-weight: 500;
  line-height: 1.2;
  color: var(--acento-claro);
}
/* Sin ganadora no hay dorado: la frase en cursiva y en tinta suave. */
.decision.sin-ganadora .decision-rotulo { color: var(--tinta-suave); }
.decision.sin-ganadora .decision-rotulo::before { background: var(--sin-dato); }
.decision.sin-ganadora .decision-nombre { font-style: italic; color: var(--tinta-suave); }

.veredictos {
  display: flex;
  flex-direction: column;
  margin-top: var(--esp-m);
}
.veredicto {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  align-items: flex-start;
  padding-block: var(--esp-xs);
  border-top: 1px solid var(--linea);
}
.veredicto-det { font-size: var(--txt-etiqueta); color: var(--tinta-suave); }
/* Ya no es una clave del JSON sino su nombre humano: fuente de texto, no de código. */
.kpi-lim { font-family: var(--fuente-cuerpo); color: var(--tinta); }
/* Los chips del veredicto llevan el nombre entero de la estrategia
   ("Comprar, reformar y vender · Verde"): en móvil tienen que poder partir línea. */
.veredicto .chip { white-space: normal; }
.veredicto-det summary { color: var(--tinta-suave); min-height: 2rem; }
.veredicto-det summary:hover { color: var(--tinta); }
.veredicto-det summary::after { width: 0.9rem; height: 0.9rem; }

/* --- Embudo de seguimiento + enlace al anuncio + desplegables (F10) ------- */
.ficha-extra {
  margin-top: var(--esp-l);
  display: flex;
  flex-direction: column;
}
.seguimiento-fila {
  display: flex;
  align-items: center;
  gap: var(--esp-s) var(--esp-m);
  flex-wrap: wrap;
  padding-bottom: var(--esp-s);
}
.seguimiento-fila .sel-seguimiento { width: auto; flex: 0 0 auto; }

.enlace-anuncio {
  padding-bottom: var(--esp-m);
  font-size: var(--txt-etiqueta);
  color: var(--tinta-suave);
}
.enlace-anuncio a { display: inline-flex; align-items: center; gap: 0.3rem; }
.enlace-anuncio .icono { width: 0.95rem; height: 0.95rem; }

/* Secciones "bajo demanda" de la ficha: cargan solo al desplegarse (nunca al
   abrir la tarjeta), así que empiezan siempre plegadas. Cada una es una
   pregunta de sección: serifa en cursiva, sin caja, línea entre filas. */
.desplegable { border-top: 1px solid var(--linea); }
.desplegable > summary {
  justify-content: space-between;
  min-height: 3rem;
  padding-block: var(--esp-xs);
  font-family: var(--fuente-display);
  font-size: var(--txt-pregunta);
  font-style: italic;
  font-weight: 500;
  line-height: 1.25;
  color: var(--tinta);
}
.desplegable > summary:hover::after { background: var(--tinta); }
.desplegable-contenido {
  padding-bottom: var(--esp-l);
  color: var(--tinta-suave);
  display: flex;
  flex-direction: column;
  gap: var(--esp-s);
}
.desplegable-contenido .aviso { text-align: left; padding: 0; }
.desplegable-contenido ul {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding-left: 1.1rem;
  list-style: disc;
}
.desplegable-contenido li::marker { color: var(--sin-dato); }
.rastro-avisos { color: var(--ambar); }
.sensibilidad-estrategia { padding-block: var(--esp-s); }
.sensibilidad-estrategia + .sensibilidad-estrategia { border-top: 1px solid var(--linea); }
.sensibilidad-estrategia h4 {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--esp-xs) var(--esp-s);
  margin-bottom: var(--esp-xs);
  font-family: var(--fuente-display);
  font-size: 1.25rem;
  font-weight: 500;
  line-height: 1.25;
  color: var(--tinta);
}
.palancas { margin-top: var(--esp-xs); }

/* --- "¿Por qué este piso?" (Tarea 3: la ficha que explica) ---------------
   Bloques separados por una línea fina, cada uno con su <h4> en tinta llena
   (el resto del contenido va en tinta suave): esto es lo primero que hay
   que leer de la ficha, no una nota al pie. */
.explicacion-ficha .desplegable-contenido { gap: var(--esp-m); }
.explicacion-bloque h4 {
  margin-bottom: 0.25rem;
  font-size: var(--txt-cuerpo);
  font-weight: 600;
  color: var(--tinta);
}
.explicacion-bloque + .explicacion-bloque {
  border-top: 1px solid var(--linea);
  padding-top: var(--esp-m);
}

/* --- Hoja de parámetros (formulario genérico sobre el JSON, F5) ----------
   Las secciones de primer nivel del JSON (profile, strategies…) son
   `.panel` con h2 en serifa, separadas por filete; lo que anida dentro
   (objetos de segundo nivel en adelante) es un fieldset sin caja: una línea
   arriba con la versalita encima. */
.panel { padding-block: var(--esp-xl); }
.panel + .panel { border-top: 1px solid var(--filete); }
.panel > h2 { margin-bottom: var(--esp-m); }
#form-hoja > .panel:first-child { padding-top: var(--esp-s); }

.campo-objeto {
  margin: var(--esp-l) 0 var(--esp-m);
  padding: var(--esp-s) 0 0;
  border-top: 1px solid var(--linea);
}
.campo-objeto .campo-objeto { margin-left: var(--esp-m); }
.campo-objeto legend {
  padding-right: var(--esp-s);
  font-size: var(--txt-versalita);
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--tinta-suave);
}
.campo-bool label {
  display: flex;
  align-items: center;
  gap: var(--esp-s);
  min-height: var(--toque);
  color: var(--tinta);
  font-size: var(--txt-cuerpo);
  cursor: pointer;
}
.campo-array textarea {
  font-family: var(--fuente-mono);
  font-size: var(--txt-etiqueta);
}
.campo-error {
  min-height: 1em;
  margin-top: 0.2rem;
  font-size: var(--txt-etiqueta);
  color: var(--rojo);
}
#avisos ul { margin: var(--esp-xs) 0 0; padding-left: 1.2rem; list-style: disc; }
#form-hoja > .campo,
#form-hoja .panel > .campo,
#form-hoja .campo-objeto > .campo { margin-bottom: var(--esp-m); }
#form-hoja .acciones {
  padding-top: var(--esp-l);
  border-top: 1px solid var(--filete);
}

/* --- Ajustes (web, Tarea 2) -----------------------------------------------
   Equivalente web de PantallaAjustes.tsx: una columna de secciones, sin la
   disposición a dos columnas del buscador (aquí no hay nada que ir
   filtrando al lado). */
.ajustes-secciones {
  max-width: var(--ancho-texto);
  margin: 0 auto;
}
.ajustes-secciones p { color: var(--tinta-suave); }
.ajustes-secciones .boton-secundario { margin-top: var(--esp-m); }
.ajustes-secciones a .icono { display: inline-block; margin-left: 0.25rem; }

/* --- Política de privacidad ------------------------------------------------ */
.legal {
  max-width: calc(var(--ancho-texto) + 2 * var(--esp-m));
  line-height: 1.65;
}
.legal > .marca { margin-bottom: var(--esp-xl); text-decoration: none; }
.legal h1 { margin-bottom: var(--esp-xs); }
.legal h2 {
  margin-top: var(--esp-xl);
  margin-bottom: var(--esp-s);
  padding-top: var(--esp-l);
  border-top: 1px solid var(--filete);
}
.legal p, .legal li { color: var(--tinta-suave); }
.legal ul {
  display: flex;
  flex-direction: column;
  gap: var(--esp-xs);
  padding-left: 1.1rem;
  list-style: disc;
}
.legal ul + p { margin-top: var(--esp-s); }
.legal li::marker { color: var(--sin-dato); }

/* --- Escritorio ---------------------------------------------------------- */
@media (min-width: 40rem) {
  .rejilla { grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); }
  .barra .marca img { height: 2.5rem; }
}

@media (min-width: 900px) {
  h1 { font-size: 2.25rem; } /* 36px */
  .barra { padding: var(--esp-s) var(--esp-l); }
  main { padding: var(--esp-xl) var(--esp-l) var(--esp-xxl); }
  main.columna-texto { max-width: calc(var(--ancho-texto) + 2 * var(--esp-l)); }
  .tarjeta .precio { font-size: 2.75rem; }

  /* Columna lateral fija de 280px con la búsqueda, los filtros y las
     búsquedas guardadas; el listado se queda con el resto (minmax(0,…) para
     que una ficha ancha no desborde la rejilla). */
  .disposicion {
    grid-template-columns: 280px minmax(0, 1fr);
    gap: var(--esp-xxl);
    align-items: start;
  }

  /* Los filtros dejan de plegarse: sin summary no hay manera de cerrarlos.
     `::details-content` reabre el panel en los navegadores que lo soportan
     por si el usuario lo había plegado antes de ensanchar la ventana; el
     resto se apoya en el atributo `open` con el que nace el panel. */
  .filtros > summary { display: none; }
  .filtros::details-content {
    content-visibility: visible;
    block-size: auto;
  }
}
