  /* --------------------------------------------------------------------------
     Las variables que necesita ESTE archivo y que styles.css no tiene.

     Viven aquí y no en buscador-base.css porque la página de búsqueda del
     sitio carga solo este archivo (su reset, su tipografía y su nav ya vienen
     de styles.css). Si estuvieran en la base, en esa página `--pfsnav-h`
     saldría vacía y la barra de filtros se pegaría en top:0, debajo del nav y
     por tanto invisible en cuanto se scrollea.

     Las de marca (--midnight, --sand, --ivory…) NO se repiten: en la landing
     las trae la base y en el buscador del sitio, styles.css.
     -------------------------------------------------------------------------- */
  :root{
    /* Alto del nav sticky = 104 de barra + 3 del borde arena. Lo consume la
       barra de filtros para pegarse DEBAJO y no quedar tapada. Eran 88+3 hasta
       que la barra con enlaces pasó a ser la del sitio entero (ago-2026); este
       valor es una COPIA del de styles.css y hay que moverlo con él. */
    --pfsnav-h:107px;
    /* Azul de selección del mapa. NO es color de marca: existe solo para el
       estado activo de pines y discos, donde el navy se pierde contra el
       fondo. Fuera del mapa, azul = --midnight. */
    --azul-sel:#1668a5;
    --font-serif:Georgia,'Times New Roman',serif;
    --font-body:'Montserrat','Helvetica Neue',Arial,sans-serif;
  }
  @media (max-width:640px){
    /* La barra baja a 80 + 3 del borde. Si esta variable no acompaña, la fila
       de filtros se pega 16 px más abajo de lo que debe y deja una franja de
       fondo colándose entre las dos. */
    :root{--pfsnav-h:83px;}
  }

  /* ---- Barra de búsqueda + filtros (fila 2 de Zillow) ----
     top:var(--pfsnav-h) y no top:0. Ahora hay DOS barras pegajosas: el nav del
     sitio (z-index 60) y ésta (20). Con las dos en top:0 se superponen y el
     nav, que va por encima, tapa entera la fila de filtros — la landing se
     queda sin precio, sin habitaciones y sin operación en cuanto se scrollea.
     Pegándola justo debajo del nav las dos quedan visibles y apiladas. */
  .searchbar{background:#fff;border-bottom:1px solid #e3e4e7;position:sticky;top:var(--pfsnav-h);z-index:20;}
  /* Sin `max-width:1560px;margin:0 auto`: la fila va de lado a lado como la de
     Zillow, y como ya iban el nav (.pfsnav__inner es width:100%) y el split de
     abajo. Con el tope puesto, en una pantalla ancha la barra quedaba centrada
     y más estrecha que el mapa que tiene debajo. */
  .searchbar__in{padding:10px 24px;display:flex;flex-wrap:wrap;gap:10px;align-items:center;}
  /* La caja de búsqueda crece con la ventana pero CON TOPE, como la de Zillow.
     Antes se quedaba con todo el sobrante y a 1440 medía 1.015 px contra los
     411 px de Zillow —dos veces y media— para escribir "Brickell": una caja de
     texto de un metro de ancho leída como el elemento dominante de la página.

     La referencia sale de medir su página, no a ojo (captura a 1440, ago-2026):
     su input va de x=90 a x=500, o sea 411 px = 28,5% de la ventana, con la
     píldora "For sale" pegada detrás a 8 px.

     El tope de aquí es DELIBERADAMENTE más ancho que el de Zillow: se probó con
     `min(620px, 30vw)` —427 px a 1440, o sea el de ellos clavado— y Mateo lo
     pidió un poco más largo (ago-2026). Con `min(680px, 35vw)` son 498 px a 1440
     y 672 a 1920: ~21% por encima de la proporción de Zillow, todavía lejos de
     los 1.015 px de los que venía. El tope duro evita que en un monitor
     ultraancho vuelva a ser una pista de aterrizaje.

     El `flex-basis` de 380 px se queda como SUELO: por debajo de ~1270 px de
     ventana el 30vw sería más estrecho que eso y la caja dejaría de admitir una
     dirección entera.

     Cuidado con el hueco de la derecha: el sobrante que la caja ya no se queda
     se va al final de la fila (~600 px a 1440). En Zillow ese hueco son 72 px,
     pero porque su barra lleva SEIS controles —For sale, Price, Beds & baths,
     Property type, Filters, Save search— y esta lleva tres. Si algún día
     estorba, la salida es añadir controles o estirar las píldoras, no volver a
     estirar la caja. */
  .zsearch{position:relative;display:flex;align-items:center;flex:1 1 380px;min-width:220px;}
  /* El tope SOLO en escritorio. Suelto se aplicaba también en móvil, donde 35vw
     de 390px son 136px: el `min-width:220px` ganaba, la caja dejaba de llenar su
     fila y el placeholder salía cortado ("Buscar zona o dire…") con 140px de
     hueco muerto al lado. En móvil la caja tiene que ocupar la fila entera —
     es el control principal y no compite con nada, porque las píldoras van
     debajo. */
  @media (min-width:1025px){
    .zsearch{max-width:min(680px,35vw);}
  }
  .zsearch input{
    width:100%;font-family:var(--font-body);font-size:.95rem;font-weight:500;color:var(--midnight);
    border:1px solid #d4d6da;border-radius:8px;padding:10px 66px 10px 14px;background:#fff;
  }
  .zsearch input::-webkit-search-cancel-button{display:none;}
  /* Anillo de foco en azul de marca (--midnight), no en arena: decisión de Mateo
     (ago-2026). Es lo que se enciende al hacer clic en la caja de búsqueda.
     La alfa baja de 0.2 a 0.15 porque el navy es bastante más oscuro que el arena
     y al mismo valor el halo pesaba más que el borde. */
  .zsearch input:focus{outline:none;border-color:var(--midnight);box-shadow:0 0 0 3px rgba(7,32,49,0.15);}
  .zsearch__clear,.zsearch__go{position:absolute;background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;}
  .zsearch__clear{right:38px;color:#9aa0a6;}
  .zsearch__clear svg{width:16px;height:16px;}
  .zsearch__go{right:10px;color:var(--midnight);}

  /* Sugerencias de ZONA bajo el buscador.
     La caja buscaba solo direcciones dentro de la zona actual, y buscar el
     nombre de otra zona no llevaba a ninguna parte — ni siquiera decía que esa
     zona existe. Ahora el nombre de una zona es un destino. */
  .zsug{
    position:absolute;top:calc(100% + 6px);left:0;right:0;z-index:70;
    background:#fff;border:1px solid #e3e5e8;border-radius:8px;
    box-shadow:0 14px 34px rgba(7,32,49,0.16);
    list-style:none;margin:0;padding:5px 0;max-height:60vh;overflow-y:auto;
  }
  .zsug[hidden]{display:none;}
  .zsug__t{padding:6px 13px 4px;font-size:.68rem;letter-spacing:.08em;text-transform:uppercase;color:#9aa0a6;font-weight:700;}
  .zsug__i{display:block;}
  .zsug__b{
    display:flex;align-items:center;gap:9px;width:100%;text-align:left;
    background:none;border:none;cursor:pointer;padding:8px 13px;
    font-family:var(--font-body);font-size:.88rem;color:var(--midnight);
  }
  .zsug__b:hover,.zsug__b.is-on{background:#f2f4f6;}
  .zsug__b[disabled]{cursor:default;color:#9aa0a6;}
  .zsug__pin{width:15px;height:15px;flex:none;color:var(--sand);}
  .zsug__n{margin-left:auto;font-size:.76rem;color:#9aa0a6;font-weight:600;}
  .zsearch__go svg{width:18px;height:18px;}

  /* ---- Barra de filtros: una fila de píldoras, como Zillow. ----
     Fueron <select> nativos disfrazados hasta que se vio el menú abierto: el
     nativo lo dibuja el sistema operativo y no se puede dar aire ni marcar la
     opción elegida, y con diez escalones de precio quedaba ilegible. Ahora son
     desplegables propios (.zdd, más abajo) que conservan el patrón
     listbox/option y el teclado. */
  .zbar__clear{background:none;border:none;color:var(--midnight);font-family:var(--font-body);font-weight:600;font-size:.85rem;cursor:pointer;padding:10px 6px;text-decoration:underline;}
  /* Explícito aunque la clase de arriba no declare `display`: en este archivo
     ya pasó una vez que un `[hidden]` no apagaba nada porque la regla de clase
     ganaba (el contador del botón de filtros, que se veía como un "0" fijo).
     Si alguien le pone un display a .zbar__clear, esto lo cubre. */
  .zbar__clear[hidden]{display:none;}

  /* ---- Desplegable propio (zdd) ----
     Sustituye a los <select> nativos de la barra. El nativo abre la lista del
     sistema operativo: en Windows sale un cuadro gris pegado, sin aire entre
     opciones, sin marcar la elegida más que con un resaltado, y no se puede
     tocar. Con diez escalones de precio eso es una lista ilegible.
     Este mantiene el teclado y aria (listbox/option), que es lo que de verdad
     aporta el nativo, y añade lo que faltaba: separación, la opción elegida con
     su palomita, y ancho suficiente para que no se corte el texto.
     Se usa para operación, precio, orden, unidades y moneda. */
  .zdd{position:relative;display:inline-flex;}
  /* Rectángulo redondeado de 8 px, NO píldora. Los controles eran
     border-radius:100px y ése es el detalle que más delataba que la barra no
     era la de Zillow: la suya usa esquinas de 8 px en la caja de búsqueda y en
     los cinco filtros, y la píldora completa la reserva para las etiquetas
     dentro de las tarjetas. Mismo radio en .zpopbtn y .zfilbtn para que la
     fila se lea como un solo juego de controles. */
  .zdd__btn{
    display:inline-flex;align-items:center;gap:8px;
    font-family:var(--font-body);font-size:.95rem;font-weight:500;color:var(--midnight);
    background:#fff;border:1px solid #d4d6da;border-radius:8px;white-space:nowrap;
    padding:10px 16px;cursor:pointer;line-height:1.2;
    transition:border-color .15s ease, box-shadow .15s ease;
  }
  .zdd__btn:hover{border-color:var(--midnight);}
  .zdd__btn:focus-visible{outline:none;border-color:var(--sand);box-shadow:0 0 0 3px rgba(170,150,100,0.2);}
  .zdd.is-set .zdd__btn,.zdd.is-open .zdd__btn{border-color:var(--midnight);box-shadow:inset 0 0 0 1px var(--midnight);background:rgba(7,32,49,0.04);}
  .zdd__chev{width:9px;height:9px;flex:none;border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:translateY(-2px) rotate(45deg);transition:transform .15s ease;}
  .zdd.is-open .zdd__chev{transform:translateY(1px) rotate(-135deg);}
  .zdd__menu{
    position:absolute;top:calc(100% + 8px);left:0;z-index:60;
    min-width:100%;width:max-content;max-width:min(320px,calc(100vw - 28px));
    max-height:min(58vh,380px);overflow-y:auto;
    background:#fff;border:1px solid #e3e4e7;border-radius:12px;
    box-shadow:0 16px 40px rgba(7,32,49,0.18);
    padding:6px;margin:0;list-style:none;
  }
  .zdd__menu[hidden]{display:none;}
  /* Anclado a la derecha para los controles del extremo derecho de la fila
     (unidades, moneda, orden): con left:0 se salen de la pantalla. */
  .zdd--der .zdd__menu{left:auto;right:0;}
  .zdd__opt{
    display:flex;align-items:center;gap:9px;width:100%;
    font-family:var(--font-body);font-size:.88rem;color:var(--midnight);text-align:left;
    background:none;border:none;border-radius:8px;padding:10px 12px;cursor:pointer;line-height:1.3;
  }
  .zdd__opt:hover{background:rgba(7,32,49,0.06);}
  .zdd__opt.is-on{font-weight:700;background:rgba(7,32,49,0.04);}
  /* Hueco de la palomita reservado SIEMPRE, marcado o no: si solo existiera en
     la opción elegida, todas las demás se correrían al abrir el menú. */
  .zdd__tick{width:14px;flex:none;color:var(--sand);font-weight:700;}
  /* El texto empuja: así la bandera queda pegada al borde derecho de la opción
     y todas quedan alineadas, en vez de flotar detrás de un texto que cambia
     de ancho. */
  .zdd__txt{flex:1 1 auto;}
  .zdd__flag{width:18px;height:13.5px;flex:none;border-radius:2px;box-shadow:0 0 0 1px rgba(7,32,49,0.12);}
  /* En el botón la bandera va detrás del código, con un poco de aire. */
  .zdd__val{display:inline-flex;align-items:center;gap:7px;}
  .zdd__sep{height:1px;background:#eceef0;margin:5px 8px;}
  .zdd__nota{padding:8px 12px 6px;font-size:.74rem;line-height:1.35;color:#6b7280;}
  /* Atribución del proveedor de tasas. Discreta —el proveedor lo permite
     expresamente— pero visible y con contraste suficiente para leerse. */
  .zdd__cred{color:#6b7280;text-decoration:underline;white-space:nowrap;}
  .zdd__cred:hover{color:var(--midnight);}

  /* ---- Botón y panel de filtros ----
     El botón imita la píldora de al lado (mismo alto, mismo radio, mismo borde)
     para que la barra se lea como una sola fila de controles y no como "los
     selects, y aparte un botón".
     El panel es un popover anclado al botón, no una barra lateral como en
     /propiedades.html: aquí abajo hay un split mapa+grilla y una columna fija
     le robaría el ancho al mapa, que es la mitad del valor de esta página. */
  .zfil{position:relative;display:inline-flex;}
  .zfilbtn{
    display:inline-flex;align-items:center;gap:7px;
    font-family:var(--font-body);font-size:.95rem;font-weight:500;color:var(--midnight);
    background:#fff;border:1px solid #d4d6da;border-radius:8px;white-space:nowrap;
    padding:10px 16px;cursor:pointer;line-height:1.2;
    transition:border-color .15s ease, box-shadow .15s ease;
  }
  .zfilbtn:hover{border-color:var(--midnight);}
  .zfilbtn:focus-visible{outline:none;border-color:var(--sand);box-shadow:0 0 0 3px rgba(170,150,100,0.2);}
  .zfilbtn__ico{width:17px;height:17px;flex:none;}
  /* Mismo tratamiento que .zpill.is-set: filtros puestos = borde marcado. */
  .zfil.is-set .zfilbtn,.zfil.is-open .zfilbtn{border-color:var(--midnight);box-shadow:inset 0 0 0 1px var(--midnight);background:rgba(7,32,49,0.04);}
  .zfilbtn__n{
    display:inline-flex;align-items:center;justify-content:center;
    min-width:19px;height:19px;padding:0 5px;border-radius:100px;
    background:var(--midnight);color:#fff;font-size:.72rem;font-weight:700;line-height:1;
  }
  /* Sin esto el contador se ve como un "0" permanente: el display:inline-flex de
     la regla de arriba es una clase y gana al [hidden] de la hoja del navegador,
     que es lo que apaga el elemento cuando no hay filtros puestos. */
  .zfilbtn__n[hidden]{display:none;}

  /* ---- Control con panel propio (.zpop): hoy solo el precio ----
     El tercer tipo de control de la barra, y hacía falta uno: el zdd es una
     LISTA de opciones excluyentes y aquí hay dos valores a la vez (el mínimo y
     el máximo). Meterlos como dos zdd era lo que había antes con el precio y
     por eso la barra iba llena.
     Lo usaba también "Hab. y baños", que volvió al panel de filtros en
     ago-2026; el mecanismo se queda porque el precio lo sigue necesitando y
     porque es genérico (montarPop en assets/buscador.js).
     Comparte caja con .zdd__btn y .zfilbtn —mismo alto, mismo radio, mismo
     borde— para que la fila se lea como un solo juego de controles. */
  .zpop{position:relative;display:inline-flex;}
  .zpopbtn{
    display:inline-flex;align-items:center;gap:8px;
    font-family:var(--font-body);font-size:.95rem;font-weight:500;color:var(--midnight);
    background:#fff;border:1px solid #d4d6da;border-radius:8px;white-space:nowrap;
    padding:10px 16px;cursor:pointer;line-height:1.2;
    transition:border-color .15s ease, box-shadow .15s ease;
  }
  .zpopbtn:hover{border-color:var(--midnight);}
  .zpopbtn:focus-visible{outline:none;border-color:var(--sand);box-shadow:0 0 0 3px rgba(170,150,100,0.2);}
  .zpop.is-set .zpopbtn,.zpop.is-open .zpopbtn{border-color:var(--midnight);box-shadow:inset 0 0 0 1px var(--midnight);background:rgba(7,32,49,0.04);}
  .zpop__panel{
    position:absolute;top:calc(100% + 8px);left:0;z-index:60;
    width:320px;max-width:calc(100vw - 28px);
    background:#fff;border:1px solid #e3e4e7;border-radius:12px;
    box-shadow:0 16px 40px rgba(7,32,49,0.18);
  }
  .zpop__panel[hidden]{display:none;}
  .zpop__body{padding:16px;}
  /* Los dos grupos de chips (habitaciones y baños) dentro del panel del pop:
     el último no lleva el margen inferior del .zfil__g o el panel queda
     descuadrado por abajo. */
  .zpop__body .zfil__g:last-child{margin-bottom:0;}
  /* El panel del precio se sale por la derecha cuando la ventana es justa;
     anclado a la derecha del botón se queda dentro. Lo pone el JS. */
  .zpop--der .zpop__panel{left:auto;right:0;}

  .zfil__panel{
    position:absolute;top:calc(100% + 10px);left:0;z-index:60;
    width:380px;max-width:calc(100vw - 28px);
    background:#fff;border:1px solid #e3e4e7;border-radius:14px;
    box-shadow:0 18px 44px rgba(7,32,49,0.18);
    display:flex;flex-direction:column;overflow:hidden;
  }
  .zfil__panel[hidden]{display:none;}
  /* La pone filAbrir() cuando el panel se saldría por la derecha, igual que
     .zpop--der en los controles con panel propio. `left:auto` es obligatorio: sin
     él ganan las dos anclas a la vez y el panel se estira de borde a borde.

     DENTRO de una media query de escritorio, y no suelta: por debajo de 720px el
     panel es una hoja a pantalla completa anclada con `inset:auto 0 0 0`, y este
     selector (0,2,0) le gana al de allí (0,1,0) por especificidad —la media query
     no puntúa—, así que suelto le metía `left:auto` a la hoja y la encogía a su
     ancho de contenido pegada a la derecha. El `matchMedia` de filAbrir() ya evita
     poner la clase ahí; esto es el cinturón, para que un cambio en el JS no pueda
     volver a romper el móvil. */
  @media (min-width:721px){
    .zfil--der .zfil__panel{left:auto;right:0;}
  }
  .zfil__head{
    display:none;align-items:center;justify-content:space-between;
    padding:14px 16px;border-bottom:1px solid #eceef0;
    font-family:var(--font-head,var(--font-body));font-size:1.05rem;color:var(--midnight);
  }
  .zfil__x{background:none;border:none;font-size:1.6rem;line-height:1;color:var(--midnight);cursor:pointer;padding:0 4px;}
  /* El cuerpo scrollea, no el panel entero: así el pie con "Ver propiedades"
     queda siempre a la vista y el visitante nunca pierde la salida.
     El tope de 420px no es estético: el widget de chat de GTM se ancla abajo a
     la derecha y su burbuja de saludo ocupa los ~160px inferiores de la ventana.
     Con el panel más alto, el pie caía justo debajo y el botón de "Ver
     propiedades" quedaba tapado — el mismo choque que ya obligó a mover el CTA
     flotante a la izquierda (ver memory.md). Medido a 900px de alto: con 420 el
     panel termina en y=620 y la burbuja empieza en 630. */
  .zfil__body{padding:16px;overflow-y:auto;max-height:min(48vh,420px);}
  .zfil__g{margin-bottom:18px;}
  .zfil__g:last-child{margin-bottom:0;}
  .zfil__lab{display:block;font-size:.82rem;font-weight:700;color:var(--midnight);margin-bottom:8px;letter-spacing:.01em;}
  .zfil__chips{display:flex;gap:6px;flex-wrap:wrap;}
  .zfil__chip{
    flex:1 1 0;min-width:52px;
    font-family:var(--font-body);font-size:.85rem;font-weight:500;color:var(--midnight);
    background:#fff;border:1px solid #d4d6da;border-radius:8px;
    padding:9px 6px;cursor:pointer;line-height:1.2;
    transition:border-color .15s ease, background .15s ease;
  }
  .zfil__chip:hover{border-color:var(--midnight);}
  .zfil__chip.is-on{background:var(--midnight);border-color:var(--midnight);color:#fff;font-weight:600;}
  .zfil__sel{
    appearance:none;-webkit-appearance:none;width:100%;
    font-family:var(--font-body);font-size:.88rem;color:var(--midnight);
    background:#fff;border:1px solid #d4d6da;border-radius:8px;
    padding:10px 30px 10px 12px;cursor:pointer;line-height:1.2;
    background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 4l4 4 4-4' fill='none' stroke='%23072031' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
    background-repeat:no-repeat;background-position:right 11px center;background-size:11px;
  }
  .zfil__sel:focus{outline:none;border-color:var(--sand);box-shadow:0 0 0 3px rgba(170,150,100,0.2);}
  .zfil__par{display:flex;align-items:center;gap:8px;}
  .zfil__sep{color:#9aa0a6;flex:none;}
  .zfil__g--chk{display:flex;flex-direction:column;gap:10px;}
  .zfil__chk{display:flex;align-items:center;gap:9px;font-size:.88rem;color:var(--midnight);cursor:pointer;}
  .zfil__chk input{width:17px;height:17px;accent-color:var(--midnight);cursor:pointer;flex:none;}
  .zfil__pie{
    display:flex;align-items:center;gap:10px;
    padding:12px 16px;border-top:1px solid #eceef0;background:#fafafa;
  }
  .zfil__reset{background:none;border:none;color:var(--midnight);font-family:var(--font-body);font-weight:600;font-size:.85rem;cursor:pointer;text-decoration:underline;padding:8px 2px;}
  .zfil__ver{
    margin-left:auto;font-family:var(--font-body);font-size:.88rem;font-weight:600;
    background:var(--midnight);color:#fff;border:none;border-radius:8px;
    padding:11px 18px;cursor:pointer;white-space:nowrap;
  }
  .zfil__ver:hover{background:#0d2f47;}
  /* El velo solo existe en móvil, donde el panel es una hoja a pantalla
     completa. En escritorio el panel se cierra al hacer clic fuera. */
  .zfil__fondo{display:none;}

  /* ---- Cabecera del listado ---- */
  /* scroll-margin-top: al cambiar de página se hace scrollIntoView aquí, y la
     barra de búsqueda es sticky. Sin este margen la cabecera queda debajo. */
  .zhead{padding:2px 2px 14px;scroll-margin-top:78px;}
  /* 1.35rem y no 1.6: la cabecera vive dentro de la columna del listado, que a
     1440 mide ~570 px de contenido. A 1.6rem el título ocupaba dos líneas en
     cuanto el nombre de la zona era largo (Sunny Isles Beach, Key Biscayne). */
  /* Es el H1 de la pagina, no un contador: dice "Buscar Propiedades" en
     propiedades.html y "Condominios en Brickell" en la landing. O sea es un
     titulo y va en la titular de marca. Estuvo excluido por error, creyendo
     que era la linea de "N propiedades en venta" — esa es .zhead__n. */
  .zhead__t{margin:0;font-family:var(--font-head,var(--font-body));font-size:1.35rem;font-weight:600;color:var(--midnight);line-height:1.25;letter-spacing:.01em;text-transform:uppercase;}
  .zhead__fila{display:flex;align-items:flex-end;justify-content:space-between;gap:10px;flex-wrap:wrap;margin-top:4px;}
  .zhead__n{margin:0;font-family:var(--font-body);font-size:.8rem;font-weight:500;color:#6b7c8c;}
  .zhead__n b{color:var(--midnight);font-weight:600;}
  /* Fila de utilidades de la cabecera del listado (unidades · moneda · orden).
     Van más discretas que las píldoras de la barra —son ajustes de lectura, no
     de búsqueda— así que el botón es plano, sin borde ni fondo. */
  .zutil{display:flex;align-items:center;gap:2px;flex-wrap:wrap;justify-content:flex-end;}
  /* El valor va en --midnight, no en arena (decisión de Mateo, ago-2026): azul de
     PFS es --midnight y punto. El realce sobre la etiqueta lo hace la OPACIDAD,
     no el tono — .zdd__lab es el mismo navy al 55% —, así que "Pies²", "USD" y
     "Más recientes" siguen leyéndose como el dato y "Unidades:", "Moneda:" y
     "Ordenar por:" como su rótulo. */
  .zutil .zdd__btn{
    border:none;background:none;padding:8px 10px;border-radius:8px;
    font-size:.82rem;font-weight:600;color:var(--midnight);
  }
  /* Los fondos bajan de 0.10/0.14 a 0.06/0.08: el navy es MUCHO más oscuro que
     el arena, así que a la misma alfa la pastilla pesaba más que el propio texto
     y el control parecía seleccionado sin estarlo. */
  .zutil .zdd__btn:hover{background:rgba(7,32,49,0.06);}
  .zutil .zdd.is-open .zdd__btn,.zutil .zdd.is-set .zdd__btn{box-shadow:none;background:rgba(7,32,49,0.08);}
  .zutil .zdd__lab{color:var(--midnight);opacity:.55;font-weight:600;}
  @media (max-width:720px){
    .zutil{gap:0;}
    .zutil .zdd__btn{padding:8px 7px;font-size:.78rem;}
  }

  /* ---- Split mapa / listado ----
     Ocupa el hueco EXACTO que dejan las dos barras pegajosas, de borde a borde
     y sin esquinas redondeadas: en escritorio la página no scrollea, scrollea
     la columna de la derecha. Es el reparto de Zillow.

     El alto era min(80vh,820px) dentro de un contenedor centrado con márgenes,
     y encima llevaba la cabecera del listado, así que a 900 px de ventana el
     mapa se veía en ~650. Ahora se ve entero.

     El alto se reparte con flex en la media query de escritorio de más abajo,
     no aquí: hace falta que el reparto NO exista en móvil, donde el split se
     deshace y la página vuelve a scrollear con normalidad.

     56/44 y no 58/42: la columna del listado tiene barra de desplazamiento
     propia y esos ~15 px salen del ancho útil. Con 42% la rejilla caía a UNA
     tarjeta por fila incluso a 1440 —medido—, que es justo lo que el minmax de
     272 px estaba puesto para evitar. Con 44% entran dos desde ~1360 px de
     ventana, igual que antes de tocar nada. */
  .zsplit{
    display:grid;grid-template-columns:56% 44%;
    overflow:hidden;background:#fff;
  }
  /* ESCRITORIO: nav + barra + split reparten el alto de la ventana con flex, y
     el split es el único que crece. Se probó antes con
     `height:calc(100dvh - var(--alto-barras))` midiendo las barras en JS y
     sobraba 1 px —offsetHeight devuelve enteros y el alto real es
     fraccionario—: la página se quedaba con 1 px de scroll, que basta para que
     el navegador pinte su barra de desplazamiento, se coma 15 px de ancho y
     tire la rejilla de dos tarjetas a una. Con flex no hay nada que redondear.

     `flex:1 1 0` y no `1 1 auto`: con base `auto` el hijo parte de su alto de
     CONTENIDO —la columna sin recortar medía 6.811 px— y estira el body en vez
     de recortarse. Medido también. */
  @media (min-width:1025px){
    body{display:flex;flex-direction:column;min-height:100dvh;}
    .zmain{flex:1 1 0;min-height:0;display:flex;flex-direction:column;}
    .zsplit{flex:1 1 0;min-height:560px;}
    /* Sangría izquierda de la página, la misma para la barra y para el mapa
       (ver .zmap más abajo) para que los dos bordes caigan en la misma
       vertical. */
    .searchbar__in{padding-left:40px;}

    /* Controles un punto más grandes, solo en escritorio (decisión de Mateo,
       ago-2026). Medido contra la captura de Zillow a 1440: sus píldoras miden
       40 px de alto con texto de ~15 px (12 px de altura de mayúscula); las
       nuestras iban a 39 px con 14,4 px (11 px de mayúscula). O sea el alto ya
       estaba, lo que faltaba era el TEXTO — de ahí el .95rem de arriba, y estos
       2 px de padding para que la caja acompañe a la letra.

       Va en la media query y NO suelto: en móvil el alto de esta barra es
       presupuesto de pantalla (--alto-barras ancla el mapa a pantalla completa),
       y allí las píldoras ya tienen su propio padding más apretado.

       El padding de la BANDA se deja en los 10px de base: con controles de 42px
       la barra sale de 63px, que es 2px más que antes. Subirlo a 12px la llevaba
       a 68px —doce más que los 56px de Zillow— y eso ya no es "un poco más
       grande", es otra barra. Lo que crece es el control, no el hueco. */
    .zsearch input{padding-top:11px;padding-bottom:11px;}
    .searchbar__in > .zdd .zdd__btn,
    .searchbar__in > .zpop .zpopbtn,
    .searchbar__in > .zfil .zfilbtn{padding-top:11px;padding-bottom:11px;}
  }

  /* --------------------------------------------------------------------------
     VARIANTE DEL BUSCADOR DEL SITIO (propiedades.html + en/pt).

     La landing ES la aplicación entera: ocupa la ventana y no hay nada debajo.
     El buscador del sitio no puede ser eso —se indexa, y debajo van las
     migas, el bloque de contacto y el pie con los enlaces internos que el
     resto del sitio necesita— pero tampoco puede repartir el alto de la
     ventana con ellos: el split se quedaría con lo que sobre después del pie.

     Solución: el reparto flex se muda de <body> a un envoltorio .zapp que
     contiene nav + barra + split y mide UNA ventana exacta. Lo de después
     queda fuera y se alcanza scrolleando la página. La columna interior lleva
     overscroll-behavior:contain, así que llegar a su final no arrastra la
     página de detrás sin querer.

     Va bajo body.zbuscador-seo para que la landing no se entere de nada: sin
     esa clase estas reglas no existen y el reparto sigue siendo el de arriba.
     -------------------------------------------------------------------------- */
  @media (min-width:1025px){
    body.zbuscador-seo{display:block;min-height:0;}
    body.zbuscador-seo .zapp{display:flex;flex-direction:column;height:100dvh;}
    body.zbuscador-seo .zmain{flex:1 1 0;min-height:0;}
    /* El pie vive dentro de la columna, que mide ~44% de la ventana, y
       .site-footer__grid es `1.4fr 1fr 1fr 1fr` que solo cae a dos columnas en
       un @media de 980px de VENTANA. Aquí la ventana sigue siendo ancha, así
       que ese @media no dispara nunca y el grid se quedaría en cuatro columnas
       de ~130px: los <h4> en versalita con letter-spacing se parten y "Miami ·
       Fort Lauderdale" sale en tres líneas. Se fuerzan dos, que es lo que ese
       mismo @media hace cuando el ancho disponible es este.
       Va en la media query de escritorio y no fuera: por debajo de 1025px la
       columna ocupa la ventana entera y manda la regla responsive del sitio. */
    body.zbuscador-seo .zcol > .site-footer .site-footer__grid{
      grid-template-columns:1fr 1fr;gap:30px;
    }
  }
  /* La columna que scrollea: cabecera del listado + rejilla + paginación +
     atribución IDX. overscroll-behavior:contain evita que al llegar al final
     el gesto siga arrastrando la página de detrás.
     12 px de lado y no 18: ver el reparto de arriba, cada píxel de padding sale
     del ancho de las tarjetas. */
  /* El padding va por variable porque los dos hijos de abajo (migas y pie)
     tienen que CANCELARLO para llegar a los bordes de la columna, y la columna
     lo cambia en tres sitios: aquí, en móvil y en la vía sin mapa. Con el valor
     escrito a mano en cada negativo, cambiar uno dejaría una franja blanca
     asimétrica en los otros dos. */
  .zcol{--zcol-pad:12px;--zcol-pad-b:30px;overflow-y:auto;overscroll-behavior:contain;padding:16px var(--zcol-pad) var(--zcol-pad-b);background:#fff;}

  /* ---- Migas y pie DENTRO de la columna que scrollea ----
     Solo el buscador del sitio los tiene: la landing deja la ficha PIE_COLUMNA
     vacía. (Sin llaves a propósito: esta hoja se INCRUSTA en la plantilla de la
     landing y pasa por el sustituidor de fichas, así que escrita entera se
     borraría sola y la frase quedaría coja. Ya pasó.)
     Es la disposición de Zillow —su <footer> es el último hijo de
     #search-page-list-container, la caja que scrollea con las tarjetas, y el
     mapa es un hermano que no se mueve— y es lo que hace que bajando por los
     resultados se llegue al pie sin que el mapa se vaya de la pantalla. */
  .zcol > .breadcrumb,
  .zcol > .site-footer{
    margin-left:calc(-1 * var(--zcol-pad));
    margin-right:calc(-1 * var(--zcol-pad));
  }
  /* Aire entre la atribución IDX y la franja navy de las migas. */
  .zcol > .breadcrumb{margin-top:18px;}
  /* El pie es el último hijo, así que el padding inferior de la columna queda
     por DEBAJO del navy: una franja blanca al final que se lee como un fallo de
     maquetación. Se cancela con el mismo valor. */
  .zcol > .site-footer:last-child{margin-bottom:calc(-1 * var(--zcol-pad-b));}
  /* position:relative para poder colgar .zmap__nota encima del mapa */
  /* isolation:isolate encierra el apilado del mapa. Dentro hay una nota con
     z-index 500 y, sin esto, position:relative SIN z-index no crea contexto de
     apilamiento: esos 500 competirían en la raíz y la nota se dibujaría encima
     de las barras pegajosas al scrollear. Con el nav sticky se nota; antes
     también pasaba con la barra de filtros. */
  .zmap{position:relative;isolation:isolate;height:100%;width:100%;background:#dfe3e6;}
  /* Un respiro a la izquierda del mapa: a sangre contra el borde de la ventana
     pesaba demasiado. Son 40 px, EL MISMO valor que el padding-left que se le
     da a .searchbar__in en la media query de escritorio, así que el borde
     izquierdo del mapa cae en la misma vertical que la caja de "Buscar zona o
     dirección" que tiene justo encima. Si se cambia uno, cambiar el otro.

     Va como margen del MAPA y no como padding del split a propósito: el padding
     se lo restaría también a la columna de la derecha, y ahí cada píxel decide
     si caben dos tarjetas o una — sacando el hueco del grid, a 1360 px la
     rejilla se caía a una sola columna. Así el reparto de la columna ni se
     entera.

     `width:auto` no es decorativo y esta regla TIENE que ir después de la de
     arriba: con el `width:100%` de .zmap ganando, el margen no encoge el mapa,
     lo DESPLAZA — se metía 24 px por debajo de la columna del listado y el
     `overflow:hidden` del split se comía la franja sin que se notara nada. */
  @media (min-width:1025px){
    .zmap{margin-left:40px;width:auto;}
  }
  /* Aviso sobre el mapa: "Ubicando N propiedades…" mientras se geocodifica y,
     al terminar, cuántas quedaron ubicadas si no fueron todas. z-index 500 lo
     pone por encima del lienzo del mapa.
     Va a la DERECHA porque a la izquierda queda el logo de Google, que es
     obligatorio y no se puede tapar; abajo a la derecha van los enlaces de
     términos de Google, que tampoco. */
  .zmap__nota{
    position:absolute;right:12px;top:12px;z-index:500;pointer-events:none;max-width:calc(100% - 76px);
    background:rgba(255,255,255,0.94);border:1px solid #e3e4e7;border-radius:6px;
    padding:7px 11px;font-family:var(--font-body);font-size:.72rem;font-weight:600;
    color:#5a6b7a;box-shadow:0 2px 8px rgba(7,32,49,0.10);
  }
  .zmap__fallback{display:flex;align-items:center;justify-content:center;height:100%;padding:22px;text-align:center;font-size:.86rem;color:#5a6b7a;font-weight:600;line-height:1.5;}
  /* Sin coordenadas en el feed el mapa no se dibuja: se colapsa a una franja de
     aviso y la grilla toma el ancho completo. Ver renderMap(). */
  .zsplit--nomap{grid-template-columns:1fr;height:auto;min-height:0;border:none;border-radius:0;background:transparent;overflow:visible;}
  .zsplit--nomap .zmap{height:auto;background:none;border:none;border-radius:0;margin:0 0 10px;}
  .zsplit--nomap .zmap__fallback{padding:0 2px 2px;font-size:.75rem;color:#9aa0a6;font-weight:400;justify-content:flex-start;text-align:left;}
  /* Sin mapa no hay split que llenar: la columna deja de scrollear por su
     cuenta y vuelve a ser una página normal, centrada y con márgenes — que es
     lo que hacía el viejo .wrap. */
  /* `width:100%` NO sobra junto al max-width: sin él el margen automático deja
     de centrar y pasa a ENCOGER. Un margen `auto` en el eje en línea anula el
     `justify-self:stretch` que traen los hijos de un grid, así que la columna
     se quedaba en su ancho de contenido —medido: 901 px de los 1.425
     disponibles, dos tarjetas por fila donde antes entraban cuatro— y encima
     parecía correcto, porque salía centrada. Con un ancho definido el margen
     vuelve a repartir el sobrante, que es lo que se le pedía. */
  .zsplit--nomap .zcol{--zcol-pad:24px;--zcol-pad-b:118px;max-height:none;overflow:visible;background:transparent;width:100%;max-width:1560px;margin:0 auto;padding:22px var(--zcol-pad) var(--zcol-pad-b);}
  /* grid-auto-rows:max-content es OBLIGATORIO, no cosmético: la columna tiene
     altura definida, y sin esto las filas automáticas se reparten esa altura
     entre las 30 tarjetas (~8,6px cada una), la tarjeta se estira a su fila y
     sus hijos flex se aplastan — la foto queda en 0px.
     El minmax de 340px da 4 columnas de ~370px a ancho completo, casi el ancho
     de tarjeta de Zillow (~355px); con menos, salen 5 y la línea de specs se
     parte en dos. Dentro del split caen solas a 2, como Zillow con el mapa. */
  /* Solo la rejilla: el scroll y el padding son de .zcol, que es quien
     envuelve además la cabecera, la paginación y la atribución. */
  .zlist{display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));grid-auto-rows:max-content;gap:26px 16px;align-content:start;background:#fff;}
  /* Con el mapa al lado la columna mide ~660px y con el minmax de 340 solo cabe
     UNA tarjeta por fila: el visitante ve una propiedad a la vez y tiene que
     scrollear 30 veces. Dentro del split se baja el mínimo para que entren dos,
     como en el panel de Zillow. Fuera del split manda el valor de arriba. */
  /* 272 y no 296. Medido a 1440: con el mapa al lado la columna mide 612 px,
     que descontando padding deja 592 de contenido; dos tarjetas de 296 más el
     hueco de 14 piden 606 y se quedaban a 14 px de entrar, así que caía a UNA
     columna de 592 px de ancho — con foto 4:3 son 444 px de alto y cabe tarjeta
     y media por pantalla. Con 272 entran dos (≈289 px cada una, como el panel
     de Zillow) desde ~1360 px de ventana, y por debajo sigue cayendo a una
     sola, que a esos anchos sí es lo correcto. */
  .zsplit:not(.zsplit--nomap) .zlist{grid-template-columns:repeat(auto-fill,minmax(272px,1fr));gap:22px 14px;}
  /* Esqueleto de carga: misma caja que la tarjeta final para que no haya salto
     de layout cuando entran los datos. */
  .zlist--skeleton .proj-card,.zlist--skeleton .proj-card__link{cursor:default;pointer-events:none;}
  .zlist--skeleton .proj-card__media{animation:pulse 1.4s ease-in-out infinite;}
  .zlist--skeleton .proj-card__price{color:transparent;}
  @keyframes pulse{0%,100%{opacity:1;}50%{opacity:.55;}}
  .zlist__empty{grid-column:1/-1;padding:40px 20px;text-align:center;color:#3d5064;font-weight:600;font-size:.95rem;line-height:1.6;}

  /* Pin de precio (contenido HTML de un AdvancedMarkerElement de Google).
     Google ancla el contenido por su borde INFERIOR centrado, mientras que el
     divIcon de Leaflet lo anclaba por la esquina superior izquierda: por eso
     lleva translate, para que el punto exacto quede en el centro del pin y no
     debajo de él. */
  /* Pin de precio. Antes era una píldora centrada sobre la coordenada: se veía
     el precio pero no QUÉ punto exacto estaba marcando, que en una calle de
     torres pegadas es justo lo que hace falta. Ahora es un marcador de verdad
     —globo arriba, pico y punto sobre la coordenada— igual que el de la ficha.

     El pico y el punto van como ::after y ::before, NO como hijos: el pintado
     recicla los nodos y les reescribe el textContent, que borraría cualquier
     hijo. Los pseudoelementos sobreviven a eso, y además no cuentan para el
     layout, así que el reciclado del pool sigue siendo un cambio de texto.

     `background-color:inherit` hace que el pico siga solo al estado activo sin
     duplicar el color en otra regla.

     AQUÍ EL PICO VA PEGADO AL GLOBO, sin el punto suelto que sí lleva el pin de
     la ficha. El motivo es la densidad: con el punto separado el marcador medía
     26px más de alto, y como esa altura entra en la agrupación (ver medirPin),
     al zoom de entrada se perdían pines de precio que pasaban a engordar los
     discos — de 5 sueltos a 2. Medido. Con el pico pegado la altura extra son
     8px y la cuenta vuelve a lo de antes, sin renunciar a que el marcador
     SEÑALE un punto en vez de flotar.
     En la ficha no hay ese problema —hay un solo pin— así que allí el punto se
     queda, que es lo que da la precisión fina. Ver .zpinx.

     Geometría: Google ancla el contenido por su borde inferior centrado. El
     cuadrado girado 45° sobresale ~8px bajo el globo, así que translateY(-8px)
     deja la PUNTA sobre la coordenada. */
  .zpin{
    position:relative;
    background:var(--midnight);color:#fff;font-family:var(--font-body);font-weight:600;
    font-size:.78rem;padding:5px 10px;border-radius:9px;white-space:nowrap;
    border:2px solid #fff;box-shadow:0 3px 10px rgba(7,32,49,0.35);text-align:center;
    cursor:pointer;transform:translateY(-8px);
    transition:background .15s ease, transform .15s ease;
  }
  /* Pico: cuadrado girado 45° que hereda dos bordes blancos, así el contorno
     del globo continúa sin costura por la punta. */
  .zpin::after{
    content:"";position:absolute;left:50%;bottom:-6px;width:9px;height:9px;
    background-color:inherit;border-right:2px solid #fff;border-bottom:2px solid #fff;
    transform:translateX(-50%) rotate(45deg);
  }
  .zpin.is-active{background:var(--azul-sel);color:#fff;transform:translateY(-8px) scale(1.12);}

  /* ---- Pin de la propiedad en la ficha (mapa de "Ubicación") ----
     No es la píldora de los resultados. Aquí hay UNA propiedad y el trabajo del
     pin es señalar el punto, así que tiene forma de marcador: globo con el
     precio, pico hacia abajo y un punto en la coordenada exacta. Una píldora
     ovalada flotando no dice dónde cae; este sí.
     El punto se monta con margin-bottom negativo de media altura para que su
     CENTRO quede sobre la coordenada: Google ancla el contenido por el borde
     inferior centrado, así que sin eso el punto colgaría por debajo del sitio. */
  .zpinx{display:flex;flex-direction:column;align-items:center;pointer-events:none;}
  .zpinx__b{
    position:relative;background:var(--midnight);color:#fff;
    font-family:var(--font-body);font-weight:700;font-size:.82rem;line-height:1;
    padding:8px 13px;border-radius:9px;border:2px solid #fff;white-space:nowrap;
    box-shadow:0 4px 12px rgba(7,32,49,.4);
  }
  /* Pico: un cuadrado girado 45° que hereda dos bordes blancos, así el contorno
     del globo continúa sin costura por la punta. */
  .zpinx__b::after{
    content:"";position:absolute;left:50%;bottom:-6px;width:10px;height:10px;
    background:var(--midnight);border-right:2px solid #fff;border-bottom:2px solid #fff;
    transform:translateX(-50%) rotate(45deg);
  }
  .zpinx__p{
    width:8px;height:8px;margin-top:7px;margin-bottom:-6px;
    border-radius:50%;background:var(--midnight);border:2px solid #fff;
    box-shadow:0 1px 4px rgba(7,32,49,.45);
  }

  /* Grupo de propiedades. Mismo anclaje que el pin: Google coloca el contenido
     por su borde inferior centrado, así que el translateY(50%) baja el círculo
     media altura para que su CENTRO caiga sobre la coordenada.
     El halo es lo que lo separa a simple vista del pin de precio: uno es una
     píldora oscura y alargada con un número de dólares, el otro un disco con
     anillo y un número a secas. Nadie tiene que aprender la diferencia.
     El halo era arena y pasó a azul con el resto de los pines: sobre el mapa el
     dorado leía como un marcador ajeno, no como parte de esta búsqueda. */
  .zclus{
    display:flex;align-items:center;justify-content:center;
    background:var(--midnight);color:var(--ivory);
    font-family:var(--font-body);font-weight:700;font-size:.86rem;line-height:1;
    border-radius:50%;border:2px solid var(--ivory);
    box-shadow:0 0 0 4px rgba(22,104,165,.45), 0 4px 12px rgba(7,32,49,.38);
    cursor:pointer;transform:translateY(50%);
    transition:transform .15s ease, background .15s ease;
  }
  .zclus:hover{transform:translateY(50%) scale(1.08);}
  /* El grupo contiene la tarjeta seleccionada. Sin esto, alejar el zoom hasta
     que la seleccionada cae dentro de un grupo borra la selección del mapa y
     parece que se perdió. */
  .zclus.is-active{background:var(--azul-sel);color:#fff;}

  /* ============================================================
     FICHA EN CAPA — la propiedad se abre ENCIMA de los resultados.

     Igual que Zillow: la lista no se descarga ni se pierde el scroll, la URL sí
     cambia a la de la propiedad (history.pushState) para que se pueda compartir
     y para que «atrás» cierre la capa. Si esa URL se abre en frío, Netlify la
     reescribe a propiedad.html y sale la ficha completa de siempre — la capa es
     un atajo desde los resultados, no un sustituto de la página.
     ============================================================ */
  .zficha[hidden]{display:none;}
  .zficha{position:fixed;inset:0;z-index:90;display:flex;align-items:center;justify-content:center;padding:24px;}
  .zficha__fondo{position:absolute;inset:0;background:rgba(5,24,38,0.62);animation:zfIn .18s ease;}
  @keyframes zfIn{from{opacity:0;}to{opacity:1;}}
  .zficha__panel{
    position:relative;background:#fff;border-radius:10px;overflow:hidden;
    width:min(1040px,100%);max-height:calc(100vh - 48px);
    display:flex;flex-direction:column;
    box-shadow:0 30px 80px rgba(0,0,0,0.42);
    animation:zfUp .22s cubic-bezier(0.22,1,0.36,1);
  }
  @keyframes zfUp{from{opacity:0;transform:translateY(14px);}to{opacity:1;transform:none;}}
  .zficha__x{
    position:absolute;top:14px;right:14px;z-index:4;
    width:38px;height:38px;border-radius:50%;border:none;cursor:pointer;
    background:rgba(255,255,255,0.94);color:var(--midnight);
    font-size:1.4rem;line-height:1;display:flex;align-items:center;justify-content:center;
    box-shadow:0 2px 10px rgba(7,32,49,0.3);
  }
  .zficha__x:hover{background:#fff;}
  .zficha__cuerpo{overflow-y:auto;overscroll-behavior:contain;}

  /* --- galería --- */
  /* max-height además del aspect-ratio: en un panel de 1040 px, 16/10 son 650 px
     de foto, y en una pantalla de 900 px no queda sitio para el precio ni las
     specs sin scrollear. La capa tiene que enseñar de un vistazo foto Y datos;
     si obliga a scrollear para ver el precio, no mejora en nada a la página. */
  /* width:100% explícito. Con aspect-ratio y el alto tope, si el ancho queda en
     auto el navegador ENCOGE EL ANCHO para respetar la proporción: la foto
     salía a 691 px en un panel de 1040 y dejaba una banda blanca a la derecha.
     Con el ancho fijo, el tope solo recorta el alto y la foto ocupa el panel
     entero (la <img> va con object-fit:cover, así que no se deforma). */
  .zfg{position:relative;width:100%;background:#0B2C42;aspect-ratio:16/10;max-height:48vh;}
  .zfg img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;}
  .zfg__nav{
    position:absolute;top:50%;transform:translateY(-50%);
    width:42px;height:42px;border-radius:50%;border:none;cursor:pointer;
    background:rgba(255,255,255,0.92);color:var(--midnight);
    font-size:1.5rem;line-height:1;display:flex;align-items:center;justify-content:center;
    box-shadow:0 2px 10px rgba(7,32,49,0.3);
  }
  .zfg__nav--prev{left:14px;} .zfg__nav--next{right:14px;}
  .zfg__nav:hover{background:#fff;}
  .zfg__cuenta{
    position:absolute;left:14px;bottom:14px;
    background:rgba(7,32,49,0.78);color:#fff;border-radius:100px;
    padding:5px 12px;font-size:.76rem;font-weight:600;
  }

  /* --- contenido --- */
  .zfc{padding:22px 26px 26px;}
  /* El precio va en sans, no en serif: en propiedades.html .proj-card__price es
     Montserrat 700. */
  /* Mapa dentro de la ficha, al final y con el pin de la propiedad — el bloque
     de ubicación de Zillow. Alto fijo: el contenedor de un mapa de Google tiene
     que tener altura propia, con `auto` se queda en 0 y no se dibuja nada. */
  .zfc__mapa{height:260px;border-radius:12px;overflow:hidden;background:#eceef0;margin-top:4px;}
  .zfc__mapaint{width:100%;height:100%;}
  .zfc__mapanota{margin:8px 0 0;font-size:.76rem;line-height:1.4;color:#6b7280;}
  @media (max-width:720px){ .zfc__mapa{height:210px;} }

  .zfc__precio{font-family:var(--font-body);font-size:1.9rem;font-weight:700;line-height:1.1;letter-spacing:.01em;}
  .zfc__dir{font-size:1rem;font-weight:600;margin-top:4px;}
  .zfc__loc{font-size:.84rem;color:#5a6b7a;margin-top:2px;}
  .zfc__specs{
    display:flex;flex-wrap:wrap;gap:0;margin:18px 0 0;
    border:1px solid #e3e4e7;border-radius:8px;overflow:hidden;
  }
  .zfc__spec{flex:1 1 25%;min-width:88px;padding:12px 8px;text-align:center;border-right:1px solid #e3e4e7;}
  .zfc__spec:last-child{border-right:none;}
  .zfc__spec strong{display:block;font-size:1rem;font-weight:600;}
  .zfc__spec span{font-size:.7rem;color:#8a9099;text-transform:uppercase;letter-spacing:.06em;}
  /* Los títulos de sección de la ficha siguen el patrón de los h4 del sistema
     (medido en propiedades.html: Montserrat 700, versalita, .1em). */
  .zfc h3{font-family:var(--font-body);font-size:.82rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--midnight);margin:24px 0 10px;}
  .zfc__texto{font-size:.9rem;line-height:1.65;color:#3d5064;white-space:pre-line;}
  .zfc__datos{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:8px 18px;font-size:.86rem;}
  .zfc__dato{display:flex;justify-content:space-between;gap:12px;padding:7px 0;border-bottom:1px solid #eef0f2;}
  .zfc__dato span{color:#8a9099;}
  .zfc__dato strong{font-weight:600;}
  .zfc__ams{display:flex;flex-wrap:wrap;gap:6px;}
  .zfc__am{background:var(--ivory);border:1px solid #e3e4e7;border-radius:100px;padding:5px 11px;font-size:.76rem;font-weight:500;}
  /* Barra de acción pegada al pie del panel: es lo único que convierte, así que
     no puede depender de que el visitante llegue scrolleando hasta el final. */
  .zficha__pie{
    flex:none;display:flex;gap:10px;align-items:center;
    padding:12px 26px;border-top:1px solid #e3e4e7;background:#fff;
  }
  /* AZUL DE MARCA (--midnight), no el verde de WhatsApp: decisión de Mateo
     (ago-2026). El botón sigue abriendo WhatsApp y conserva su icono, que es lo
     que dice por dónde se contesta; el color pasa a ser el de la empresa.
     Es --midnight y NO --azul-sel: el azul de PFS es el navy de la marca, el
     mismo del nav y del botón "Ver N propiedades" del panel de filtros.
     --azul-sel (#1668a5) existe solo para el estado activo de los pines y los
     discos DEL MAPA, donde el navy se confundiría con el fondo; fuera del mapa
     no se usa.
     `--wa-green` se queda para el CTA del nav (.nav-wa), que ahí sí es un
     enlace de WhatsApp sin más contexto.
     Si alguien lo ve "mal" y quiere devolverlo a verde: es intencionado. */
  .zficha__wa{
    flex:1;display:inline-flex;align-items:center;justify-content:center;gap:9px;
    background:var(--midnight);color:#fff;border:none;border-radius:6px;cursor:pointer;
    font-family:var(--font-body);font-size:.92rem;font-weight:600;padding:13px 18px;
    transition:background .2s ease;
  }
  .zficha__wa svg{width:19px;height:19px;fill:#fff;}
  /* Mismo hover que .zfil__ver, que es el otro botón sólido de la página. */
  .zficha__wa:hover{background:#0d2f47;}
  .zficha__completa{
    font-size:.82rem;font-weight:600;color:#5a6b7a;text-decoration:none;
    white-space:nowrap;padding:13px 4px;
  }
  .zficha__completa:hover{color:var(--sand);text-decoration:underline;}
  body.zficha-abierta{overflow:hidden;}

  @media (max-width:720px){
    .zficha{padding:0;}
    .zficha__panel{width:100%;max-height:100vh;height:100vh;border-radius:0;}
    .zfg{aspect-ratio:4/3;}
    .zfc{padding:18px 16px 22px;}
    .zfc__precio{font-size:1.6rem;}
    .zficha__pie{padding:10px 16px;}
    .zficha__completa{display:none;}
  }

  /* ---- Tarjeta: misma anatomía que la .proj-card del sitio (la que usa
     assets/dtf-listings.js en /zonas/…). Foto con sombra y overlay al hover,
     y debajo, centrado: nombre → ubicación → fila de 4 stats → precio en
     banda gris. Valores tomados de styles.css (.proj-card + los overrides de
     .dtf-grid, que son los que realmente se ven en la página de zona). ---- */
  /* La tarjeta es el contenedor; el enlace a la ficha es lo que se maqueta en
     columna. Van separados porque el botón de WhatsApp tiene que quedar FUERA
     del <a> (ver renderList), y para eso necesita un padre posicionado. */
  .proj-card{position:relative;width:100%;font-family:var(--font-body);color:var(--midnight);}
  /* Al tocar un pin, select() hace scrollIntoView sobre su tarjeta. Ese cálculo
     NO sabe nada de las barras pegajosas: cuando la tarjeta queda por ENCIMA
     del scroll, el navegador la alinea con el borde superior del scrollport y
     los 278 px de nav + filtros la tapan entera — medido: foto y título
     invisibles. La tarjeta "resaltada" no se veía por ningún lado.
     scroll-margin-top le reserva ese alto. Solo hasta 1024 px: por encima el
     que scrollea es la columna .zcol (overflow-y:auto), no la página, y las
     barras no se le montan encima, así que ahí el margen sobraría y dejaría un
     hueco al principio del panel. El valor lo mide el JS (medirBarras): la
     fila de filtros cambia de alto según cuántas píldoras quepan. */
  @media (max-width:1024px){
    .proj-card{scroll-margin-top:var(--tope-pegajoso,286px);}
  }
  .proj-card__link{
    display:flex;flex-direction:column;gap:14px;
    text-decoration:none;cursor:pointer;color:inherit;
  }
  .proj-card__link:focus-visible{outline:2px solid var(--sand);outline-offset:4px;}
  .proj-card__media{
    position:relative;aspect-ratio:4/3;border-radius:0;overflow:hidden;
    background:#0B2C42;box-shadow:0 12px 30px rgba(0,0,0,0.28);
    transition:transform .35s ease, box-shadow .35s ease;
    flex-shrink:0;
  }
  .proj-card:hover .proj-card__media{transform:translateY(-6px);box-shadow:0 20px 44px rgba(0,0,0,0.4);}
  /* La foto va ABSOLUTA: el MLS entrega fotos verticales (960x1280) y una <img>
     en flujo con height:100% dentro de un contenedor flex cae a su altura
     natural y rompe el aspect-ratio, estirando la fila entera de la grilla. */
  .proj-card__media img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;}
  .proj-card__nophoto{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#8a9099;font-size:.85rem;font-weight:500;background:#e6e4df;}
  .proj-card__hover{
    position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
    text-align:center;padding:0 16px;background:rgba(7,32,49,0.72);color:#fff;
    font-family:var(--font-body);font-weight:600;font-size:1rem;letter-spacing:.01em;
    opacity:0;transition:opacity .3s ease;pointer-events:none;z-index:2;
  }
  .proj-card:hover .proj-card__hover{opacity:1;}
  .proj-card__foot{display:flex;flex-direction:column;align-items:center;gap:8px;text-align:center;padding:0 8px;}
  /* La dirección es el único sitio donde el sistema usa serif, y es Georgia.
     Valores medidos sobre propiedades.html servida por este repo:
     Georgia / 16.8px / 500 / .03em / uppercase / line-height 1.25.
     Antes esta regla llevaba Playfair y .08em, copiados del computado de OTRO
     sitio (pfsrealtygroupv2). Al comparar contra la página de este repo —que es
     la referencia buena— las dos cosas resultaron ser distintas, así que ahora
     manda lo medido aquí. */
  .proj-card__name{
    font-family:var(--font-serif);font-size:1.05rem;font-weight:500;
    letter-spacing:.03em;color:var(--midnight);line-height:1.25;text-transform:uppercase;
  }
  /* Peso 700 y no 600: es el de propiedades.html. Estaba en 600 solo porque la
     petición de fuentes no cargaba el 700 y un peso no cargado sale sintetizado.
     Ahora el 700 viaja en la URL, así que se puede usar el real. */
  .proj-card__loc{
    font-family:var(--font-body);font-size:.62rem;font-weight:700;
    text-transform:uppercase;letter-spacing:.16em;color:var(--sand);
  }
  .proj-card__stats{
    width:100%;display:grid;grid-template-columns:repeat(4,1fr);
    border-top:1px solid rgba(7,32,49,0.14);margin-top:10px;padding-top:12px;
  }
  .proj-stat{display:flex;flex-direction:column;align-items:center;gap:4px;padding:2px 6px;border-right:1px solid rgba(7,32,49,0.14);}
  .proj-stat:last-child{border-right:none;}
  .proj-stat strong{font-family:var(--font-body);font-size:.82rem;font-weight:700;color:var(--midnight);white-space:nowrap;}
  .proj-stat span{font-family:var(--font-body);font-size:.58rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:rgba(7,32,49,0.55);white-space:nowrap;}
  /* El precio va en sans: en propiedades.html es Montserrat 700, no serif. */
  .proj-card__price{
    width:100%;background:#EFEFEF;color:var(--midnight);text-align:center;
    font-family:var(--font-body);font-size:1.05rem;font-weight:700;
    letter-spacing:.01em;padding:11px 12px;margin-top:4px;
  }
  /* Tarjeta resaltada desde un pin del mapa */
  .proj-card.is-selected .proj-card__media{box-shadow:0 0 0 3px var(--sand),0 20px 44px rgba(0,0,0,0.4);}

  /* ---- Paginación. Anatomía de Zillow, medida en su página 15 de 20: fila
     centrada de círculos de 48px, número en negrita, ventana
     «1 … 14 15 16 … 20» (siempre la primera y la última, más ±1 alrededor de la
     actual) y chevrones de 40px con SVG de 16px a los lados. La página actual va
     con el círculo TEÑIDO, no relleno —allá es un azul claro sobre texto oscuro—
     y aquí el tinte es midnight al 10%.
     Peso 600 y no 700 a propósito: esta página solo carga Montserrat
     300/400/500/600, y pedir 700 obliga al navegador a sintetizar una negrita
     falsa. Es un número, no un encabezado → font-body, no la serif. ---- */
  .zpag{margin:30px 0 4px;display:flex;justify-content:center;}
  /* display:flex gana a [hidden] por especificidad, hay que apagarlo a mano */
  .zpag[hidden]{display:none;}
  .zpag__list{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:4px;list-style:none;margin:0;padding:0;}
  .zpag__list li{display:flex;}
  .zpag__n,.zpag__gap,.zpag__step{
    display:flex;align-items:center;justify-content:center;
    font-family:var(--font-body);font-size:1rem;font-weight:600;color:var(--midnight);
  }
  .zpag__n,.zpag__gap{width:48px;height:48px;}
  .zpag__n{background:none;border:none;border-radius:50%;padding:0;cursor:pointer;transition:background .15s ease;}
  .zpag__n:hover{background:rgba(7,32,49,0.06);}
  .zpag__n[aria-current="page"]{background:rgba(7,32,49,0.10);cursor:default;}
  .zpag__gap{color:rgba(7,32,49,0.45);}
  .zpag__step{width:40px;height:40px;background:none;border:none;border-radius:50%;padding:0;cursor:pointer;transition:background .15s ease;}
  .zpag__step:hover:not(:disabled){background:rgba(7,32,49,0.06);}
  .zpag__step:disabled{opacity:.3;cursor:default;}
  .zpag__step svg{width:16px;height:16px;display:block;}
  .zpag__n:focus-visible,.zpag__step:focus-visible{outline:2px solid var(--sand);outline-offset:-2px;}

  /* Atribución IDX. NO es decorativa: mostrar listados del MLS sin ella
     incumple los términos del feed (BeachesMLS / Miami REALTORS® vía Trestle).
     Es lo único que queda debajo de la grilla. */
  .idx{margin:20px auto 0;max-width:900px;text-align:center;font-size:.72rem;color:#8a9099;line-height:1.5;}

  /* ============================================================
     MÓVIL: MAPA Y LISTA SON DOS VISTAS, NO UNA ENCIMA DE OTRA.

     Antes el móvil apilaba una franja de mapa de 300 px sobre la grilla: el
     mapa quedaba demasiado pequeño para explorar y aun así robaba un tercio de
     la primera pantalla a las tarjetas, que es lo que de verdad se lee. Zillow
     resuelve esto —comprobado en su propia página, no de memoria— enseñando
     SOLO la lista y dejando una píldora flotante abajo al centro para saltar al
     mapa a pantalla completa. Aquí va igual, con una diferencia: la suya lleva
     «Map | Sort» y la nuestra solo el mapa, porque el orden ya vive en la fila
     de filtros y dos controles de orden en la misma pantalla se contradicen.
     ============================================================ */
  .zvista{display:none;}
  @media (max-width:1024px){
    /* El split deja de ser split: un contenedor con scroll propio dentro de una
       página que ya scrollea atrapa el gesto del dedo en móvil. */
    .zsplit{grid-template-columns:1fr;height:auto;min-height:0;overflow:visible;}
    /* La columna deja de tener scroll propio y recupera los márgenes de página
       que antes ponía .wrap. */
    .zcol{--zcol-pad:14px;--zcol-pad-b:104px;overflow:visible;max-height:none;padding:16px var(--zcol-pad) var(--zcol-pad-b);}
    /* Los 104px de abajo eran la holgura para que la píldora fija "Ver mapa" no
       tapara la paginación. Ahora el último hijo es el pie y ese padding se
       cancela (ver .zcol > .site-footer:last-child), así que la holgura se la
       queda el pie o la píldora se come su línea de copyright. */
    .zcol > .site-footer{padding-bottom:104px;}
    /* Por defecto: solo lista. El :not(--nomap) deja pasar la franja de aviso
       de cuando Google Maps no carga, que sí debe verse. */
    .zsplit:not(.zsplit--nomap) .zmap{display:none;}
    /* Vista mapa: ocupa lo que queda de pantalla bajo las barras pegajosas y se
       queda ahí (sticky) en vez de irse con el scroll.
       100dvh y no 100vh: en móvil, vh cuenta la barra de direcciones del
       navegador aunque esté visible, así que con vh el mapa se sale por abajo y
       la píldora queda fuera de alcance. */
    /* !important y no por gusto: al inicializarse, Google Maps escribe
       style="position:relative" DIRECTAMENTE en el nodo del mapa, y un estilo
       en línea gana a cualquier regla de hoja por específica que sea. Sin esto
       el sticky se caía a relative y —como la regla sí aplicaba su top— los
       286 px de `top` desplazaban el mapa hacia abajo en vez de fijarlo:
       quedaba medio metido fuera de pantalla con una franja blanca encima.
       Verificado: poniendo position:sticky en línea funcionaba, lo que
       confirmaba que el problema era de precedencia y no de soporte. */
    /* fixed y no sticky: sticky respeta la posición de flujo, así que el mapa
       arrancaba 403 px abajo —debajo del H1, la cuenta y el orden— y se salía
       por el pie. Anclado con top/bottom llena exactamente el hueco que dejan
       las barras, que es lo que hace Zillow: bajo el filtro, todo mapa.
       --alto-barras es el alto REAL de nav + filtros; --tope-pegajoso lleva
       8 px de aire de más que aquí dejarían una franja de fondo asomando. */
    .zsplit.is-mapa .zmap{
      display:block;position:fixed !important;
      top:var(--alto-barras,278px);left:0;right:0;bottom:0;
      width:auto;height:auto;border-radius:0;z-index:15;
    }
    /* Con el mapa fijo no queda nada que scrollear detrás, y dejar que la
       página se moviera bajo un mapa inmóvil se siente roto. */
    body.vista-mapa{overflow:hidden;}
    /* En vista mapa se esconde la columna ENTERA, con lo que la paginación y
       la atribución se van con ella. Antes eran hermanas del split y hacía
       falta una regla aparte (`.is-mapa ~ .zpag`); al mudarse dentro de .zcol
       esa regla sobra. */
    .zsplit.is-mapa .zcol{display:none;}

    .zvista{
      display:block;position:fixed;left:50%;transform:translateX(-50%);
      bottom:22px;z-index:40;
    }
    .zvista__btn{
      display:inline-flex;align-items:center;gap:9px;
      background:#fff;color:var(--midnight);
      border:1px solid #e3e4e7;border-radius:100px;
      padding:12px 22px;cursor:pointer;
      font-family:var(--font-body);font-size:.92rem;font-weight:600;
      box-shadow:0 6px 22px rgba(7,32,49,0.28);
      transition:transform .15s ease;
    }
    .zvista__btn:active{transform:scale(0.96);}
    .zvista__btn svg{width:18px;height:18px;flex:none;}
  }
  /* Suelo estrecho: la píldora se separa del borde y encoge un punto para no
     rozar la burbuja del chat, que va fija abajo a la derecha. */
  @media (max-width:400px){
    .zvista{bottom:18px;}
    .zvista__btn{padding:11px 18px;font-size:.88rem;}
  }
  /* El panel de filtros como hoja a pantalla completa. Un popover de 380px
     anclado al botón no cabe en un móvil, y con la barra sticky el panel
     quedaba cortado por el borde inferior de la pantalla. A partir de aquí es
     un modal: velo, cabecera con su X y el pie siempre visible. */
  @media (max-width:720px){
    /* Por contenido, igual que sus vecinas (ver el bloque de 1024px): a media
       fila, "Filtros" se llevaba una fila entera para él solo. */
    .zfil{flex:0 1 auto;}
    .zfilbtn{width:100%;justify-content:center;}
    .zfil__panel{
      position:fixed;inset:auto 0 0 0;top:auto;
      width:100%;max-width:none;max-height:88vh;
      border:none;border-radius:16px 16px 0 0;
      box-shadow:0 -10px 40px rgba(7,32,49,0.25);
    }
    .zfil__head{display:flex;}
    .zfil__body{max-height:none;flex:1 1 auto;}
    .zfil__fondo{display:block;position:fixed;inset:0;z-index:55;background:rgba(7,32,49,0.45);}
    .zfil__fondo[hidden]{display:none;}
    /* El pie se pega al borde inferior con el hueco de la barra del sistema. */
    .zfil__pie{padding-bottom:calc(12px + env(safe-area-inset-bottom));}
    /* El conmutador flotante "Ver mapa" vive fijo abajo al centro y se montaba
       justo encima del pie de la hoja, tapando "Ver N propiedades". Con la hoja
       abierta no hay ningún mapa que conmutar, así que se esconde en vez de
       pelear por el z-index. */
    body.zfil-abierto .zvista{display:none;}
    /* Mismo motivo, y misma solución que ya se aplicó al CTA flotante: la
       burbuja del chat ocupa la esquina inferior DERECHA, así que la acción
       principal se va a la izquierda y lo que queda debajo del widget es el
       enlace secundario, no el botón que cierra la interacción. */
    .zfil__ver{order:-1;margin-left:0;}
    .zfil__reset{margin-left:auto;}
  }
  @media (max-width:720px){
    .zlist{grid-template-columns:1fr;}
    /* Dos por fila en móvil, igual que hacían las píldoras nativas. */
    /* Las píldoras se dimensionan por CONTENIDO y empaquetan varias por fila, en
       vez de ocupar media fila cada una.

       Con `1 1 calc(50% - 5px)` cada píldora pedía la mitad de la fila, y las
       dos de etiqueta larga —"Hab. y baños" y "Tipo de propiedad"— piden MÁS que
       eso, así que se iban a una fila propia cada una: medido a 390px, cinco
       píldoras ocupaban CUATRO filas y la barra 254px, o sea --alto-barras en
       329 de una pantalla de 844 (39%). Empaquetadas por contenido caben
       "En venta + Precio + Hab. y baños" en una fila y "Tipo de propiedad +
       Filtros" en la siguiente: dos filas en vez de cuatro.

       No se usa `overflow-x:auto` para meterlas en UNA sola fila (que es lo que
       hace Zillow) porque .zpop__panel y .zdd__menu son `position:absolute` y un
       contenedor con overflow los RECORTA: se ganarían 42px a cambio de que los
       menús de precio y de tipo salieran cortados. */
    .searchbar__in > .zdd,.searchbar__in > .zpop{flex:0 1 auto;}
    .searchbar__in > .zdd .zdd__btn,.searchbar__in > .zpop .zpopbtn{width:100%;justify-content:center;}
    /* 7 números + 2 chevrones a 48px son ~430px: no caben en un móvil, y lo que
       se parte a la segunda fila es justo el chevron de «siguiente». */
    .zpag__list{gap:2px;}
    .zpag__n,.zpag__gap{width:38px;height:38px;}
    .zpag__n,.zpag__gap,.zpag__step{font-size:.92rem;}
    .zpag__step{width:34px;height:34px;}
  }
  /* Píldoras de precio a 360px: la mitad del ancho útil son 161px y el select
     se comía 50 en padding, dejando sitio para ~15 caracteres. "Hasta
     US$15.000" (renta) mide 15 justos y "Desde US$400.000" medía 16, así que
     se cortaba. Con la etiqueta abreviada en venta (priceLabel) más este
     ajuste de tipo y padding quedan ~17 caracteres de sitio y entran las dos
     escalas enteras. El chevron se mueve con el padding o se monta encima. */
  @media (max-width:420px){
    .searchbar__in > .zdd .zdd__btn,.searchbar__in > .zpop .zpopbtn{font-size:.8rem;padding:10px 12px;gap:6px;}
    /* El control de precio, dos píxeles más apretado que sus vecinos. No es
       gusto: en renta la etiqueta es "US$1.500 – 15.000" (los importes de
       alquiler no se abrevian, ver priceLabel) y a 360 px medía 153 px contra
       los 151 que da la mitad de la fila. Por dos píxeles se iba a una fila
       propia y la barra pegajosa pasaba de 204 a 251 px. */
    .searchbar__in > [data-pop="precio"] .zpopbtn{padding:10px 10px;gap:5px;}
  }
  /* Móvil estrecho (360–375px, que es el suelo real: iPhone SE y Android viejo).
     Ancho útil = 360 − 28 de padding = 332px. Con 36 + 32 + 1 de hueco la fila
     mide 324 y entra; con los valores del bloque de arriba mide 350 y se parte.
     36px sigue siendo un objetivo táctil aceptable para un control secundario. */
  @media (max-width:420px){
    .zpag__list{gap:1px;}
    .zpag__n,.zpag__gap{width:36px;height:36px;}
    .zpag__step{width:32px;height:32px;}
  }
