:root{
  /* ---- Manual de marca Agostini Desarrollos ---- */
  --brand-green:#6F8F72; --brand-orange:var(--brand-green); --brand-gray:#616163; --brand-dark:#151515; --brand-white:#FEFEFE;

  --bg:#151515;
  --panel:rgba(21,21,21,.90);
  --panel-soft:rgba(21,21,21,.78);
  --surface:rgba(254,254,254,.055);
  --surface-hover:rgba(254,254,254,.09);

  --line:rgba(254,254,254,.12);
  --line-soft:rgba(254,254,254,.07);

  --text-primary:#FEFEFE;
  --text-secondary:rgba(254,254,254,.72);
  --text-muted:rgba(254,254,254,.48);

  --primary:#6F8F72; --primary-hover:#8FB394; --primary-pressed:#5A7860;
  --primary-soft:rgba(111,143,114,.14); --primary-line:rgba(111,143,114,.40);
  --disabled:#616163;

  /* ---- estados comerciales ----
     ÚNICA definición de los colores de estado de una unidad. El mapa los lee
     desde acá (`paletaEstados()` en core.js hace getComputedStyle sobre :root),
     así que no hay una segunda copia en JavaScript.

     Por qué dejaron de ser verdes: el verde de marca es el color de las
     ACCIONES (botones, foco, selección). Cuando "Disponible" usaba ese mismo
     verde, un badge de estado y un CTA se leían igual y "Disponible" parecía
     clickeable. Ahora la familia de estado es propia: esmeralda más frío y
     luminoso que el verde de marca, gris medio para el intermedio y un rojo
     arcilla apagado para lo vendido. Nada de rojo puro, verde neón ni amarillo.

     Cada estado trae tres valores:
       ·        base  relleno del polígono en el mapa y color de referencia
       · -line         contorno del polígono y color de TEXTO (más luminoso:
                       el base no llega a 4.5:1 sobre #151515 en el caso de
                       "vendido", el -line sí)
       · -soft         fondo translúcido de badges y fichas */
  --st-disponible:#4FA47C; --st-disponible-line:#7ACCA4; --st-disponible-soft:rgba(79,164,124,.15);
  --st-reservado:#8D9298;  --st-reservado-line:#B4B9BF;  --st-reservado-soft:rgba(141,146,152,.16);
  --st-vendido:#B65F66;    --st-vendido-line:#D8949A;    --st-vendido-soft:rgba(182,95,102,.15);
  /* Sin subdividir: macrolotes y reservas. Gris neutro y SIEMPRE con borde
     discontinuo, que es lo que lo distingue sin depender del color. */
  --st-nosub:#62676D;      --st-nosub-line:#9AA0A6;      --st-nosub-soft:rgba(98,103,109,.16);

  /* funcionales: solo diagnóstico, nunca identidad */
  --fn-ok:#3FA37A; --fn-warn:#D9963F; --fn-risk:#D9584F;

  /* ---- alias heredados: mantienen el CSS existente funcionando ---- */
  --solid:#1C1C1C; --raise:#242424;
  --line2:var(--line-soft);
  --txt:var(--text-primary); --dim:var(--text-secondary); --mute:var(--text-muted);
  --mint:var(--primary); --amber:var(--primary); --slate:var(--brand-gray); --rose:var(--fn-risk);
  --r:12px; --rs:8px;
  --sh:0 18px 48px -12px rgba(0,0,0,.72);
  --sh-soft:0 4px 14px -8px rgba(0,0,0,.5);

  /* ---- despeje de barras fijas ----
     Había cuatro constantes distintas (62, 66, 70 y 72 px) para despejar la
     MISMA barra inferior, así que cada pieza quedaba a una altura distinta y
     alguna terminaba abajo del todo. Ahora la medida es una sola y cada pieza
     le suma su propio margen. `--mbar-h` es la caja de diseño de la barra; el
     inset seguro lo agrega el token, no el consumidor. */
  --mbar-h:56px;
  --mbar-clear:calc(var(--mbar-h) + env(safe-area-inset-bottom, 0px));
  /* El header ya se corre con `env(safe-area-inset-top)`, así que lo que
     cuelga debajo tiene que descontarlo también o se le mete abajo. En mobile
     el header mide 54 px y el token se redefine ahí. */
  --header-clear:calc(58px + env(safe-area-inset-top, 0px));

  /* ---- jerarquía de capas ----
     Una sola lista, de abajo hacia arriba. Antes los z-index estaban repartidos
     por el archivo y quién ganaba dependía del orden en el DOM. */
  --z-panel:30; --z-sheet:35; --z-float:37; --z-header:40; --z-nav:45;
  --z-tip:50; --z-modal:60; --z-vpanel:64; --z-toast:70; --z-adv:78;
  --z-msg:88; --z-boot:90; --z-intro:95; --z-list:97; --z-tour:100;
  --z-llsheet:110; --z-loader:120;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%;overflow:hidden}
body{
  font-family:Inter,-apple-system,system-ui,sans-serif;
  background:var(--bg);color:var(--txt);
  font-size:14px;line-height:1.45;-webkit-font-smoothing:antialiased;
  font-feature-settings:"tnum" 1,"cv05" 1;
}
button,input,select{font:inherit;color:inherit}
button{cursor:pointer;border:none;background:none}
:focus-visible{outline:2px solid rgba(111,143,114,.85);outline-offset:2px;border-radius:4px}
button:focus:not(:focus-visible),input:focus:not(:focus-visible),select:focus:not(:focus-visible){outline:none}
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important}
}
::-webkit-scrollbar{width:8px;height:8px}
::-webkit-scrollbar-thumb{background:rgba(255,255,255,.13);border-radius:4px}
::-webkit-scrollbar-track{background:transparent}
.glass{background:var(--panel);backdrop-filter:blur(22px) saturate(1.5);-webkit-backdrop-filter:blur(22px) saturate(1.5);border:1px solid var(--line);box-shadow:var(--sh)}
#map{position:fixed;inset:0}
#boot{position:fixed;inset:0;z-index:var(--z-boot);background:var(--bg);display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:16px;transition:opacity .45s ease}
#boot.off{opacity:0;pointer-events:none}
#boot .m{width:52px;height:52px;border-radius:14px;background:var(--primary);
  display:grid;place-items:center;font-weight:700;font-size:23px;color:#151515;letter-spacing:-1px;
  animation:bob 1.7s ease-in-out infinite}
@keyframes bob{0%,100%{transform:translateY(0) scale(1)}50%{transform:translateY(-7px) scale(1.04)}}
#boot .t{font-size:15px;font-weight:600;letter-spacing:-.2px}
#boot .s{font-size:12.5px;color:var(--mute);text-align:center;max-width:280px;line-height:1.5}
#boot .bar{width:180px;height:3px;border-radius:2px;background:rgba(255,255,255,.1);overflow:hidden}
#boot .bar i{display:block;height:100%;width:38%;border-radius:2px;background:var(--primary);
  animation:slide 1.5s cubic-bezier(.5,0,.5,1) infinite}
@keyframes slide{0%{transform:translateX(-110%)}100%{transform:translateX(370%)}}
.maplibregl-ctrl-attrib{font-size:9px!important;background:rgba(0,0,0,.5)!important}
.maplibregl-ctrl-attrib a{color:#8A8A8C!important}

/* ---------- HEADER ---------- */
header{
  position:fixed;top:env(safe-area-inset-top,0);left:0;right:0;height:58px;z-index:var(--z-header);
  display:flex;align-items:center;gap:14px;padding:0 14px;
  background:linear-gradient(180deg,rgba(7,8,9,.96) 0%,rgba(7,8,9,.75) 62%,transparent 100%);
}
.brand{display:flex;align-items:center;gap:10px;padding-right:14px;border-right:1px solid var(--line2)}
.mark{width:28px;height:28px;border-radius:7px;background:var(--primary);
  display:grid;place-items:center;font-weight:800;font-size:13px;color:var(--brand-dark);letter-spacing:-.5px}
.brand b{font-size:14px;font-weight:600;letter-spacing:-.2px;display:block;line-height:1.15}
.brand span{font-size:10.5px;color:var(--mute);letter-spacing:.4px;text-transform:uppercase}
.proj{display:flex;gap:4px;background:rgba(255,255,255,.045);padding:3px;border-radius:9px;border:1px solid var(--line2)}
.proj button{padding:5px 11px;border-radius:6px;font-size:12.5px;font-weight:500;color:var(--dim);white-space:nowrap;transition:.15s}
.proj button.on{background:var(--raise);color:var(--txt);box-shadow:0 1px 3px rgba(0,0,0,.4)}
.proj button:disabled{color:#4A4A4C;cursor:not-allowed}
.search{position:relative;margin-left:auto}
.search input{width:190px;padding:7px 10px 7px 30px;border-radius:8px;background:rgba(255,255,255,.05);
  border:1px solid var(--line2);font-size:12.5px;outline:none;transition:.18s}
.search input:focus{border-color:var(--primary-line);background:rgba(255,255,255,.07);width:220px}
.search svg{position:absolute;left:9px;top:50%;transform:translateY(-50%);opacity:.45}
.modes{display:flex;gap:3px;background:rgba(255,255,255,.045);padding:3px;border-radius:9px;border:1px solid var(--line2)}
.modes button{padding:6px 12px;border-radius:6px;font-size:12.5px;font-weight:500;color:var(--dim);display:flex;align-items:center;gap:6px;transition:.15s}
.modes button.on{background:var(--primary);color:var(--brand-dark);font-weight:700}
.hbtn{width:34px;height:34px;border-radius:8px;display:grid;place-items:center;
  background:rgba(255,255,255,.05);border:1px solid var(--line2);color:var(--dim);transition:.15s}
.hbtn:hover{background:rgba(255,255,255,.1);color:var(--txt)}

/* ---------- FILTERS ---------- */
/* `top` sale del despeje del header más el aire de 12 px: el número suelto de
   70 px ignoraba el inset seguro que el header sí consume. En escritorio da los
   mismos 70 px de siempre. `dvh` va después de `vh` para los navegadores que
   todavía no lo entienden. */
#filters{
  position:fixed;left:14px;top:calc(var(--header-clear) + 12px);width:268px;
  max-height:calc(100vh - 160px);
  max-height:calc(100dvh - 160px);
  z-index:var(--z-panel);
  border-radius:var(--r);display:flex;flex-direction:column;overflow:hidden;transition:.28s cubic-bezier(.4,0,.2,1)
}
#filters.hide{transform:translateX(-300px);opacity:0;pointer-events:none}
.fhead{display:flex;align-items:center;gap:10px;padding:12px 14px;border-bottom:1px solid var(--line2)}
/* El título empuja al resto contra el borde derecho: "Limpiar" y la cruz quedan
   juntas y el título no se mueve cuando aparece o desaparece la cruz. */
.fhead h3{font-size:12px;font-weight:600;letter-spacing:.7px;text-transform:uppercase;color:var(--dim);margin-right:auto}
/* En escritorio los filtros son un panel fijo del layout: cerrarlos no es una
   acción que exista. La cruz aparece solo en el bloque mobile. */
.fclose{display:none}
.fbody{overflow-y:auto;padding:4px 14px 14px}
.fgrp{padding:13px 0;border-bottom:1px solid var(--line2)}
.fgrp:last-child{border:none}
.flab{font-size:11px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;color:var(--mute);margin-bottom:9px;display:flex;justify-content:space-between}
.chk{display:flex;align-items:center;gap:9px;padding:6px 8px;border-radius:7px;cursor:pointer;transition:.13s;margin:0 -8px}
.chk:hover{background:rgba(255,255,255,.045)}
.chk .dot{width:9px;height:9px;border-radius:3px;flex:none}
/* Las referencias de Filtros salían con el hexadecimal escrito en el HTML —y
   "Reservado" repetía el verde de "Disponible"—. Ahora leen el token. */
.chk .dot--disponible{background:var(--st-disponible)}
.chk .dot--reservado{background:var(--st-reservado)}
.chk .dot--vendido{background:var(--st-vendido)}
.chk .nm{flex:1;font-size:13px}
.chk .ct{font-size:11.5px;color:var(--mute);font-variant-numeric:tabular-nums}
.chk input{display:none}
.chk .box{width:15px;height:15px;border-radius:4px;border:1.5px solid rgba(255,255,255,.22);display:grid;place-items:center;flex:none;transition:.13s}
.chk input:checked + .box{background:var(--primary);border-color:var(--primary)}
.chk .box svg{opacity:0;stroke:var(--brand-dark);stroke-width:3}
.chk input:checked + .box svg{opacity:1}
.rng{position:relative;height:26px;margin-top:4px}
.rng input{position:absolute;width:100%;top:8px;height:3px;-webkit-appearance:none;appearance:none;background:none;pointer-events:none;margin:0}
.rng .track{position:absolute;top:8px;left:0;right:0;height:3px;background:rgba(255,255,255,.12);border-radius:2px}
.rng .fill{position:absolute;top:8px;height:3px;background:var(--primary);border-radius:2px}
.rng input::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;border-radius:50%;background:#fff;
  border:2px solid var(--primary);pointer-events:auto;cursor:grab;box-shadow:0 2px 6px rgba(0,0,0,.5);margin-top:0}
.rng input::-moz-range-thumb{width:14px;height:14px;border-radius:50%;background:#fff;border:2px solid var(--primary);pointer-events:auto;cursor:grab}
.rngv{display:flex;justify-content:space-between;font-size:11.5px;color:var(--dim);margin-top:2px;font-variant-numeric:tabular-nums}
select.sel{width:100%;padding:7px 9px;border-radius:7px;background:rgba(255,255,255,.05);border:1px solid var(--line2);font-size:12.5px;outline:none;cursor:pointer}
select.sel:focus{border-color:rgba(111,143,114,.45)}
.tgl{display:flex;align-items:center;justify-content:space-between;padding:7px 0;cursor:pointer;font-size:13px}
.sw{width:34px;height:19px;border-radius:10px;background:rgba(255,255,255,.13);position:relative;transition:.18s;flex:none}
.sw::after{content:'';position:absolute;top:2px;left:2px;width:15px;height:15px;border-radius:50%;background:#fff;transition:.18s}
.tgl input{display:none}
.tgl input:checked + .sw{background:var(--primary)}
.tgl input:checked + .sw::after{transform:translateX(15px)}
.ffoot{padding:11px 14px;border-top:1px solid var(--line2);display:flex;align-items:center;justify-content:space-between;background:rgba(0,0,0,.25)}
.ffoot .n{font-size:19px;font-weight:700;letter-spacing:-.6px}
.ffoot .l{font-size:10.5px;color:var(--mute);text-transform:uppercase;letter-spacing:.5px}
.lnk{font-size:12px;color:var(--primary);font-weight:500}
.lnk:hover{text-decoration:underline}

/* ---------- LEGEND ---------- */
#legend{position:fixed;left:14px;bottom:14px;transition:left .28s cubic-bezier(.4,0,.2,1);z-index:var(--z-panel);border-radius:var(--r);padding:11px 13px;display:flex;flex-direction:column;gap:7px;min-width:180px}
#legend .ttl{font-size:10px;font-weight:600;letter-spacing:.7px;text-transform:uppercase;color:var(--mute);margin-bottom:1px}
#legend .row{display:flex;align-items:center;gap:8px;font-size:12.5px}
#legend .row .swatch{width:18px;height:13px;border-radius:3px;flex:none;border:1.5px solid;box-sizing:border-box}
#legend .row .dot{width:10px;height:10px;border-radius:3px}
#legend .row .v{margin-left:auto;color:var(--dim);font-variant-numeric:tabular-nums;font-size:12px}
#legend.shift{left:368px}
.bar{height:6px;border-radius:3px;background:linear-gradient(90deg,#2A2A2A,#616163,rgba(111,143,114,.55),#6F8F72,#8FB394);margin-top:2px}

/* ---------- DETAIL ---------- */
#detail{
  position:fixed;right:14px;top:calc(var(--header-clear) + 12px);bottom:14px;width:352px;z-index:var(--z-sheet);border-radius:var(--r);
  display:flex;flex-direction:column;overflow:hidden;transform:translateX(390px);opacity:0;pointer-events:none;
  transition:transform .34s cubic-bezier(.32,.72,0,1),opacity .2s
}
#detail.on{transform:none;opacity:1;pointer-events:auto}
.dhead{padding:15px 16px 13px;border-bottom:1px solid var(--line2);position:relative;flex:none}
.dhead .x{position:absolute;right:11px;top:11px;width:26px;height:26px;border-radius:7px;display:grid;place-items:center;color:var(--mute);transition:.14s}
.dhead .x:hover{background:rgba(255,255,255,.08);color:var(--txt)}
.dhead .pj{font-size:10.5px;letter-spacing:.9px;text-transform:uppercase;color:var(--mute);margin-bottom:3px}
.dhead h2{font-size:20px;font-weight:700;letter-spacing:-.6px;line-height:1.15}
.chips{display:flex;gap:6px;margin-top:9px;flex-wrap:wrap}
.chip{font-size:11px;font-weight:600;padding:3.5px 8px;border-radius:999px;letter-spacing:.2px}
/* Los badges de estado son delineados y translúcidos a propósito: un CTA es una
   superficie sólida y grande, un estado es una etiqueta. Si "Disponible" tuviera
   fondo pleno volvería a parecer un botón. */
.chip.st-disponible{background:var(--st-disponible-soft);color:var(--st-disponible-line);border:1px solid var(--st-disponible)}
.chip.st-reservado{background:var(--st-reservado-soft);color:var(--st-reservado-line);border:1px solid var(--st-reservado)}
.chip.st-vendido{background:var(--st-vendido-soft);color:var(--st-vendido-line);border:1px solid var(--st-vendido)}
.chip.esq{background:rgba(254,254,254,.15);color:rgba(254,254,254,.62)}
.dbody{flex:1;overflow-y:auto;padding:16px}
.price{display:flex;align-items:baseline;gap:8px;margin-bottom:3px}
.price .cur{font-size:13px;color:var(--dim);font-weight:600}
.price .v{font-size:31px;font-weight:700;letter-spacing:-1.4px;line-height:1;color:var(--text-primary)}
.price .um{font-size:12px;color:var(--mute);margin-left:auto}
.specs{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--line2);border-radius:var(--rs);overflow:hidden;margin:15px 0}
.specs div{background:var(--solid);padding:10px 11px}
.specs .k{font-size:10.5px;color:var(--mute);text-transform:uppercase;letter-spacing:.5px;margin-bottom:2px}
.specs .v{font-size:14px;font-weight:600;letter-spacing:-.2px}
.sect{margin-top:18px}
.sect h4{font-size:11px;font-weight:600;letter-spacing:.7px;text-transform:uppercase;color:var(--mute);margin-bottom:10px;display:flex;justify-content:space-between;align-items:center}
.simu{background:var(--solid);border:1px solid var(--line2);border-radius:var(--rs);padding:13px}
.simu .lin{display:flex;justify-content:space-between;font-size:12.5px;padding:4px 0;color:var(--dim)}
.simu .lin b{color:var(--txt);font-weight:600;font-variant-numeric:tabular-nums}
.simu .big{border-top:1px dashed var(--line);margin-top:9px;padding-top:10px;display:flex;align-items:baseline;justify-content:space-between}
.simu .big span{font-size:12px;color:var(--dim)}
.simu .big b{font-size:22px;font-weight:700;letter-spacing:-.8px;color:var(--primary)}
.cta{display:flex;flex-direction:column;gap:7px;margin-top:16px}
.btn{padding:11px;border-radius:9px;font-size:13.5px;font-weight:600;display:flex;align-items:center;justify-content:center;gap:8px;transition:.15s;letter-spacing:-.1px}
.btn.pri{background:var(--primary);color:var(--brand-dark);font-weight:700}
.btn.pri:active{background:var(--primary-pressed);transform:none}
/* En pantallas táctiles el `:hover` se queda pegado después del toque y el
   botón se quedaba subido 1 px hasta que tocabas otra cosa. Se gatea. */
@media (hover:hover){
  .btn.pri:hover{background:var(--primary-hover);transform:translateY(-1px)}
}
.btn.wa{background:var(--surface);color:var(--text-primary);border:1px solid var(--line)}
.btn.wa:hover{background:var(--surface-hover);border-color:var(--primary-line)}
.btn.gh{background:rgba(255,255,255,.06);border:1px solid var(--line);color:var(--txt)}
.btn.gh:hover{background:rgba(255,255,255,.11)}
.btn:disabled{opacity:.45;cursor:not-allowed;transform:none!important}
.btn2{display:grid;grid-template-columns:1fr 1fr;gap:7px}
.internal{background:rgba(111,143,114,.07);border:1px solid rgba(111,143,114,.22);border-radius:var(--rs);padding:12px;margin-top:16px}
.internal .t{font-size:10.5px;font-weight:700;letter-spacing:.7px;text-transform:uppercase;color:var(--primary);margin-bottom:8px;display:flex;align-items:center;gap:6px}
.internal .r{display:flex;justify-content:space-between;font-size:12.5px;padding:3px 0;color:var(--dim)}
.internal .r b{color:var(--txt);font-weight:600}
.internal .nt{font-size:12.5px;color:var(--txt);margin-top:7px;padding-top:8px;border-top:1px dashed rgba(111,143,114,.2);font-style:italic}
.wait{background:var(--solid);border:1px solid var(--line2);border-radius:var(--rs);padding:13px;margin-top:16px}
.wait p{font-size:12.5px;color:var(--dim);margin-bottom:9px}
.wait .f{display:flex;gap:6px}
.wait input{flex:1;padding:9px 10px;border-radius:7px;background:rgba(255,255,255,.05);border:1px solid var(--line2);font-size:12.5px;outline:none}
.wait input:focus{border-color:rgba(111,143,114,.45)}
.wait button{padding:0 14px;border-radius:7px;background:var(--primary);color:var(--brand-dark);min-height:44px;font-weight:600;font-size:12.5px}

/* ---------- SHORTLIST BAR ---------- */
#slbar{position:fixed;bottom:calc(14px + env(safe-area-inset-bottom,0px));left:50%;transform:translate(-50%,90px);z-index:36;border-radius:var(--r);
  padding:9px 10px 9px 14px;display:flex;align-items:center;gap:12px;transition:.3s cubic-bezier(.32,.72,0,1);opacity:0}
#slbar.on{transform:translate(-50%,0);opacity:1}
#slbar .items{display:flex;gap:6px}
#slbar .it{background:rgba(255,255,255,.07);border:1px solid var(--line2);border-radius:7px;padding:5px 8px;font-size:12px;display:flex;align-items:center;gap:7px}
#slbar .it button{color:var(--mute);font-size:15px;line-height:1}
#slbar .it button:hover{color:var(--rose)}

/* ---------- ANALYTICS ---------- */
#analytics{position:fixed;left:14px;top:calc(var(--header-clear) + 12px);bottom:14px;width:340px;z-index:31;border-radius:var(--r);
  display:none;flex-direction:column;overflow:hidden}
#analytics.on{display:flex}
.ahead{padding:13px 15px;border-bottom:1px solid var(--line2)}
.ahead h3{font-size:13px;font-weight:600;letter-spacing:-.2px}
.ahead p{font-size:11.5px;color:var(--mute);margin-top:2px}
.abody{flex:1;overflow-y:auto;padding:14px 15px}
.kpis{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:16px}
.kpi{background:var(--solid);border:1px solid var(--line2);border-radius:var(--rs);padding:10px 11px}
.kpi .k{font-size:10px;color:var(--mute);text-transform:uppercase;letter-spacing:.5px}
.kpi .v{font-size:21px;font-weight:700;letter-spacing:-.9px;margin-top:2px}
.kpi .v small{font-size:12px;color:var(--dim);font-weight:500;letter-spacing:0}
.asec{margin-bottom:18px}
.asec h4{font-size:11px;font-weight:600;letter-spacing:.7px;text-transform:uppercase;color:var(--mute);margin-bottom:9px}
.trow{display:flex;align-items:center;gap:9px;padding:7px 8px;border-radius:7px;cursor:pointer;transition:.13s;margin:0 -8px}
.trow:hover{background:rgba(255,255,255,.05)}
.trow .id{font-size:12.5px;font-weight:600;width:82px;flex:none}
.trow .mt{flex:1;height:4px;border-radius:3px;background:rgba(255,255,255,.08);overflow:hidden}
.trow .mt i{display:block;height:100%;border-radius:3px;background:linear-gradient(90deg,#616163,#6F8F72)}
.trow .n{font-size:11.5px;color:var(--dim);width:56px;text-align:right;flex:none;font-variant-numeric:tabular-nums}
.funnel{display:flex;flex-direction:column;gap:6px}
.fst{background:var(--solid);border:1px solid var(--line2);border-radius:7px;padding:8px 10px;position:relative;overflow:hidden}
.fst i{position:absolute;inset:0;background:linear-gradient(90deg,rgba(111,143,114,.20),rgba(111,143,114,.04));border-right:2px solid var(--primary)}
.fst .c{position:relative;display:flex;justify-content:space-between;align-items:center}
.fst .l{font-size:12.5px;font-weight:500}
.fst .v{font-size:13px;font-weight:700;font-variant-numeric:tabular-nums}
.fst .p{font-size:10.5px;color:var(--dim);margin-left:7px;font-weight:500}
.insight{background:rgba(111,143,114,.07);border:1px solid rgba(111,143,114,.2);border-radius:var(--rs);padding:11px 12px;font-size:12.5px;color:rgba(254,254,254,.82);line-height:1.5}
.insight b{color:var(--primary)}

/* ---------- MODALS ---------- */
/* El relleno suma el inset seguro: en un teléfono con muesca el modal se metía
   abajo del notch. Sin inset (escritorio) el cálculo da los 20 px de siempre. */
.ov{position:fixed;inset:0;background:rgba(3,5,7,.72);backdrop-filter:blur(6px);z-index:var(--z-modal);display:none;place-items:center;
  padding:calc(20px + env(safe-area-inset-top,0px)) 20px calc(20px + env(safe-area-inset-bottom,0px))}
.ov.on{display:grid}
.mdl{width:100%;max-width:460px;border-radius:16px;overflow:hidden;background:var(--solid);border:1px solid var(--line);box-shadow:var(--sh);
  max-height:88vh;max-height:88dvh;display:flex;flex-direction:column}
.mdl.wide{max-width:760px}
.mhead{padding:17px 19px;border-bottom:1px solid var(--line2);display:flex;align-items:flex-start;justify-content:space-between}
.mhead h3{font-size:17px;font-weight:700;letter-spacing:-.4px}
.mhead p{font-size:12.5px;color:var(--mute);margin-top:3px}
.mbody{padding:19px;overflow-y:auto}
.mfoot{padding:14px 19px;border-top:1px solid var(--line2);display:flex;gap:9px;background:rgba(0,0,0,.22)}
.mfoot .btn{flex:1}
.hold{background:rgba(111,143,114,.09);border:1px solid rgba(111,143,114,.26);border-radius:var(--rs);padding:12px;display:flex;align-items:center;gap:11px;margin-bottom:15px}
.hold .clk{font-size:25px;font-weight:700;color:var(--primary);letter-spacing:-1px;font-variant-numeric:tabular-nums}
.hold .tx{font-size:12px;color:rgba(254,254,254,.78);line-height:1.4}
.sum{background:rgba(255,255,255,.03);border:1px solid var(--line2);border-radius:var(--rs);padding:13px}
.sum .r{display:flex;justify-content:space-between;padding:5px 0;font-size:13px;color:var(--dim)}
.sum .r b{color:var(--txt);font-weight:600;font-variant-numeric:tabular-nums}
.sum .r.tot{border-top:1px solid var(--line);margin-top:7px;padding-top:10px}
.sum .r.tot b{font-size:19px;color:var(--primary);letter-spacing:-.6px}
table.cmp{width:100%;border-collapse:collapse;font-size:13px}
table.cmp th,table.cmp td{padding:9px 10px;text-align:left;border-bottom:1px solid var(--line2)}
table.cmp th{font-size:10.5px;text-transform:uppercase;letter-spacing:.6px;color:var(--mute);font-weight:600}
table.cmp td:first-child{color:var(--mute);font-size:12px}
table.cmp td b{font-weight:600;font-variant-numeric:tabular-nums}
table.cmp tr.hl td{background:var(--primary-soft)}
pre.code{background:#101010;border:1px solid var(--line2);border-radius:var(--rs);padding:13px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:11.5px;line-height:1.65;color:rgba(254,254,254,.78);overflow-x:auto;white-space:pre}
pre.code .s{color:#9DBFA1}.k{color:rgba(254,254,254,.62)}.c{color:rgba(254,254,254,.40)}
.steps{display:flex;flex-direction:column;gap:11px}
.step{display:flex;gap:11px}
.step .n{width:23px;height:23px;border-radius:7px;background:rgba(111,143,114,.14);color:var(--mint);display:grid;place-items:center;font-size:12px;font-weight:700;flex:none}
.step .t{font-size:13px;font-weight:600;margin-bottom:2px}
.step .d{font-size:12.5px;color:var(--dim);line-height:1.5}

/* ---------- VENDEDOR ---------- */
#vend{position:fixed;left:14px;top:calc(var(--header-clear) + 12px);bottom:14px;width:340px;z-index:31;border-radius:var(--r);display:none;flex-direction:column;overflow:hidden}
#vend.on{display:flex}
.vrow{padding:10px 11px;border-radius:var(--rs);background:var(--solid);border:1px solid var(--line2);margin-bottom:7px;cursor:pointer;transition:.14s}
/* Mismo motivo que en `.btn.pri`: en táctil la fila quedaba corrida 2 px. */
@media (hover:hover){
  .vrow:hover{border-color:rgba(111,143,114,.35);transform:translateX(2px)}
}
.vrow .top{display:flex;align-items:center;gap:8px;margin-bottom:4px}
.vrow .id{font-size:13px;font-weight:600}
.vrow .pr{margin-left:auto;font-size:12.5px;color:var(--dim);font-variant-numeric:tabular-nums}
.vrow .who{font-size:11.5px;color:var(--mute)}
.vrow .nt{font-size:11.5px;color:var(--dim);margin-top:4px;font-style:italic}

/* ---------- MISC ---------- */
#tip{position:fixed;z-index:var(--z-tip);pointer-events:none;background:rgba(10,12,15,.94);border:1px solid var(--line);
  border-radius:9px;padding:8px 10px;font-size:12px;box-shadow:var(--sh);display:none;backdrop-filter:blur(10px);min-width:135px}
#tip .a{font-weight:700;font-size:13px;letter-spacing:-.2px;margin-bottom:3px}
#tip .b{color:var(--dim);display:flex;justify-content:space-between;gap:14px;font-size:11.5px}
#tip .st{margin-top:5px;padding-top:5px;border-top:1px solid var(--line2);font-size:11px;font-weight:600}
/* `.pjlbl` NO lleva `pointer-events:none`. Lo heredaba de cuando era un rótulo
   pasivo como `.mzlbl` y `.ltlbl`; después pasó a ser un <button> con su propio
   manejador de clic, pero la regla se quedó. Con ella el toque atravesaba la
   tarjeta, caía en el lienzo, MapLibre disparaba su `click` y se abría la ficha
   del lote que hubiera debajo. El `stopPropagation` del botón no llegaba a
   correr nunca: el botón ni siquiera era el destino del toque. */
.pjlbl{background:rgba(8,10,13,.86);border:1px solid rgba(111,143,114,.45);color:#FEFEFE;
  padding:6px 12px;border-radius:10px;pointer-events:auto;white-space:nowrap;backdrop-filter:blur(6px);
  text-align:center;box-shadow:0 6px 20px -6px rgba(0,0,0,.7)}
.pjlbl b{display:block;font-size:14px;font-weight:700;letter-spacing:-.3px}
.pjlbl span{font-size:11px;color:var(--primary);font-weight:600}
.mzlbl{background:rgba(8,10,13,.72);border:1px solid rgba(255,255,255,.14);color:#FEFEFE;font-size:9.5px;font-weight:700;
  padding:1.5px 5px;border-radius:5px;letter-spacing:.5px;pointer-events:none;white-space:nowrap;backdrop-filter:blur(4px)}
.ltlbl{color:#fff;font-size:10px;font-weight:700;text-shadow:0 1px 3px rgba(0,0,0,.95),0 0 8px rgba(0,0,0,.7);pointer-events:none}
#toast{position:fixed;bottom:calc(22px + env(safe-area-inset-bottom,0px));left:50%;transform:translate(-50%,80px);z-index:var(--z-toast);background:var(--raise);
  border:1px solid var(--line);border-radius:11px;padding:12px 16px;font-size:13px;box-shadow:var(--sh);
  transition:.32s cubic-bezier(.32,.72,0,1);opacity:0;display:flex;align-items:center;gap:10px;max-width:400px}
#toast.on{transform:translate(-50%,0);opacity:1}
#toast .ic{width:19px;height:19px;border-radius:50%;background:var(--primary);display:grid;place-items:center;flex:none}
.demo{position:fixed;top:64px;left:50%;transform:translateX(-50%);z-index:29;background:rgba(10,12,15,.8);
  border:1px solid var(--line2);border-radius:999px;padding:4px 12px;font-size:11px;color:var(--mute);
  backdrop-filter:blur(10px);white-space:nowrap;letter-spacing:.2px}
.demo b{color:var(--dim);font-weight:600}
#gps{position:fixed;bottom:calc(14px + env(safe-area-inset-bottom,0px));left:50%;transform:translate(-50%,120px);z-index:var(--z-float);border-radius:14px;
  padding:12px 14px;display:flex;align-items:center;gap:12px;min-width:290px;max-width:calc(100vw - 28px);
  transition:.34s cubic-bezier(.32,.72,0,1);opacity:0}
#gps.on{transform:translate(-50%,0);opacity:1}
#gps .pin{width:34px;height:34px;border-radius:10px;background:rgba(111,143,114,.15);display:grid;place-items:center;flex:none;position:relative}
#gps .pin::after{content:'';position:absolute;inset:-4px;border-radius:13px;border:1.5px solid rgba(111,143,114,.45);animation:pulse 2s infinite}
#gps.sim .pin{background:transparent;border:1.5px dashed var(--primary-line)}
#gps.sim .pin::after{display:none}
#gps .simtag{display:none;font-size:9.5px;font-weight:700;letter-spacing:.7px;text-transform:uppercase;
  color:var(--primary);border:1px solid var(--primary-line);border-radius:5px;padding:1px 6px;margin-bottom:3px}
#gps.sim .simtag{display:inline-block}
@keyframes pulse{0%{transform:scale(.85);opacity:1}100%{transform:scale(1.25);opacity:0}}
#gps .tx{flex:1;min-width:0}
#gps .k{font-size:10.5px;letter-spacing:.7px;text-transform:uppercase;color:var(--primary);font-weight:600}
#gps .v{font-size:15px;font-weight:700;letter-spacing:-.3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#gps .s{font-size:11.5px;color:var(--mute)}
#gps button{padding:8px 12px;border-radius:8px;font-size:12.5px;font-weight:600;flex:none}
#simgps{font-size:12px;font-weight:600;color:var(--primary);min-height:38px;white-space:nowrap;
  background:rgba(111,143,114,.09);padding:8px 11px;border-radius:8px;border:1px solid rgba(111,143,114,.3);
  display:flex;align-items:center;gap:6px;transition:.15s;flex:none}
#simgps:hover{background:rgba(111,143,114,.14)}
#simgps.act{background:var(--primary);color:var(--brand-dark);border-color:var(--primary)}
.maplibregl-user-location-dot,.maplibregl-user-location-dot::before{background-color:#6F8F72!important}
.maplibregl-user-location-dot{border:2px solid #151515!important}
.maplibregl-user-location-accuracy-circle{background-color:rgba(111,143,114,.18)!important}
.zoomhint{position:fixed;right:14px;bottom:calc(82px + env(safe-area-inset-bottom,0px));z-index:29;font-size:11px;color:var(--mute);background:rgba(10,12,15,.72);
  padding:5px 10px;border-radius:7px;border:1px solid var(--line2);backdrop-filter:blur(8px)}

/* ---------- SIMULADOR DE CUOTAS (réplica del interno de Agostini) ---------- */
#ovSim .mdl{max-width:820px}
.simgrid{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.simfield label{display:block;font-size:11px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;color:var(--mute);margin-bottom:6px}
.simfield .wrap{display:flex;align-items:center;gap:6px;background:rgba(255,255,255,.05);border:1px solid var(--line2);border-radius:8px;padding:0 10px;transition:.15s}
.simfield .wrap:focus-within{border-color:rgba(111,143,114,.5);background:rgba(255,255,255,.07)}
.simfield .wrap b{color:var(--mute);font-weight:600}
.simfield input{flex:1;background:none;border:none;outline:none;padding:10px 0;font-size:15px;font-weight:600;font-variant-numeric:tabular-nums}
.idx{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:14px}
.idxc{background:var(--solid);border:1px solid var(--line2);border-radius:var(--rs);padding:11px 12px}
.idxc .h{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}
.idxc .h span{font-size:11px;font-weight:600;letter-spacing:.4px;text-transform:uppercase;color:var(--mute)}
.idxc .h b{font-size:11.5px;color:var(--primary)}
.idxr{display:flex;align-items:center;justify-content:space-between;padding:2.5px 0;font-size:12px;color:var(--dim)}
.idxr input{width:56px;text-align:right;background:rgba(255,255,255,.05);border:1px solid var(--line2);
  border-radius:5px;padding:2px 5px;font-size:11.5px;outline:none;font-variant-numeric:tabular-nums}
.idxr input:focus{border-color:rgba(111,143,114,.45)}
.sem{border-radius:var(--rs);padding:13px 14px;margin-bottom:14px;border:1px solid}
.sem.verde{background:rgba(63,163,122,.10);border-color:rgba(63,163,122,.34)}
.sem.amarillo{background:rgba(217,150,63,.10);border-color:rgba(217,150,63,.34)}
.sem.rojo{background:rgba(217,88,79,.10);border-color:rgba(217,88,79,.34)}
.sem .k{font-size:10px;font-weight:700;letter-spacing:.9px;text-transform:uppercase;color:var(--mute);margin-bottom:5px}
.sem .t{font-size:17px;font-weight:700;letter-spacing:-.4px;display:flex;align-items:center;gap:9px}
.sem .t i{width:11px;height:11px;border-radius:50%;flex:none}
.sem.verde .t i{background:var(--fn-ok)} .sem.amarillo .t i{background:var(--fn-warn)} .sem.rojo .t i{background:var(--fn-risk)}
.sem .d{font-size:12.5px;color:var(--dim);margin-top:4px}
.simcards{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:14px}
.simcard{background:var(--solid);border:1px solid var(--line2);border-radius:var(--rs);padding:12px 13px}
.simcard .k{font-size:10px;letter-spacing:.8px;text-transform:uppercase;color:var(--mute)}
.simcard .v{font-size:27px;font-weight:700;letter-spacing:-1.1px;margin:2px 0 1px;color:var(--text-primary)}
.simcard .s{font-size:11.5px;color:var(--mute)}
.simcard .c{font-size:12.5px;color:var(--dim);margin-top:5px;font-variant-numeric:tabular-nums}
.chartbox{background:var(--solid);border:1px solid var(--line2);border-radius:var(--rs);padding:13px;margin-bottom:14px}
.chartbox .ttl{font-size:11.5px;color:var(--dim);margin-bottom:10px}
.chartbox .lg{display:flex;gap:14px;font-size:11px;color:var(--mute);margin-top:8px}
.chartbox .lg i{display:inline-block;width:10px;height:3px;border-radius:2px;margin-right:5px;vertical-align:middle}
table.simt{width:100%;border-collapse:collapse;font-size:12.5px}
table.simt th{font-size:10px;text-transform:uppercase;letter-spacing:.6px;color:var(--mute);font-weight:600;text-align:left;padding:7px 8px;border-bottom:1px solid var(--line2)}
table.simt td{padding:7px 8px;border-bottom:1px solid var(--line2);font-variant-numeric:tabular-nums}
table.simt td:last-child{text-align:right}
.pill{font-size:10.5px;font-weight:700;padding:2px 7px;border-radius:999px}
.pill.verde{background:rgba(63,163,122,.16);color:#6FC5A0}
.pill.amarillo{background:rgba(217,150,63,.16);color:#E5B571}
.pill.rojo{background:rgba(217,88,79,.16);color:#E88C85}
/* Acá vivía `.simfoot` como pie de letra chica dentro de `#simOut`. Ese
   disclaimer duplicado lo eliminó `core.js` al reestructurar el modal, y el
   nombre pasó a designar OTRA cosa: la zona del CTA "Ver proyección". La regla
   vieja quedaba pintando ese bloque con texto de 10,5 px centrado y en gris,
   así que se va. La definición vigente está al final del archivo. */

/* ---------- INTRODUCCIÓN DE ENTRADA ---------- */
/* El z-index vive una sola vez, en el bloque editorial de más abajo: acá
   estaba declarado 92 y allá 95, y el que mandaba era el segundo. */
#entryIntro{position:fixed;inset:0;display:none;align-items:center;justify-content:center;
  padding:calc(24px + env(safe-area-inset-top,0px)) 24px calc(24px + env(safe-area-inset-bottom,0px));background:rgba(4,6,8,.62);backdrop-filter:blur(9px) saturate(1.1);
  -webkit-backdrop-filter:blur(9px) saturate(1.1);opacity:0;transition:opacity .34s ease}
#entryIntro.on{display:flex}
#entryIntro.vis{opacity:1}
#entryIntro .card{width:100%;max-width:720px;background:var(--panel-soft);border:1px solid var(--line);
  border-radius:18px;box-shadow:var(--sh);overflow:hidden;
  transform:translateY(14px) scale(.985);transition:transform .38s cubic-bezier(.32,.72,0,1);
  max-height:calc(100vh - 48px);
  max-height:calc(100dvh - 48px);display:flex;flex-direction:column}
#entryIntro.vis .card{transform:none}
#entryIntro .head{padding:26px 26px 20px;text-align:center;flex:none}
#entryIntro .eyebrow{font-size:10.5px;font-weight:700;letter-spacing:1.3px;text-transform:uppercase;color:var(--primary)}
#entryIntro h2{font-size:25px;font-weight:700;letter-spacing:-.8px;margin-top:8px;line-height:1.15}
#entryIntro .sub{font-size:13.5px;color:var(--dim);margin-top:7px;line-height:1.5}
#entryIntro .opts{display:grid;grid-template-columns:1fr 1fr;gap:12px;padding:0 22px 22px;overflow-y:auto}
.eopt{background:var(--solid);border:1px solid var(--line2);border-radius:var(--r);padding:18px 17px;
  display:flex;flex-direction:column;transition:border-color .18s,transform .18s,background .18s}
.eopt:hover{border-color:rgba(111,143,114,.32);background:rgba(255,255,255,.035)}
.eopt .ic{width:40px;height:40px;border-radius:11px;background:rgba(111,143,114,.12);color:var(--mint);
  display:grid;place-items:center;margin-bottom:13px;flex:none}
.eopt h3{font-size:16px;font-weight:700;letter-spacing:-.3px}
.eopt p{font-size:13px;color:var(--dim);line-height:1.5;margin-top:6px;flex:1}
.eopt .btn{margin-top:15px;min-height:46px}
.eopt .note{font-size:11px;color:var(--mute);margin-top:9px;line-height:1.45;display:flex;gap:6px;align-items:flex-start}
.eopt .note svg{flex:none;margin-top:1px;opacity:.7}
.eopt .demo-btn{margin-top:8px;padding:10px;border-radius:8px;font-size:12.5px;font-weight:600;min-height:44px;
  background:transparent;border:1px dashed var(--primary-line);color:var(--primary);
  display:flex;align-items:center;justify-content:center;gap:7px;transition:.16s ease}
.eopt .demo-btn:hover{background:var(--primary-soft);border-style:solid}
#introErr{display:none;margin:0 22px 18px;padding:11px 13px;border-radius:var(--rs);
  background:rgba(217,88,79,.1);border:1px solid rgba(217,88,79,.3);color:#F0C4C0;
  font-size:12.5px;line-height:1.5}
#introErr.on{display:block}
#entryIntro .foot{padding:0 22px 20px;text-align:center;font-size:11.5px;color:var(--mute);flex:none}
#entryIntro .foot button{color:var(--dim);text-decoration:underline;text-underline-offset:3px;font-size:11.5px}
#entryIntro .foot button:hover{color:var(--txt)}

/* ---------- CALLOUT DE ORIENTACIÓN ---------- */
#exploreGuide{position:fixed;left:50%;bottom:calc(16px + env(safe-area-inset-bottom,0px));transform:translate(-50%,120px);z-index:38;
  width:min(430px,calc(100vw - 28px));border-radius:var(--r);padding:15px 16px;
  transition:transform .38s cubic-bezier(.32,.72,0,1),opacity .28s;opacity:0;display:none}
#exploreGuide.on{display:block}
#exploreGuide.vis{transform:translate(-50%,0);opacity:1}
#exploreGuide .x{position:absolute;right:9px;top:9px;width:24px;height:24px;border-radius:6px;
  display:grid;place-items:center;color:var(--mute);transition:.14s}
#exploreGuide .x:hover{background:rgba(255,255,255,.08);color:var(--txt)}
#exploreGuide h4{font-size:14px;font-weight:700;letter-spacing:-.3px;margin-bottom:11px;padding-right:26px}
#exploreGuide ol{list-style:none;counter-reset:g;display:flex;flex-direction:column;gap:8px;margin-bottom:14px}
#exploreGuide li{counter-increment:g;display:flex;gap:10px;font-size:12.5px;color:var(--dim);line-height:1.45}
#exploreGuide li::before{content:counter(g);width:19px;height:19px;border-radius:6px;flex:none;
  background:var(--primary-soft);color:var(--primary);font-size:11px;font-weight:700;
  display:grid;place-items:center;margin-top:.5px}
#exploreGuide .acts{display:grid;grid-template-columns:1fr 1fr;gap:8px}
#exploreGuide .acts .btn{padding:9px;font-size:12.5px}
#filters.pulseHi{border-color:var(--primary-line);box-shadow:var(--sh),0 0 0 3px rgba(111,143,114,.12);
  animation:pulseHi 1.15s ease-in-out 2}
@keyframes pulseHi{0%,100%{box-shadow:var(--sh),0 0 0 3px rgba(111,143,114,.10)}
  50%{box-shadow:var(--sh),0 0 0 7px rgba(111,143,114,.20)}}
/* Acá vivía un bloque a 760 px que ajustaba `#entryIntro .card/.opts/.eopt`:
   ese marcado ya no existe (lo reemplazó `.icard`) y el breakpoint suelto
   peleaba con la unificación en 900. Lo único que seguía vivo —el relleno de
   la intro y el apilado de las acciones de la guía— se mudó al bloque mobile. */

/* ---------- AGENDAR VISITA ---------- */
#ovVis .mdl{max-width:560px}
.vsec{margin-bottom:15px}
.vsec>label,.vlab{display:block;font-size:11px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;
  color:var(--text-muted);margin-bottom:7px}
.vin{width:100%;padding:11px 12px;border-radius:8px;background:var(--surface);border:1px solid var(--line);
  color:var(--text-primary);font-size:14px;outline:none;transition:.16s ease;min-height:44px}
.vin:focus{border-color:var(--primary-line);background:var(--surface-hover)}
.vin::placeholder{color:var(--text-muted)}
/* Fila de dos campos DEL FORMULARIO DE VISITA. Acotada a #ovVis: `.vrow` es
   además la tarjeta de unidad del panel de vendedor, y esta grilla la partía en
   dos columnas de 150 px donde el texto caía palabra por palabra. */
#ovVis .vrow{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.vchips{display:flex;flex-wrap:wrap;gap:7px}
.vchip{padding:9px 13px;border-radius:8px;background:var(--surface);border:1px solid var(--line);
  font-size:13px;font-weight:600;color:var(--text-secondary);transition:.16s ease;min-height:44px}
.vchip:hover{background:var(--surface-hover);border-color:var(--primary-line)}
.vchip.on{background:var(--primary);border-color:var(--primary);color:var(--brand-dark)}
.vchip:disabled{opacity:.35;cursor:not-allowed;background:transparent}
.vlote{display:flex;align-items:center;gap:9px;background:var(--surface);border:1px solid var(--line);
  border-radius:8px;padding:10px 12px;font-size:13.5px}
.vlote b{font-weight:700}
.vlote span{margin-left:auto;color:var(--text-muted);font-size:12px}
.vok{text-align:center;padding:8px 4px 4px}
.vok .ic{width:52px;height:52px;border-radius:50%;background:var(--primary-soft);border:1px solid var(--primary-line);
  color:var(--primary);display:grid;place-items:center;margin:0 auto 14px}
.vok h3{font-size:19px;font-weight:700;letter-spacing:-.4px}
.vok p{font-size:13px;color:var(--text-secondary);margin-top:6px;line-height:1.5}
.vres{background:var(--surface);border:1px solid var(--line);border-radius:var(--rs);padding:13px;margin-top:16px;text-align:left}
.vres .r{display:flex;justify-content:space-between;gap:14px;padding:5px 0;font-size:13px;color:var(--text-secondary)}
.vres .r b{color:var(--text-primary);font-weight:600;text-align:right}
#visErr{display:none;margin-top:4px;font-size:12.5px;color:#E88C85}
#visErr.on{display:block}
@media(max-width:1120px){#detail{width:320px}#filters{width:250px}}
/* -----------------------------------------------------------------------------
   MOBILE — un solo breakpoint: 900 px.
   Antes convivían 900 y 860 y entre 861 y 900 no había ni selector de proyectos,
   ni buscador, ni filtros, ni barra inferior: la franja quedaba sin interfaz.
   Todo lo que estaba en 860 se mudó acá o se reescribió a 900 en su lugar.
   -------------------------------------------------------------------------- */
@media(max-width:900px){
  /* El header baja a 54 px, así que el despeje que consumen los paneles
     anclados debajo tiene que bajar con él. */
  :root{--header-clear:calc(54px + env(safe-area-inset-top, 0px))}
  header{gap:9px;padding:0 10px;height:54px}
  .brand span,.proj,.search{display:none}
  .simgrid,.idx,.simcards{grid-template-columns:1fr}
  .modes{margin-left:auto}
  .modes button{padding:6px 8px;font-size:11.5px}
  .brand{padding-right:9px}
  #simgps span{display:none}
  #simgps{padding:8px}
  #ovVis .vrow{grid-template-columns:1fr}
  /* Venían del bloque muerto de 760 px. */
  #entryIntro{padding:14px}
  #exploreGuide .acts{grid-template-columns:1fr}
  .demo{display:none}
  #gps{bottom:calc(10px + env(safe-area-inset-bottom,0px));padding:10px 11px;min-width:0;width:calc(100vw - 20px)}
  #gps button{min-height:44px;min-width:88px}
  .btn{min-height:44px}
}
/* =============================================================================
   CAPA 2 — dirección visual, tipografía Cadiz y componentes nuevos.
   Se aplica como override sobre la base para no reescribir reglas ya probadas.
   ========================================================================== */

/* ------------------------------------------------------------ tipografía ---
   Funnel Sans (OFL), autohospedada en /assets/fonts/. Es una fuente VARIABLE:
   un solo archivo de 17 KB cubre los pesos 300 a 800. Se usa para todo —
   títulos, cuerpo e interfaz — y la jerarquía la dan el tamaño y el peso, no
   el cambio de familia. Cadiz queda descartada: es comercial y no fue
   entregada.                                                                  */
@font-face{
  font-family:'Funnel Sans'; font-style:normal; font-weight:300 800;
  font-display:swap; src:url('../fonts/FunnelSans.woff2') format('woff2');
}

:root{
  /* --- familias --- */
  --font-body:'Funnel Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --font-title:var(--font-body);     /* misma familia: jerarquía por tamaño y peso */
  --font-primary:var(--font-body);   /* alias heredado: no romper reglas viejas */

  /* --- escala tipográfica --- */
  --fs-display:30px;   /* títulos de intro y modales grandes */
  --fs-h2:21px;
  --fs-h3:16.5px;
  --fs-body:14.5px;    /* cuerpo cómodo, un punto más que antes */
  --fs-ui:13.5px;      /* botones, controles */
  --fs-sm:12.5px;      /* metadatos */
  --fs-xs:11px;        /* etiquetas y overlines */

  --lh-title:1.18;
  --lh-body:1.55;
  --lh-tight:1.35;

  --fw-body:400; --fw-medium:500; --fw-semi:600; --fw-bold:700;
  --ls-over:.09em;     /* overlines en mayúsculas */

  /* Dos radios. Nada más. */
  --r:12px; --rs:6px;
  /* Sombras menos profundas: la jerarquía la da el contraste, no la caída. */
  --sh:0 10px 28px -14px rgba(0,0,0,.62);
  --sh-soft:0 4px 14px -8px rgba(0,0,0,.5);
  --panel:#181818;
  --panel-soft:#1C1C1C;
}
body{ font-family:var(--font-body); font-size:var(--fs-body); line-height:var(--lh-body); }
h1,h2,h3{ font-family:var(--font-title); font-weight:var(--fw-semi);
  letter-spacing:-.022em; line-height:var(--lh-title); }
h4{ font-family:var(--font-body); font-weight:var(--fw-semi); letter-spacing:.01em; }
/* Números tabulares: precios, superficies y contadores no bailan al cambiar. */
.price .v,.ffoot .n,.kpi .v,.interes b,.adv__recprice,.vpanel__price,
.cmp td,.simt td,#fcount,#fval{ font-variant-numeric:tabular-nums; }

/* Paneles de lectura: sólidos, borde sutil, casi sin blur. */
#filters,#detail,#analytics,#vend,.mdl,.lv__card,.icard,.llsheet__card,.tour__pop{
  background:var(--panel); backdrop-filter:none; -webkit-backdrop-filter:none;
  border:1px solid var(--line); box-shadow:var(--sh);
}
/* Piezas chicas sobre el mapa: ahí sí, algo de transparencia. */
#legend,#gps,#slbar,#exploreGuide,.msg,.demotag{
  background:rgba(21,21,21,.88);
  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
  border:1px solid var(--line); box-shadow:var(--sh-soft);
}

/* Normalización de radios: todo cae en 6 o 12. */
.proj,.modes,.rng .track,.rng .fill,.chk,.chk .box,select.sel,.hbtn,.mark,
.search input,.proj button,.modes button,#legend .row .swatch,#legend .row .dot,
.chk .dot,.bar{ border-radius:var(--rs); }
#filters,#detail,#analytics,#vend,#legend,#gps,.mdl,.icard{ border-radius:var(--r); }
.sw,.rng input::-webkit-slider-thumb,.rng input::-moz-range-thumb{ border-radius:999px; }

/* El naranja es acción, disponibilidad, selección, foco y progreso.
   No es decoración: se le baja el volumen donde solo adornaba. */
#filters .fhead h3,#analytics h3,#vend h3{ color:var(--text-primary); }
.sect h4{ color:var(--text-secondary); letter-spacing:.02em; }

.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}
.sr-only:focus{position:static;width:auto;height:auto;margin:0;clip:auto;white-space:normal}

/* Checkbox accesible: se oculta visualmente pero conserva foco y teclado
   (nada de display:none). */
.chk input[type=checkbox],.tgl input[type=checkbox]{
  position:absolute;width:1px;height:1px;opacity:0;margin:0;
}
.chk input:focus-visible + .box,.tgl input:focus-visible + .sw{
  outline:2px solid var(--primary); outline-offset:2px;
}

/* ------------------------------------------------------- loader Osmo ------ */
html.is-loading, html.is-loading body{ overflow:hidden; }
/* La salida es una transición de CSS, no una timeline de GSAP. GSAP avanza con
   requestAnimationFrame: si el navegador no entrega cuadros —pestaña de fondo,
   Safari mobile bajo carga— la timeline no termina nunca y el loader se queda
   puesto. Una transición de opacidad la resuelve el compositor y, si tampoco
   corre, el respaldo por temporizador lo saca igual. */
.loading-container{position:fixed;inset:0;z-index:var(--z-loader);background:var(--brand-dark);
  display:grid;place-items:center;font-family:var(--font-primary);
  opacity:1;transition:opacity .38s ease}
.loading-container.is--out{opacity:0;pointer-events:none}
.loading-screen{position:relative;display:flex;align-items:center;gap:clamp(18px,4vw,44px)}
.loading__progress{position:absolute;left:clamp(-34px,-4vw,-22px);top:0;bottom:0;width:2px;
  background:rgba(254,254,254,.12);border-radius:999px;overflow:hidden}
/* El relleno lo escribe el JS como `transform:scaleY(x)` y lo anima esta
   transición. Sin GSAP: es un solo elemento y una sola propiedad. */
.loading__progress-inner{position:absolute;inset:0;background:var(--primary);
  transform-origin:bottom center;transform:scaleY(0);
  transition:transform .28s cubic-bezier(.4,0,.2,1)}
/* Respiración mientras se espera un recurso real (tiles del mapa). Va sobre la
   opacidad y no sobre el transform, para no pelearse con el valor que escribe
   el JS. Si la animación no corre, la barra simplemente queda quieta: el
   porcentaje sigue siendo correcto. */
@keyframes loaderRespira{0%,100%{opacity:1}50%{opacity:.55}}
.loading__progress-inner.is--waiting{animation:loaderRespira 1.6s ease-in-out infinite}

/* --- el contador: un solo nodo de texto ---------------------------------
   `min-width` reserva de entrada más de lo que ocupa "100%", que es la cadena
   más ancha. Sin eso la caja crecía 10 px al pasar de "75%" a "100%" y, como la
   barra está posicionada contra `.loading-screen`, la barra se corría 5 px
   justo en el último escalón. Medido a 390 px: "100%" ocupa 138 px con una
   fuente de 58 px, o sea 2,38em; 2,9em deja 22 % de margen y acompaña solo al
   `clamp`, sin depender del ancho de ningún glifo ni de ninguna medición en JS.

   `line-height:1.25` es lo que hace que la caja CONTENGA los glifos: con 1 el
   texto pintado sobresalía 7 px arriba y abajo de su propia caja. Hoy no hay
   ningún ancestro con overflow —está verificado— así que no se recortaba nada,
   pero dejarlo dependiendo de eso es exactamente el tipo de fragilidad que
   rompió el contador anterior.

   `tabular-nums` mantiene todos los dígitos del mismo ancho y `nowrap` impide
   que el "%" caiga a otro renglón: el número y el símbolo son el mismo nodo de
   texto, no pueden separarse. */
.loading__numbers{display:flex;align-items:center;justify-content:center}
.loading__pct{
  display:block;
  white-space:nowrap;
  font-variant-numeric:tabular-nums;
  font-size:clamp(58px,13vw,138px);
  line-height:1.25;
  font-weight:600;
  letter-spacing:-.03em;
  color:var(--brand-white);
  text-align:center;
  min-width:2.9em;
  overflow:visible;
}
.loading__error{position:absolute;left:50%;transform:translateX(-50%);bottom:-64px;width:min(88vw,340px);
  text-align:center;font-size:12.5px;color:var(--text-muted);line-height:1.5}
.loading__retry{position:absolute;left:50%;transform:translateX(-50%);bottom:-124px;
  min-height:44px;padding:0 20px;border-radius:var(--rs);
  background:var(--primary);color:var(--brand-dark);font-weight:700;font-size:13.5px;
  white-space:nowrap}
.loading__retry[hidden]{display:none!important}
html.reduced-motion .loading-container,
html.reduced-motion .loading__progress-inner{transition:none;animation:none}

/* ------------------------------------------------------- intro editorial -- */
#entryIntro{position:fixed;inset:0;z-index:var(--z-intro);display:none;
  align-items:flex-end;justify-content:flex-start;padding:clamp(14px,3vw,40px)}
#entryIntro.on{display:flex}
/* Atenúa sin desenfocar: el mapa tiene que seguir leyéndose detrás. */
#entryIntro::before{content:'';position:absolute;inset:0;
  background:linear-gradient(105deg,rgba(21,21,21,.94) 0%,rgba(21,21,21,.78) 46%,rgba(21,21,21,.30) 100%);
  opacity:0;transition:opacity .4s ease}
#entryIntro.vis::before{opacity:1}
.icard{position:relative;width:min(520px,100%);padding:clamp(22px,3vw,34px);
  opacity:0;transform:translateY(14px);transition:opacity .4s ease,transform .4s cubic-bezier(.22,1,.36,1)}
#entryIntro.vis .icard{opacity:1;transform:none}
.ieyebrow{font-size:11px;letter-spacing:.13em;text-transform:uppercase;color:var(--primary);font-weight:600}
.icard h2{font-size:clamp(23px,3.1vw,31px);line-height:1.14;margin:10px 0 12px;max-width:15ch}
.isub{font-size:14px;line-height:1.55;color:var(--text-secondary);max-width:46ch}
.iacts{display:flex;gap:9px;margin-top:22px;flex-wrap:wrap}
.iacts .btn{flex:1 1 auto;min-width:158px}
.ilink{margin-top:13px;font-size:13px;color:var(--text-secondary);text-decoration:underline;
  text-underline-offset:3px;padding:4px 0;transition:color .15s}
.ilink:hover{color:var(--primary)}
.ifacts{list-style:none;margin:22px 0 0;padding:17px 0 0;border-top:1px solid var(--line-soft);
  display:grid;gap:7px}
.ifacts li{font-size:12.5px;color:var(--text-muted);line-height:1.5;padding-left:15px;position:relative}
.ifacts li::before{content:'';position:absolute;left:0;top:.55em;width:5px;height:1px;background:var(--brand-gray)}
.ionsite{margin-top:19px;padding-top:16px;border-top:1px solid var(--line-soft)}
.ionsite .btn{width:100%}
.inote{font-size:11.5px;color:var(--text-muted);margin-top:8px;line-height:1.45}
.iskip{position:absolute;top:14px;right:16px;font-size:12px;color:var(--text-muted);padding:4px 8px;border-radius:var(--rs)}
.iskip:hover{color:var(--text-primary);background:var(--surface)}
#introErr:empty{display:none}
#introErr{margin-top:12px;font-size:12.5px;color:var(--fn-risk);line-height:1.45}

/* ---------------------------------------------------------------- tour ---- */
.tour{position:fixed;inset:0;z-index:var(--z-tour);pointer-events:none;opacity:0;transition:opacity .25s ease}
.tour.is--on{opacity:1}
/* El spotlight atenúa el resto con un box-shadow gigante: la interfaz sigue
   visible, solo pierde protagonismo. */
.tour__spot{position:absolute;border-radius:var(--r);pointer-events:none;
  box-shadow:0 0 0 9999px rgba(21,21,21,.62),0 0 0 1px var(--primary-line) inset;
  transition:all .38s cubic-bezier(.22,1,.36,1)}
html.reduced-motion .tour__spot{transition:none}
.tour__pop{position:absolute;width:min(340px,calc(100vw - 24px));padding:16px 17px 14px;
  border-radius:var(--r);pointer-events:auto}
.tour__pop.is--center{left:50%!important;top:50%!important;transform:translate(-50%,-50%)}
.tour__bar{display:flex;justify-content:space-between;align-items:center;margin-bottom:9px}
.tour__step{font-size:11px;letter-spacing:.09em;text-transform:uppercase;color:var(--text-muted);font-weight:600}
.tour__x{width:24px;height:24px;border-radius:var(--rs);display:grid;place-items:center;color:var(--text-muted)}
.tour__x:hover{background:var(--surface);color:var(--text-primary)}
.tour__tag{display:inline-block;font-size:10.5px;letter-spacing:.05em;text-transform:uppercase;
  color:var(--fn-warn);border:1px solid rgba(217,150,63,.4);border-radius:var(--rs);
  padding:2px 7px;margin-bottom:8px;font-weight:600}
.tour__ttl{font-size:16px;line-height:1.24;margin-bottom:7px}
.tour__desc{font-size:13px;line-height:1.55;color:var(--text-secondary)}
.tour__acts{display:flex;gap:7px;margin-top:14px}
.tour__acts .btn{flex:1;padding:8px 10px;font-size:12.5px}
.tour__dots{display:flex;gap:4px;margin-top:12px;justify-content:center}
.tour__dots i{width:5px;height:5px;border-radius:999px;background:rgba(254,254,254,.2)}
.tour__dots i.past{background:rgba(254,254,254,.4)}
.tour__dots i.on{background:var(--primary);width:14px}
@media(max-width:900px){
  .tour__pop{left:8px!important;right:8px!important;top:auto!important;
    bottom:calc(var(--mbar-clear) + 10px);
    width:auto;transform:none!important}
  /* `is--center` es más específico y volvía a imponer `left:50%`: con el
     `transform` anulado el globo aparecía corrido media pantalla a la derecha.
     Acá se le repite el anclaje completo, no solo el transform. */
  .tour__pop.is--center{left:8px!important;right:8px!important;top:auto!important;transform:none!important}
}

/* ------------------------------------------------------- riel de mensajes - */
.msg-rail{position:fixed;left:50%;transform:translateX(-50%);bottom:16px;z-index:var(--z-msg);
  display:flex;flex-direction:column-reverse;gap:7px;width:min(430px,calc(100vw - 24px));
  pointer-events:none}
.msg{display:flex;align-items:flex-start;gap:10px;padding:10px 12px;border-radius:var(--rs);
  font-size:12.8px;line-height:1.45;pointer-events:auto;
  opacity:0;transform:translateY(8px);transition:opacity .2s ease,transform .2s ease}
.msg.is--in{opacity:1;transform:none}
.msg__t{flex:1}
.msg__a{font-size:12.5px;font-weight:600;color:var(--primary);white-space:nowrap;padding:1px 2px;
  border-radius:4px;text-decoration:underline;text-underline-offset:3px}
.msg__x{flex:none;width:20px;height:20px;display:grid;place-items:center;color:var(--text-muted);border-radius:4px}
.msg__x:hover{color:var(--text-primary);background:var(--surface)}
.msg--success{border-left:2px solid var(--fn-ok)}
.msg--warn{border-left:2px solid var(--fn-warn)}
.msg--error{border-left:2px solid var(--fn-risk)}
.msg--info{border-left:2px solid var(--brand-gray)}
@media(max-width:900px){ .msg-rail{bottom:calc(var(--mbar-clear) + 12px)} }

/* --------------------------------------------------------- vista lista ---- */
.lv{position:fixed;inset:0;z-index:var(--z-list);display:grid;place-items:center;
  padding:calc(16px + env(safe-area-inset-top,0px)) 16px calc(16px + env(safe-area-inset-bottom,0px));
  background:rgba(10,10,10,.62)}
.lv[hidden]{display:none}
.lv__card{width:min(680px,100%);
  max-height:min(86vh,760px);
  max-height:min(86dvh,760px);border-radius:var(--r);
  display:flex;flex-direction:column;overflow:hidden}
.lv__head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;
  padding:17px 18px 12px;border-bottom:1px solid var(--line-soft)}
.lv__head h2{font-size:16px}
.lv__head p{font-size:12.5px;color:var(--text-muted);margin-top:2px}
.lv__head .x{width:28px;height:28px;border-radius:var(--rs);display:grid;place-items:center;color:var(--text-muted)}
.lv__head .x:hover{background:var(--surface);color:var(--text-primary)}
.lv__hint{font-size:11.5px;color:var(--text-muted);padding:9px 18px 0}
.lv__body{list-style:none;overflow-y:auto;padding:10px 18px 18px;display:grid;gap:7px}
.lv-row{display:grid;grid-template-columns:1fr auto;gap:8px 14px;align-items:center;
  padding:11px 13px;border:1px solid var(--line-soft);border-radius:var(--rs);background:var(--surface)}
.lv-main{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.lv-nm{font-weight:600;font-size:13.5px}
.lv-pj{font-size:11.5px;color:var(--text-muted)}
/* El estado nunca se comunica solo por color: texto + borde + patrón. */
.lv-st{font-size:10.5px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  padding:2px 7px;border-radius:4px;border:1px solid}
.lv-st--disponible{color:var(--st-disponible-line);border-color:var(--st-disponible);background:var(--st-disponible-soft)}
/* El rayado se conserva: es el segundo canal —además del texto y del borde—
   que distingue "Reservado" sin pedirle nada al color. */
.lv-st--reservado{color:var(--st-reservado-line);border-color:var(--st-reservado);
  background:repeating-linear-gradient(45deg,rgba(141,146,152,.22) 0 3px,transparent 3px 6px)}
.lv-st--vendido{color:var(--st-vendido-line);border-color:var(--st-vendido);background:var(--st-vendido-soft)}
.lv-meta{grid-column:1;display:flex;gap:18px;margin:0}
.lv-meta dt{font-size:10.5px;color:var(--text-muted);text-transform:uppercase;letter-spacing:.05em}
.lv-meta dd{font-size:13px;font-weight:600;margin:0}
.lv-go{grid-row:1/3;grid-column:2;padding:8px 13px;font-size:12.5px}
.lv-empty{font-size:13px;color:var(--text-muted);line-height:1.55;padding:18px 0}

/* ------------------------------------------------ asistente de conexión --- */
.llsheet{position:fixed;inset:0;z-index:var(--z-llsheet);display:grid;place-items:end center;
  background:rgba(10,10,10,.72);padding:0}
.llsheet[hidden]{display:none}
.llsheet__card{width:min(520px,100%);border-radius:var(--r) var(--r) 0 0;padding:22px 20px calc(20px + env(safe-area-inset-bottom));
  max-height:88vh;
  max-height:88dvh;overflow-y:auto}
@media(min-width:700px){ .llsheet{place-items:center} .llsheet__card{border-radius:var(--r)} }
.llsheet__card h2{font-size:18px;line-height:1.2}
.llsheet__card > p{font-size:13px;color:var(--text-secondary);margin-top:7px;line-height:1.5}
.llsheet__opts{list-style:none;display:grid;gap:8px;margin:18px 0 14px}
.llsheet__opts button{width:100%;text-align:left;padding:13px 14px;border-radius:var(--rs);
  border:1px solid var(--line);background:var(--surface);transition:.14s;display:grid;gap:3px}
.llsheet__opts button:hover{background:var(--surface-hover);border-color:var(--primary-line)}
.llsheet__opts b{font-size:13.5px;font-weight:600}
.llsheet__opts span{font-size:12px;color:var(--text-muted);line-height:1.45}
.llsheet__rem{display:flex;align-items:center;gap:9px;font-size:12.5px;color:var(--text-secondary);cursor:pointer}
.llsheet__foot{font-size:11.5px;color:var(--text-muted);margin-top:12px}

/* ------------------------------------------------------------ ficha ------- */
.specs{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--line-soft);
  border:1px solid var(--line-soft);border-radius:var(--rs);overflow:hidden;margin-top:13px}
.specs > div{background:var(--panel);padding:10px 12px}
.specs dt{font-size:10.5px;color:var(--text-muted);text-transform:uppercase;letter-spacing:.05em}
.specs dd{font-size:14px;font-weight:600;margin:0;margin-top:3px}
.h4sub{text-transform:none;letter-spacing:0;color:var(--text-muted);font-weight:400;font-size:11.5px}
.simu__row{display:flex;gap:10px;margin-bottom:11px}
.simu__f{flex:1}
.simu__f--cuo{width:96px;flex:none}
.simu__f .k{display:block;font-size:10.5px;color:var(--text-muted);text-transform:uppercase;
  letter-spacing:.05em;margin-bottom:5px}
.simu__f input[type=range]{width:100%;accent-color:var(--primary)}
.cta{display:grid;gap:8px;margin-top:15px}
.wa2{border-color:rgba(254,254,254,.16)}
.more{border-top:1px solid var(--line-soft);padding-top:10px;margin-top:2px}
.more summary{font-size:12.5px;color:var(--text-secondary);cursor:pointer;list-style:none;
  padding:5px 0;display:flex;align-items:center;gap:6px}
.more summary::-webkit-details-marker{display:none}
.more summary::after{content:'';width:6px;height:6px;border-right:1.6px solid currentColor;
  border-bottom:1.6px solid currentColor;transform:rotate(45deg) translateY(-2px);transition:transform .18s}
.more[open] summary::after{transform:rotate(-135deg) translateY(-2px)}
.more__in{display:grid;gap:7px;padding-top:8px}
.more__in .btn{font-size:12.5px;padding:9px}
/* Fila compacta de métricas DENTRO DE LA FICHA: tres indicadores en línea.
   Iba sin acotar y pisaba la grilla de `.kpis` definida más arriba, así que en
   Analítica los cuatro indicadores se convertían en una fila de la que solo
   entraban tres. Cada panel declara su propia disposición. */
#dbody .kpis{display:flex;gap:9px}
#dbody .kpis .kpi{flex:1}
.sect--soft{opacity:.78}
.simchip{display:inline-block;font-size:10px;letter-spacing:.05em;text-transform:uppercase;
  color:var(--fn-warn);border:1px solid rgba(217,150,63,.35);border-radius:4px;padding:1px 6px;
  margin-left:7px;font-weight:600;vertical-align:middle}
.internal--gps{background:var(--primary-soft);border-color:var(--primary-line)}
.internal--gps .t{color:var(--primary)}
.wait__ok{color:var(--fn-ok);margin-top:9px;font-size:12px}

/* ------------------------------------------------------ rótulo demo ------- */
.demotag{margin-left:10px;font-size:10.5px;letter-spacing:.05em;text-transform:uppercase;
  color:var(--text-muted);border:1px solid var(--line);border-radius:4px;padding:2px 7px;
  font-weight:600;white-space:nowrap;align-self:center}

/* -------------------------------------------------------- barra mobile ---- */
.mbar{display:none}
@media(max-width:900px){
  /* La barra baja de 60 a 45: queda arriba de los paneles y las hojas, pero
     abajo de los modales `.ov` (60). Es lo que ya pasaba de hecho —el `.ov`
     ganaba por orden en el DOM—, ahora dicho en voz alta. */
  .mbar{position:fixed;left:0;right:0;bottom:0;z-index:var(--z-nav);display:grid;
    grid-template-columns:repeat(5,1fr);gap:2px;padding:6px 6px calc(6px + env(safe-area-inset-bottom));
    background:rgba(21,21,21,.95);backdrop-filter:blur(10px);border-top:1px solid var(--line)}
  .mbar__b{min-height:44px;display:flex;flex-direction:column;align-items:center;justify-content:center;
    gap:2px;font-size:10px;color:var(--text-secondary);border-radius:var(--rs);padding:4px 2px}
  .mbar__b[aria-expanded=true],.mbar__b:active{background:var(--surface);color:var(--primary)}
  header .proj,header .search,header .modes,header #simgps{display:none}
  #legend{bottom:calc(var(--mbar-clear) + 12px)}
  /* Los filtros pasan a hoja inferior: nada se pierde en mobile.
     OJO: acá NO puede volver un `display:none`. El bloque de 900 lo tenía y
     este otro nunca redeclaraba `display`, así que el panel medía 0×0 y el
     botón "Filtrar" no hacía nada visible. Se oculta por estado —fuera de
     pantalla y sin eventos—, nunca por `display`. */
  /* La hoja ocupaba tres cuartos de la pantalla y no se veía cómo cambiaba el
     mapa al filtrar, que es justamente el sentido de filtrar acá. Se queda con
     poco más de la mitad y deja el resto de mapa a la vista. */
  #filters{position:fixed;left:0;right:0;bottom:0;top:auto;width:auto;
    max-height:54vh;
    max-height:54dvh;
    border-radius:var(--r) var(--r) 0 0;transform:translateY(102%);opacity:1;pointer-events:none;
    transition:transform .3s cubic-bezier(.22,1,.36,1)}
  #filters.sheet-open{transform:none;pointer-events:auto}
  /* El pie con el contador y "Limpiar" no puede quedar abajo de la barra. */
  .ffoot{padding-bottom:calc(11px + var(--mbar-clear));flex:none}
  /* En una columna flex el `min-height:auto` impide que el cuerpo se achique
     por debajo de su contenido: crecía entero, empujaba al pie fuera de la
     hoja y el `overflow:hidden` del panel lo recortaba. Resultado medido: los
     últimos filtros terminaban 53 px por debajo del borde de la barra y el pie
     no se veía nunca. */
  #filters .fbody{flex:1 1 auto;min-height:0}
  .mbar__b svg{width:19px;height:19px}
  /* Área táctil mínima en todos los cierres */
  .x,.hbtn,.msg__x,.tour__x{min-width:44px;min-height:44px}
}

/* -------------------------------------------------- reducción de movimiento */
html.reduced-motion #entryIntro .icard,html.reduced-motion .msg{transition:none}
html.reduced-motion .loading-container{transition:none}

/* Con un diálogo abierto el fondo no debe scrollear detrás. */
html.has-dialog body{overflow:hidden}

/* La base ocultaba los checkbox con display:none, lo que los saca del orden de
   tabulación y del árbol de accesibilidad. Se revierte a ocultamiento visual. */
.chk input[type=checkbox],.tgl input[type=checkbox]{
  display:block!important;appearance:none;-webkit-appearance:none;
  position:absolute;width:1px;height:1px;opacity:0;margin:0;pointer-events:none;
}
/* Índices del simulador: la etiqueta visible es el mes de la fila. */
.idxr input{width:72px}

/* Botón de simulación dentro de la intro: acción terciaria, claramente
   marcada como demostración. */
#entryIntro .demo-btn{margin-top:9px;width:100%;padding:8px;font-size:12px;
  color:var(--fn-warn);border:1px dashed rgba(217,150,63,.4);border-radius:var(--rs);
  background:transparent;transition:.14s}
#entryIntro .demo-btn:hover{background:rgba(217,150,63,.08)}

/* El rótulo de demostración tiene que informar, no gritar. */
.demotag{border:0;background:transparent;color:var(--text-muted);
  font-size:10px;letter-spacing:.08em;padding:0;margin-left:12px;
  padding-left:12px;border-left:1px solid var(--line)}
/* El chip "datos simulados" no debe empujar el título a dos renglones. */
.sect h4{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap}
.simchip{margin-left:0;flex:none}

/* =============================================================================
   ASESORAMIENTO PERSONALIZADO · VISITA AUTOGUIADA · ORIENTACIÓN
   Se apoya en el sistema visual existente: mismos tokens, mismos radios y el
   naranja reservado para acción primaria, selección y foco.
   ========================================================================== */

/* --- panel del cuestionario ---------------------------------------------- */
.adv{position:fixed;inset:0;z-index:var(--z-adv);display:flex;align-items:center;justify-content:center;
  padding:calc(20px + env(safe-area-inset-top,0px)) 20px calc(20px + env(safe-area-inset-bottom,0px));
  background:rgba(0,0,0,.52);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px)}
.adv__card{width:100%;max-width:520px;
  max-height:88vh;
  max-height:88dvh;display:flex;flex-direction:column;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--sh);
  backdrop-filter:blur(22px) saturate(1.5);-webkit-backdrop-filter:blur(22px) saturate(1.5)}
.adv__head{position:relative;padding:16px 46px 10px 18px;flex:none}
.adv__prog{height:3px;border-radius:2px;background:var(--line-soft);overflow:hidden;margin-bottom:10px}
.adv__bar{display:block;height:100%;width:0;background:var(--primary);transition:width .32s ease}
.adv__step{font-size:11px;letter-spacing:.05em;text-transform:uppercase;color:var(--text-muted)}
.adv__x{position:absolute;top:14px;right:14px;width:28px;height:28px;border-radius:var(--rs);
  color:var(--text-muted);display:flex;align-items:center;justify-content:center;transition:.14s}
.adv__x:hover{background:var(--surface-hover);color:var(--text-primary)}
.adv__body{padding:4px 18px 16px;overflow-y:auto;flex:1 1 auto}
.adv__ttl{font-size:19px;font-weight:600;letter-spacing:-.4px;line-height:1.3;margin-bottom:6px}
.adv__help{font-size:12.5px;color:var(--text-secondary);line-height:1.5;margin-bottom:14px}
.adv__ops{display:flex;flex-direction:column;gap:8px}
.adv__ops--entrada{margin-top:14px}
.adv__op{display:flex;align-items:center;gap:11px;width:100%;text-align:left;
  padding:13px 14px;min-height:48px;border-radius:var(--rs);border:1px solid var(--line);
  background:var(--surface);font-size:14px;line-height:1.35;transition:.14s}
.adv__op:hover{background:var(--surface-hover);border-color:rgba(254,254,254,.22)}
.adv__op.is--on{background:var(--primary-soft);border-color:var(--primary-line);color:var(--text-primary)}
.adv__opmark{flex:none;width:17px;height:17px;border-radius:50%;border:1.5px solid var(--line);
  position:relative;transition:.14s}
.adv__op.is--on .adv__opmark{border-color:var(--primary);background:var(--primary)}
/* La selección no depende solo del color: además aparece la marca de tilde. */
.adv__op.is--on .adv__opmark::after{content:"";position:absolute;left:5px;top:2px;width:5px;height:9px;
  border:solid var(--brand-dark);border-width:0 2px 2px 0;transform:rotate(45deg)}
.adv__foot{display:flex;gap:8px;padding:12px 18px;border-top:1px solid var(--line-soft);flex:none;flex-wrap:wrap}
.adv__foot .btn{flex:1 1 auto;min-height:44px}
.adv__foot .btn.pri{flex:2 1 auto}
.adv__geo{margin-top:16px;padding:14px;border-radius:var(--rs);border:1px solid var(--primary-line);
  background:var(--primary-soft)}
.adv__geo p{font-size:13px;line-height:1.5}
.adv__geoacts{display:flex;gap:8px;margin-top:11px;flex-wrap:wrap}
.adv__geoacts .btn{flex:1 1 auto;min-height:44px}
.adv__geonote{font-size:11.5px;color:var(--text-muted);margin-top:9px}

/* --- tarjetas de recomendación ------------------------------------------- */
.adv__rec{padding:14px;border-radius:var(--rs);border:1px solid var(--line-soft);
  background:var(--surface);margin-bottom:10px}
.adv__rec--main{border-color:var(--primary-line);background:var(--primary-soft)}
.adv__rectag{font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--primary);margin-bottom:5px}
.adv__rec h3{font-size:16px;font-weight:600;letter-spacing:-.3px}
.adv__recsub{font-size:12px;color:var(--text-secondary);margin-top:2px}
.adv__recprice{font-size:17px;font-weight:700;letter-spacing:-.5px;margin-top:7px}
.adv__recmeta{font-size:12px;color:var(--text-muted);margin-top:5px}
.adv__why{list-style:none;margin:11px 0 0;padding:0;display:flex;flex-direction:column;gap:5px}
.adv__why li{position:relative;padding-left:17px;font-size:12.5px;color:var(--text-secondary);line-height:1.45}
.adv__why li::before{content:"";position:absolute;left:2px;top:6px;width:6px;height:6px;
  border-radius:50%;background:var(--primary)}
.adv__recacts{display:flex;gap:7px;margin-top:12px;flex-wrap:wrap}
.adv__recacts .btn{flex:1 1 auto;min-height:44px;font-size:12.5px}
.adv__altttl{font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--text-muted);
  margin:16px 0 8px}

/* --- recorrido autoguiado ------------------------------------------------ */
.vpanel{position:fixed;right:18px;bottom:18px;z-index:var(--z-vpanel);width:330px;max-width:calc(100vw - 36px);
  padding:15px;border-radius:var(--r)}
.vpanel__head{display:flex;align-items:center;justify-content:space-between;gap:10px}
.vpanel__step{font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--primary)}
.vpanel__x{width:26px;height:26px;border-radius:var(--rs);color:var(--text-muted);
  display:flex;align-items:center;justify-content:center}
.vpanel__x:hover{background:var(--surface-hover);color:var(--text-primary)}
.vpanel__ttl{font-size:16px;font-weight:600;letter-spacing:-.3px;margin-top:6px}
.vpanel__price{font-size:16px;font-weight:700;letter-spacing:-.4px;margin-top:4px}
.vpanel__meta{font-size:12px;color:var(--text-muted);margin-top:4px}
.vpanel__dist{font-size:12px;color:var(--primary);margin-top:4px}
.vpanel__why{list-style:none;margin:9px 0 0;padding:0;display:flex;flex-direction:column;gap:4px}
.vpanel__why li{position:relative;padding-left:15px;font-size:12px;color:var(--text-secondary);line-height:1.4}
.vpanel__why li::before{content:"";position:absolute;left:2px;top:6px;width:5px;height:5px;
  border-radius:50%;background:var(--primary)}
.vpanel__acts{display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-top:12px}
.vpanel__acts .btn{min-height:44px;font-size:12px;padding:8px 10px}
.vpanel__acts .btn.pri{grid-column:1/-1}
.vres__list{display:flex;flex-direction:column;gap:8px}
.vres__it{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:11px 12px;border-radius:var(--rs);border:1px solid var(--line-soft);background:var(--surface)}
.vres__it b{display:block;font-size:13.5px}
.vres__it span{display:block;font-size:11.5px;color:var(--text-muted);margin-top:2px}

/* --- orientación dentro del mapa ----------------------------------------- */
.ori{position:fixed;left:50%;transform:translateX(-50%);bottom:20px;z-index:66;
  width:min(380px,calc(100vw - 32px));padding:13px 15px;border-radius:var(--r)}
.ori__row{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
.ori__k{font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--text-muted)}
.ori__v{font-size:15px;font-weight:600;letter-spacing:-.3px;margin-top:2px}
.ori__x{width:26px;height:26px;flex:none;border-radius:var(--rs);color:var(--text-muted);
  display:flex;align-items:center;justify-content:center}
.ori__x:hover{background:var(--surface-hover);color:var(--text-primary)}
.ori__d{font-size:13px;color:var(--primary);margin-top:6px;font-weight:600}
.ori__note{font-size:11px;color:var(--text-muted);margin-top:7px;line-height:1.4;
  padding-top:7px;border-top:1px solid var(--line-soft)}

/* --- interés por el lote (en público: solamente vistas) ------------------- */
.interes{font-size:13px;color:var(--text-secondary);margin-top:4px}
.interes b{font-size:22px;font-weight:700;letter-spacing:-.6px;color:var(--text-primary);
  margin-right:5px;vertical-align:-1px}

/* --- panel comercial: campos que aporta el sistema de gestión ------------- */
.vseg{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;margin-top:9px;
  background:var(--line-soft);border-radius:var(--rs);overflow:hidden}
.vseg > div{background:var(--solid);padding:7px 9px}
.vseg dt{font-size:9.5px;letter-spacing:.05em;text-transform:uppercase;color:var(--text-muted)}
.vseg dd{margin:2px 0 0}
.vpend{font-size:11px;color:var(--text-muted);font-style:italic}
.vfoot{font-size:11.5px;color:var(--text-muted);margin-top:12px;padding-top:10px;
  border-top:1px solid var(--line-soft);line-height:1.45}

/* --- CRM explicado en una frase ------------------------------------------ */
.apisimple{font-size:15px;line-height:1.55;color:var(--text-primary)}
.apinote{font-size:12px;color:var(--text-muted);margin-top:12px;padding-top:11px;
  border-top:1px solid var(--line-soft)}

/* --- proyección de cuotas ------------------------------------------------- */
.simdisc{font-size:11.5px;color:var(--text-muted);line-height:1.45;margin-top:14px;
  padding-top:11px;border-top:1px solid var(--line-soft)}

/* --- cierre institucional MP360 ------------------------------------------ */
.mp__marca{margin-bottom:14px}
.mp__marca img{max-height:38px;width:auto}
.mp__marca--txt{font-size:22px;font-weight:700;letter-spacing:-.6px;color:var(--primary)}
.mp__txt{font-size:14.5px;line-height:1.6;color:var(--text-secondary)}
.mp__txt2{font-size:13px;line-height:1.55;color:var(--text-muted);margin-top:10px}
.mp__logos{display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:10px;margin-top:18px}
.mp__logo{display:flex;align-items:center;justify-content:center;padding:12px;
  border-radius:var(--rs);border:1px solid var(--line-soft);background:var(--surface)}
.mp__logo img{max-width:100%;max-height:34px;width:auto;opacity:.85}
.mp__ph{display:flex;align-items:center;justify-content:center;min-height:56px;padding:10px;
  border-radius:var(--rs);border:1px dashed var(--line);background:transparent}
.mp__ph span{font-size:10.5px;letter-spacing:.05em;text-transform:uppercase;color:var(--text-muted)}
.mp__pendnote{font-size:11.5px;color:var(--text-muted);margin-top:11px;line-height:1.45}
.mp__pendnote code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px}

/* --- mobile: hoja inferior estable; el mapa nunca queda tapado del todo --- */
@media (max-width:900px){
  .adv{align-items:flex-end;padding:0}
  .adv__card{max-width:none;
    max-height:82vh;
    max-height:82dvh;border-radius:var(--r) var(--r) 0 0;border-bottom:0}
  .adv__foot{padding-bottom:calc(12px + env(safe-area-inset-bottom))}
  /* El recorrido y la orientación los pinta `visit.js` al mismo tiempo y
     compartían este mismo borde inferior: uno tapaba al otro. Se escalonan. */
  .vpanel{left:8px;right:8px;bottom:calc(var(--mbar-clear) + 8px);width:auto;
    max-height:52vh;
    max-height:52dvh;overflow-y:auto}
  .ori{bottom:calc(var(--mbar-clear) + 8px);width:calc(100vw - 16px)}
  /* Con la orientación en pantalla el recorrido se va arriba, pegado al
     header: es la única forma de que las dos se lean sin arrastre ni JS. */
  body:has(#oriBox) .vpanel{top:calc(var(--header-clear) + 8px);bottom:auto;
    max-height:42vh;
    max-height:42dvh}
  .vseg{grid-template-columns:1fr}
}

@media (prefers-reduced-motion: reduce){
  .adv__bar{transition:none}
}


/* --- resultados del buscador --------------------------------------------- */
header .search{position:relative}
/* El desplegable no tiene por qué medir lo mismo que el input: si hereda esos
   190px, el nombre de la unidad se corta en "Manzana 1 · L…". */
.qres{position:absolute;top:calc(100% + 6px);left:0;right:auto;
  width:max(100%,360px);max-width:min(420px,calc(100vw - 24px));z-index:80;
  max-height:min(58vh,420px);
  max-height:min(58dvh,420px);overflow-y:auto;padding:6px;border-radius:var(--rs);
  display:flex;flex-direction:column;gap:2px}
.qres__head{font-size:10.5px;letter-spacing:.05em;text-transform:uppercase;
  color:var(--primary);padding:7px 10px 5px;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.qres__aviso{font-size:11.5px;color:var(--text-muted);line-height:1.45;
  padding:8px 10px;border-top:1px solid var(--line-soft);margin-top:4px}
/* flex:none es lo que evita que las filas se aplasten y se superpongan dentro
   del contenedor con scroll. Sin esto, 12 resultados se comprimen y el texto de
   uno se monta sobre el siguiente. */
.qres__it{flex:none;display:block;width:100%;text-align:left;padding:10px 11px;
  border-radius:var(--rs);background:transparent;border:1px solid transparent;transition:.12s}
.qres__head,.qres__aviso,.qres__sugs,.qres__nores{flex:none}
.qres__it:hover,.qres__it.is--on{background:var(--surface-hover);border-color:var(--line)}
.qres__it.is--on{border-color:var(--primary-line)}
.qres__nm{font-size:13.5px;font-weight:600;letter-spacing:-.2px;line-height:1.25;
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.qres__meta{display:block;font-size:11.5px;color:var(--text-muted);margin-top:3px;
  line-height:1.35;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.qres__why{display:block;font-size:11.5px;color:var(--primary);margin-top:3px;
  line-height:1.35;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.qres__nores{padding:11px 10px 4px}
.qres__nores b{display:block;font-size:13.5px;font-weight:600;color:var(--text-primary)}
.qres__nores span{display:block;font-size:12px;color:var(--text-secondary);margin-top:4px;line-height:1.45}

@media (max-width:900px){
  .qres{max-height:52vh;
    max-height:52dvh;left:0;right:0;width:auto;max-width:none}
}

/* Cabecera del recorrido: minimizar y finalizar conviven sin apretarse. */
.vpanel__hacts{display:flex;gap:4px;flex:none}

/* --- buscador: sugerencias y alternativas -------------------------------- */
.qres__top{display:flex;align-items:center;justify-content:space-between;gap:9px;min-width:0}
.qres__st{flex:none;font-size:9.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  padding:2px 7px;border-radius:999px;border:1px solid var(--line);color:var(--text-muted);
  background:var(--surface)}
.qres__st--disponible{color:var(--st-disponible-line);border-color:var(--st-disponible);background:var(--st-disponible-soft)}
.qres__st--reservado{color:var(--st-reservado-line);border-color:var(--st-reservado);background:var(--st-reservado-soft)}
.qres__st--vendido{color:var(--st-vendido-line);border-color:var(--st-vendido);background:var(--st-vendido-soft)}
.qres__sugs{display:flex;flex-wrap:wrap;gap:6px;padding:2px 9px 9px}
.qres__sug{padding:6px 11px;min-height:34px;border-radius:999px;border:1px solid var(--line);
  background:var(--surface);color:var(--text-primary);font-size:12.5px;transition:.12s}
.qres__sug:hover{background:var(--primary-soft);border-color:var(--primary-line);color:var(--primary)}

/* --- sliders nativos: pista sobria y pulgar de marca --------------------- */
.simu input[type=range],#ant{-webkit-appearance:none;appearance:none;width:100%;
  height:4px;border-radius:999px;background:var(--line);outline:none}
.simu input[type=range]::-webkit-slider-thumb,#ant::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;width:16px;height:16px;border-radius:50%;
  background:var(--primary);border:2px solid var(--solid);box-shadow:var(--sh-soft);cursor:pointer}
.simu input[type=range]::-moz-range-thumb,#ant::-moz-range-thumb{
  width:16px;height:16px;border-radius:50%;background:var(--primary);
  border:2px solid var(--solid);box-shadow:var(--sh-soft);cursor:pointer}
.simu input[type=range]::-moz-range-track,#ant::-moz-range-track{
  height:4px;border-radius:999px;background:var(--line)}

/* --- ritmo tipográfico: la jerarquía la dan tamaño y peso ---------------- */
.icard h2{font-size:var(--fs-display);letter-spacing:-.028em}
.ieyebrow{font-size:var(--fs-xs);letter-spacing:var(--ls-over)}
.isub{font-size:15px;line-height:1.6}
#dttl{font-size:22px;letter-spacing:-.026em}
.mhead h3,.adv__ttl{font-size:var(--fs-h2);letter-spacing:-.022em}
.tour__ttl{font-size:var(--fs-h2);letter-spacing:-.022em}
.dhead .pj,.flab,.specs dt,.specs .k,.kpi .k,.vseg dt,.qres__head,.adv__rectag,
.vpanel__step,.ori__k,.lv-st,.simchip{
  font-size:var(--fs-xs);letter-spacing:var(--ls-over);text-transform:uppercase;
}
.dbody{padding:18px 20px 22px}
.mbody{padding:20px}
@media (max-width:900px){
  .icard h2{font-size:25px}
  #dttl{font-size:20px}
}

/* --- encabezado sin bloque de marca --------------------------------------- */
/* El selector de proyectos pasa a ser el primer elemento: sin el borde derecho
   de .brand ni el hueco que dejaba. */
.brand{display:none}
header > .proj:first-child{margin-left:2px}
.demotag{margin-left:0;padding-left:0;border-left:0;margin-right:4px}

/* --- banner de entrada: centrado y con ancho útil ------------------------- */
/* Antes se anclaba abajo a la izquierda. Ahora ocupa el centro del viewport y
   el título dispone del ancho completo de la tarjeta. */
#entryIntro{align-items:center;justify-content:center}
#entryIntro::before{
  background:radial-gradient(120% 100% at 50% 50%,
    rgba(21,21,21,.70) 0%, rgba(21,21,21,.88) 55%, rgba(21,21,21,.94) 100%);
}
.icard{width:min(760px,100%)}
/* Sin `max-width` en el título: el corte lo decide el ancho de la tarjeta.
   `balance` reparte las dos líneas en lugar de dejar una huérfana. */
/* Especificidad de ID: hay un bloque `#entryIntro h2` heredado que si no gana. */
#entryIntro .icard h2{max-width:none;font-size:clamp(26px,3.2vw,42px);text-wrap:balance;line-height:1.1}
.isub{max-width:58ch}
.iacts{gap:14px;align-items:center;margin-top:26px}
@media (max-width:900px){
  /* Baja de clamp(23px,6.2vw,28px): en 390 pasa de 24,2 a 21,8 px y el título
     se resuelve en dos renglones en vez de dos y medio. El piso de 21 px es lo
     que se lee cómodo en 320, donde puede ocupar hasta tres. */
  #entryIntro .icard h2{font-size:clamp(21px,5.6vw,26px);text-wrap:pretty}
  .isub{max-width:none}
}

/* ===================== sistema de botones (Osmo) ========================== */
/* Principal: "Button with Bubble Arrow". Secundario: "Button 004".
   Se adaptan color, radio exterior, tamaño, semántica, foco y touch.
   Estructura, recorridos, timing y easing son los del componente original. */

/* --- principal: bubble arrow --------------------------------------------- */
.btn-bubble-arrow{
  --bba-size:3.1em;            /* diámetro de la burbuja = alto del botón */
  --bba-radius:8px;
  --bba-ease:cubic-bezier(.625,.05,0,1);
  font-size:var(--fs-ui);font-weight:var(--fw-bold);letter-spacing:-.01em;
  color:var(--brand-dark);
  border-radius:var(--bba-radius);
  justify-content:center;align-items:center;
  text-decoration:none;display:flex;position:relative;
  padding:0;border:none;background:none;
  -webkit-user-select:none;user-select:none;
  -webkit-tap-highlight-color:transparent;
}
.btn-bubble-arrow__arrow{
  color:var(--brand-dark);background-color:var(--brand-white);
  border-radius:999px;
  flex-flow:row;justify-content:center;align-items:center;
  width:var(--bba-size);height:var(--bba-size);
  display:flex;position:relative;
  transition:transform .735s var(--bba-ease);
  transform:scale(0) rotate(.001deg);
  transform-origin:left;
}
.btn-bubble-arrow__arrow-svg{
  width:40%;transition:transform .735s var(--bba-ease);transform:rotate(.001deg);
}
.btn-bubble-arrow__arrow.is--duplicate{
  position:absolute;z-index:2;right:0;
  transform:scale(1) rotate(.001deg);transform-origin:right;
}
.btn-bubble-arrow__content{
  color:var(--brand-dark);background-color:var(--primary);
  border-radius:var(--bba-radius);
  justify-content:center;align-items:center;
  height:var(--bba-size);padding-left:1.65em;padding-right:1.65em;
  display:flex;position:relative;
  transition:transform .735s var(--bba-ease);
  transform:translateX(calc(var(--bba-size) * -1)) rotate(.001deg);
}
.btn-bubble-arrow__content-text{line-height:1;white-space:nowrap}
/* Anillo de foco propio: el radio acompaña al del contenedor. */
.btn-bubble-arrow:focus-visible{outline:none}
.btn-bubble-arrow::after{
  content:'';position:absolute;inset:-.25em;pointer-events:none;z-index:3;
  border-radius:calc(var(--bba-radius) + .25em);
  transition:box-shadow .3s cubic-bezier(.32,.72,0,1);
}
.btn-bubble-arrow:focus-visible::after{box-shadow:0 0 0 2px var(--brand-white)}
.btn-bubble-arrow:disabled{opacity:.45;cursor:not-allowed;pointer-events:none}
/* Teclado: el movimiento también se dispara con foco, en cualquier puntero. */
.btn-bubble-arrow:focus-visible .btn-bubble-arrow__content{transform:translateX(0) rotate(.001deg)}
.btn-bubble-arrow:focus-visible .btn-bubble-arrow__arrow-svg{transform:rotate(-45deg)}
.btn-bubble-arrow:focus-visible .btn-bubble-arrow__arrow{transform:scale(1) rotate(.001deg)}
.btn-bubble-arrow:focus-visible .btn-bubble-arrow__arrow.is--duplicate{transform:scale(0) rotate(.001deg)}
/* Hover solo donde existe: en táctil el estado de reposo ya es legible. */
@media (hover:hover) and (pointer:fine){
  .btn-bubble-arrow:hover .btn-bubble-arrow__content{transform:translateX(0) rotate(.001deg)}
  .btn-bubble-arrow:hover .btn-bubble-arrow__arrow-svg{transform:rotate(-45deg)}
  .btn-bubble-arrow:hover .btn-bubble-arrow__arrow{transform:scale(1) rotate(.001deg)}
  .btn-bubble-arrow:hover .btn-bubble-arrow__arrow.is--duplicate{transform:scale(0) rotate(.001deg)}
}
/* Sin movimiento: el botón se queda en reposo en lugar de saltar. */
@media (prefers-reduced-motion:reduce){
  .btn-bubble-arrow :is(.btn-bubble-arrow__content,.btn-bubble-arrow__arrow,.btn-bubble-arrow__arrow-svg){
    transition:none!important;
  }
  .btn-bubble-arrow:is(:hover,:focus-visible) .btn-bubble-arrow__content{transform:translateX(calc(var(--bba-size) * -1)) rotate(.001deg)}
  .btn-bubble-arrow:is(:hover,:focus-visible) .btn-bubble-arrow__arrow{transform:scale(0) rotate(.001deg)}
  .btn-bubble-arrow:is(:hover,:focus-visible) .btn-bubble-arrow__arrow.is--duplicate{transform:scale(1) rotate(.001deg)}
  .btn-bubble-arrow:is(:hover,:focus-visible) .btn-bubble-arrow__arrow-svg{transform:rotate(.001deg)}
}
html.reduced-motion .btn-bubble-arrow :is(.btn-bubble-arrow__content,.btn-bubble-arrow__arrow,.btn-bubble-arrow__arrow-svg){transition:none}

/* --- secundario: button 004 ----------------------------------------------
   Dos modos:
   · completo  (`.button-004`)               reemplaza el chrome del botón:
     fondo, borde y radio propios del componente. Lo usan los secundarios
     reales (`.btn.gh`, `.btn.wa`).
   · integrado (`.button-004--inline`)       aporta solo el reemplazo de texto
     y respeta el fondo, el padding y el radio que el botón ya tenía. Lo usan
     los primarios de panel, las pestañas de modo/proyecto y los terciarios,
     que no deben cambiar de forma.
   El armado del marcado lo hace `assets/js/buttons.js`.                     */
.button-004{
  --button-004-color:var(--text-primary);
  --button-004-color-background:var(--primary-soft);
  --button-004-color-border:var(--primary-line);
  --button-004-color-focus:var(--brand-white);
  --button-004-border-radius:8px;
  --button-004-padding:1.05em 1.25em;
  --button-004-translate-y:1.25em;
  --button-004-focus-inset:-.25em;
  --button-004-click-scale:.955 .925;
  --button-004-ease-hover:cubic-bezier(.675,.15,.1,1);
  --button-004-ease-click:cubic-bezier(.4,0,.2,1);
  --button-004-ease-focus:cubic-bezier(.32,.72,0,1);
  -webkit-user-select:none;user-select:none;
  -webkit-tap-highlight-color:transparent;
  /* Ojo: `position` no se toca acá. En modo integrado el botón puede venir
     posicionado por su propia regla (`.iskip` es absolute) y pisarlo lo
     saca de lugar. Solo el modo completo lo necesita, para su anillo. */
}
/* --- modo completo: el componente pone el chrome ------------------------- */
/* Los `!important` neutralizan reglas heredadas más específicas del tipo
   `#exploreGuide .acts .btn{padding:9px}`, que si no duplicarían el relleno. */
/* No se fija `font-size`: cada botón conserva el suyo (`.btn` 13.5px, el
   recorrido 12.5px…) y el relleno, que está en `em`, acompaña solo. */
.button-004:not(.button-004--inline){
  color:var(--button-004-color);
  line-height:1;text-decoration:none;position:relative;
  display:inline-grid!important;
  padding:0!important;background:none!important;border:none!important;
  min-height:0!important;box-shadow:none!important;
  outline-style:none;
  transition:scale .15s var(--button-004-ease-click);
}
.button-004:not(.button-004--inline)::after{
  content:'';display:block;position:absolute;
  inset:var(--button-004-focus-inset);
  border-radius:calc(var(--button-004-border-radius) + .25em);
  transition:box-shadow .3s var(--button-004-ease-focus);
  pointer-events:none;z-index:1;
}
.button-004:not(.button-004--inline):is(:focus-visible)::after{
  box-shadow:0 0 0 2px var(--button-004-color-focus);
}
.button-004:not(.button-004--inline):active{scale:var(--button-004-click-scale)}
.button-004:disabled{opacity:.45;cursor:not-allowed;pointer-events:none}
.button-004__inner{
  pointer-events:none;border-radius:var(--button-004-border-radius);
  z-index:1;padding:var(--button-004-padding);
  grid-area:1/1;display:grid;grid-auto-flow:column;
  align-items:center;justify-content:center;gap:.55em;
}
/* La pila mantiene las dos copias del texto exactamente superpuestas. */
.button-004__stack{display:grid;pointer-events:none}
.button-004__text{perspective:10em;transform-style:preserve-3d;grid-area:1/1}
/* Si el split no corrió (JS bloqueado o sin cargar), la copia de hover no tiene
   caracteres que la mantengan invisible y quedaría encimada sobre la otra.
   `data-split-done` lo pone el JS: sin él, esa copia no se dibuja. */
.button-004__text.is--hover:not([data-split-done]){visibility:hidden}
/* El corte de línea solo puede caer en un espacio real, nunca entre letras. */
.button-004__word{white-space:nowrap}
.button-004__text .button-004__split-char{
  --base-delay:.05s;
  --max-extra:2.9s;
  --t:calc(var(--index) / max(var(--max-index), 1));
  --curve:sin(calc(var(--t) * 1.5deg));
  --delay:calc(var(--base-delay) + (var(--curve) * var(--max-extra)));
  --rot-t:calc(var(--index) / max(var(--max-index), 1));
  --rot-curve:sin(calc(var(--rot-t) * 30deg));
  --rot-sign:clamp(-1, var(--signed-index), 1);
  --rot-max:36deg;
  display:inline-block;
}
.button-004__text.is--default .button-004__split-char{
  transition:transform .325s var(--button-004-ease-hover),translate .425s var(--button-004-ease-hover),rotate .45s var(--button-004-ease-hover),opacity .15s ease-out;
}
.button-004__text.is--hover .button-004__split-char{
  transition:transform .35s var(--button-004-ease-hover),translate .35s var(--button-004-ease-hover),rotate .35s var(--button-004-ease-hover),opacity .15s .1s ease-out;
  rotate:1 0 0 -72deg;
  transform:rotateZ(calc(var(--rot-sign) * var(--rot-curve) * var(--rot-max) * -1)) scale(.65);
  translate:calc(var(--signed-index) * .125em) calc(var(--button-004-translate-y) * 1) 0;
  opacity:0;
}
.button-004__bg{
  background-color:var(--button-004-color-background);
  border:1px solid var(--button-004-color-border);
  border-radius:var(--button-004-border-radius);
  grid-area:1/1;width:100%;height:100%;padding:0;
}
@media (hover:hover) and (pointer:fine) and (prefers-reduced-motion:no-preference){
  /* El original marca `will-change` siempre. Acá hay decenas de botones y
     cientos de caracteres: se activa solo mientras el botón está apuntado. */
  .button-004:is(:hover,:focus-visible) .button-004__split-char{
    will-change:transform,translate,rotate,opacity;
  }
  .button-004:is(:hover,:focus-visible) .button-004__text.is--default .button-004__split-char,
  [data-hover]:is(:hover,:focus-visible) .button-004 .button-004__text.is--default .button-004__split-char{
    translate:calc(var(--signed-index) * .125em) calc(var(--button-004-translate-y) * -1) 0;
    rotate:1 0 0 72deg;
    transform:rotateZ(calc(var(--rot-sign) * var(--rot-curve) * var(--rot-max) * -1)) scale(.65);
    opacity:0;
    transition:transform .35s var(--delay) var(--button-004-ease-hover),translate .35s var(--delay) var(--button-004-ease-hover),rotate .35s var(--delay) var(--button-004-ease-hover),opacity .15s calc(var(--delay) + .1s) ease-out;
  }
  .button-004:is(:hover,:focus-visible) .button-004__text.is--hover .button-004__split-char,
  [data-hover]:is(:hover,:focus-visible) .button-004 .button-004__text.is--hover .button-004__split-char{
    translate:0 0 0;
    rotate:1 0 0 0deg;
    transform:rotateZ(0deg) scale(1);
    opacity:1;
    transition:transform .325s calc(var(--delay) + .05s) var(--button-004-ease-hover),translate .425s calc(var(--delay) + .05s) var(--button-004-ease-hover),rotate .45s calc(var(--delay) + .05s) var(--button-004-ease-hover),opacity .15s calc(var(--delay) + .075s) ease-out;
  }
}
/* Teclado en dispositivos sin hover fino: el reemplazo igual ocurre. */
@media (hover:none) and (prefers-reduced-motion:no-preference){
  .button-004:focus-visible .button-004__text.is--default .button-004__split-char{opacity:0;transition:opacity .15s ease-out}
  .button-004:focus-visible .button-004__text.is--hover .button-004__split-char{
    translate:0 0 0;rotate:1 0 0 0deg;transform:rotateZ(0deg) scale(1);opacity:1;
    transition:opacity .15s .1s ease-out;
  }
}

/* --- modo integrado ------------------------------------------------------ */
/* El botón anfitrión conserva su fondo, su relleno y su radio: lo único que
   se agrega es la pila de texto. Por eso acá no va ni `__inner` ni `__bg`. */
.button-004--inline{--button-004-translate-y:1em}
/* Controles compactos: el vuelo de los caracteres se acorta para que no
   invada al vecino dentro de los segmentados ni se salga del popover. */
.modes .button-004,.proj .button-004,#simgps.button-004,
.demo-btn.button-004,.tour__acts .button-004{--button-004-translate-y:.78em}

/* Los dos botones del banner comparten alto y no empujan el layout. */
.iacts .btn-bubble-arrow,.iacts .button-004{flex:0 0 auto}
@media (max-width:420px){
  .btn-bubble-arrow{font-size:12.5px}
  .btn-bubble-arrow__content{padding-left:1.3em;padding-right:1.3em}
  .iacts .button-004{font-size:12.5px;--button-004-padding:1.05em 1.25em}
}

/* --- paneles internos: cada uno declara su disposición ------------------- */
/* Analítica: cuatro indicadores en 2 × 2 dentro de un panel de 340 px.
   `minmax(0,1fr)` evita que una cifra larga estire la columna y desborde. */
#abody .kpis{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
#abody .kpi,#vbody .kpi{min-width:0}
#abody .kpi .k,#vbody .kpi .k{white-space:normal;line-height:1.3}
/* Vendedor: la tarjeta de unidad es un bloque, no una grilla. */
#vbody .vrow{display:block}
#vbody .vrow .top{flex-wrap:wrap}
.vnota{font-size:11.5px;color:var(--text-muted);line-height:1.5;margin:-4px 0 14px}

/* --- desplegables nativos ------------------------------------------------ */
/* El popup de un <select> lo dibuja el sistema operativo, no la página. Sin
   declarar el esquema de color lo pinta claro y hereda nuestro texto blanco:
   las opciones quedaban blancas sobre blanco y solo se leía la resaltada.
   `color-scheme:dark` hace que el popup nativo se dibuje oscuro en todas las
   plataformas; los colores explícitos cubren a los navegadores que sí permiten
   estilar <option> pero ignoran el esquema. */
select,input[type=date],input[type=time],input[type=month]{color-scheme:dark}
select option,select optgroup{background-color:#1C1C1C;color:#FEFEFE}

/* =============================================================================
   MOBILE ≤900 — segunda pasada
   Este bloque va acá abajo a propósito, no por desprolijidad: varias de estas
   reglas tienen que ganarle a declaraciones que aparecen más adelante en el
   archivo (el radio unificado de los paneles en la "capa 2", por ejemplo) y la
   única forma de hacerlo sin inflar la especificidad es el orden de aparición.
   ========================================================================== */

/* Cierre de Analítica y Vendedor. El marcado —`.x.aclose` adentro de `.ahead`—
   lo pone el Agente 3, pero `.x` solo trae anclaje adentro de `.dhead`: fuera
   de ahí el botón caía en el flujo, delante del título. La esquina la pone
   esta regla, y en mobile `.x` lo lleva solo a 44 px. */
.ahead{position:relative;padding-right:52px}
.aclose{position:absolute;right:9px;top:50%;transform:translateY(-50%);
  border-radius:var(--rs);width:28px;height:28px;display:grid;place-items:center;
  color:var(--text-muted);background:transparent;transition:.14s}
.aclose:hover{background:var(--surface);color:var(--text-primary)}

/* Expandir la ficha solo tiene sentido donde la ficha es una hoja recortada:
   en escritorio el panel ya va de arriba abajo y no hay nada que expandir. */
.dexpand{display:none}

@media (max-width:900px){

  /* --- ficha de unidad ---------------------------------------------------- */
  /* Antes ocupaba 66 vh fijos: en un 390×844 eran 557 px, dos tercios de la
     pantalla, con el pie de acciones tapado por la barra y sin manera de
     agrandarla. Ahora arranca en poco más de media pantalla —el mapa se sigue
     leyendo— y se expande con un botón. Sin sistema de arrastre. */
  #detail{
    left:0;right:0;width:auto;top:auto;bottom:0;
    height:min(55vh,560px);
    height:min(55dvh,560px);
    border-radius:18px 18px 0 0;
    transform:translateY(102%);
    padding-bottom:0;
  }
  #detail.on{transform:none}
  #detail.is--full{
    height:min(92vh,900px);
    height:min(92dvh,900px);
  }
  /* El scroll de la ficha se queda adentro de la ficha: sin esto, al llegar al
     final de la lista el gesto seguía de largo y el que se movía era el mapa.
     El relleno inferior es lo que saca las acciones de abajo de la barra. */
  #dbody{overscroll-behavior:contain;padding-bottom:calc(22px + var(--mbar-clear))}
  /* Mismo criterio para el cuerpo de los filtros: el gesto termina en la hoja. */
  .fbody{overscroll-behavior:contain}
  /* Expandir/contraer, a la izquierda del cierre. El marcado lo pone el
     Agente 3; acá quedan definidos el lugar y los dos estados. */
  .dexpand{display:grid;position:absolute;right:59px;top:11px;width:44px;height:44px;
    border-radius:var(--rs);display:grid;place-items:center;
    color:var(--text-muted);background:transparent;transition:.14s}
  .dexpand:hover{background:var(--surface);color:var(--text-primary)}
  .dexpand svg{transition:transform .22s cubic-bezier(.22,1,.36,1)}
  #detail.is--full .dexpand svg{transform:rotate(180deg)}
  /* El título y el rótulo del proyecto no pueden meterse abajo de los dos
     botones de 44 px; los chips sí pueden usar el ancho completo. */
  .dhead .pj,.dhead h2{padding-right:104px}

  /* --- analítica y vendedor ----------------------------------------------- */
  /* Eran `calc(100vw - 28px)` pero conservaban `top:70px; bottom:14px`, así que
     chocaban con la barra y con la leyenda. Pasan a hoja casi completa. */
  #analytics,#vend{
    left:0;right:0;width:auto;top:var(--header-clear);bottom:0;
    border-radius:18px 18px 0 0;
  }
  #analytics .abody,#vend .abody{
    overscroll-behavior:contain;padding-bottom:calc(14px + var(--mbar-clear));
  }
  /* `.x` ya lo lleva a 44 px: acá solo hay que abrirle el lugar al título. */
  .ahead{padding-right:62px}

  /* --- despeje de la barra inferior --------------------------------------- */
  /* Ninguna de estas cuatro tenía despeje y las cuatro quedaban abajo de la
     barra. `#gps` tenía solo el inset seguro, que no alcanza. */
  #slbar{bottom:calc(var(--mbar-clear) + 10px);max-width:calc(100vw - 20px)}
  #slbar .items{overflow-x:auto;min-width:0}
  #toast{bottom:calc(var(--mbar-clear) + 12px);max-width:min(400px,calc(100vw - 24px))}
  #exploreGuide{bottom:calc(var(--mbar-clear) + 12px)}
  .zoomhint{bottom:calc(var(--mbar-clear) + 12px)}
  #gps{bottom:calc(var(--mbar-clear) + 8px)}

  /* --- grillas que nunca colapsaban --------------------------------------- */
  /* Dos columnas dentro de un panel de 292 px dejan celdas de 140: el texto
     caía palabra por palabra. `#abody .kpis` queda en 2×2 por especificidad
     propia y `#dbody .kpis` en flex: cada panel manda sobre lo suyo. */
  .btn2{grid-template-columns:1fr}
  .kpis{grid-template-columns:1fr}
  .vpanel__acts{grid-template-columns:1fr}
  /* `.lv-row` y `.lv-go` se redefinen más abajo, en el bloque de tarjetas. */

  /* --- anchos fijos sin corrección ---------------------------------------- */
  #legend{min-width:0;max-width:calc(100vw - 28px)}
  #tip{min-width:0;max-width:calc(100vw - 24px)}
  .trow .id{width:auto;flex:none;min-width:64px}
  .simu__f--cuo{width:min(96px,34%)}

  /* --- campos de formulario ----------------------------------------------- */
  /* Abajo de 16 px iOS hace zoom solo al enfocar, y con `body{overflow:hidden}`
     el usuario se queda trabado en esa escala sin poder volver. En escritorio
     la escala compacta se conserva: esto vive únicamente acá adentro.
     Los selectores repetidos son para ganarle a las reglas de clase que ya
     fijaban 11,5 / 12,5 / 14 px. */
  input,select,textarea,
  .search input,select.sel,.wait input,.simfield input,.idxr input,.vin{font-size:16px}

  /* --- objetivos táctiles -------------------------------------------------- */
  /* `.button-004` declara `min-height:0!important` y con eso los botones de
     acción de la ficha se quedaban en 39 px. Se restituye el mínimo desde
     afuera, sin tocar el componente. */
  #bres,#bwa,#bsim,#bvis,#bcmp,#bshare,#bsimu,.cta .btn{min-height:44px!important}
  /* Los controles nativos del mapa miden 29×29 y el grupo terminaba abajo de
     la barra. */
  .maplibregl-ctrl button{min-width:44px;min-height:44px}
  .maplibregl-ctrl-bottom-right{bottom:calc(var(--mbar-clear) + 8px)}

  /* --- tarjetas de unidad: una jerarquía, no una lista de campos ----------- */
  /* Antes cada tarjeta terminaba en un botón centrado de ancho completo que
     repetía el nombre de la unidad. Ahora manda el título, el resto es apoyo,
     y se toca la tarjeta entera. */
  .lv-row{
    grid-template-columns:1fr auto;
    grid-template-areas:'main ir' 'meta ir';
    align-items:center;gap:2px 10px;padding:12px 13px;cursor:pointer;
  }
  .lv-row:active{background:var(--surface-hover)}
  /* Grilla explícita y no flex: con `wrap` el nombre y el badge nunca entraban
     en la misma línea y la tarjeta trepaba a 148 px. Acá cada uno tiene su
     celda y el nombre se recorta con puntos suspensivos si hace falta. */
  .lv-main{grid-area:main;display:grid;grid-template-columns:auto minmax(0,1fr);
    align-items:center;column-gap:7px;row-gap:2px}
  /* El título se queda con el ancho completo: compartiéndolo con el badge,
     "Manzana 27 · Lote 01" no entraba y se cortaba con puntos suspensivos. */
  .lv-nm{grid-column:1/-1;grid-row:1;font-size:14px;font-weight:600;letter-spacing:-.2px;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .lv-st{grid-column:1;grid-row:2}
  .lv-pj{grid-column:2;grid-row:2;font-size:11.5px;color:var(--text-muted);
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  /* Segunda línea: solo los valores, separados por un punto. Con las etiquetas
     "SUPERFICIE" y "PRECIO" delante no entran juntas ni en 390 px, y el dato
     ya se entiende solo. Las etiquetas siguen ahí para el lector de pantalla. */
  .lv-meta{grid-area:meta;display:flex;flex-wrap:nowrap;gap:0 7px;margin-top:2px;min-width:0}
  .lv-meta > div{display:flex;align-items:baseline;gap:7px;min-width:0}
  .lv-meta > div + div::before{content:'·';color:var(--text-muted);flex:none}
  .lv-meta dt{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
  .lv-meta dd{font-size:12.5px;font-weight:600;white-space:nowrap;
    overflow:hidden;text-overflow:ellipsis}
  /* El botón queda como afordancia mínima a la derecha y como destino de
     teclado; el nombre completo sigue en su texto para lector de pantalla. */
  /* Ojo: nada de `grid-row`/`grid-column` después de `grid-area` — son la misma
     propiedad y la reescriben a `auto`, que fue lo que dejó el botón ocupando
     una fila entera de 170 px. */
  .lv-go{grid-area:ir;align-self:center;justify-self:end;
    min-width:44px;min-height:44px;padding:0 10px;font-size:12px;white-space:nowrap}
  /* En 320 px la tarjeta se queda con 242 px útiles: el botón y el badge le
     comen al título los 3 px que le faltaban para entrar entero. Se aprieta
     solo lo accesorio; el título y el proyecto no se recortan. */
  @media(max-width:360px){
    .lv-row{padding:11px 10px;gap:2px 8px}
    .lv-go{padding:0 7px;font-size:11px}
    .lv-st{padding:2px 6px;letter-spacing:.03em}
  }
  .lv-mas{list-style:none;padding:4px 0 2px}
  .lv-mas .btn{width:100%;min-height:44px}
  .lv-mas__n{font-weight:400;color:var(--text-muted);margin-left:5px}

  /* --- la hoja de filtros manda mientras está abierta ---------------------- */
  /* La leyenda "Estado del lote" y los flotantes del mapa quedaban encima de
     los controles. Se repliegan mientras dura la hoja; la barra inferior no,
     porque es la que la cierra. */
  body:has(#filters.sheet-open) :is(#legend,#slbar,#gps,.zoomhint,#exploreGuide,.demo),
  body:has(#filters.sheet-open) .maplibregl-ctrl-bottom-right{
    opacity:0;pointer-events:none;
  }

  /* --- estados que venían de escritorio ------------------------------------ */
  /* `mode()` le pone `.hide` a los filtros y `.shift` a la leyenda para correr
     el panel lateral. En mobile no hay panel lateral: `.hide` mandaba la hoja
     hacia el costado con opacidad 0 y `.shift` empujaba la leyenda a 368 px,
     fuera de una pantalla de 390. */
  #filters.hide{transform:translateY(102%);opacity:1}
  #filters.hide.sheet-open{transform:none}
  #legend.shift{left:14px}
}

/* Dos columnas de specs entran hasta 420 px; abajo de eso el valor se parte. */
@media (max-width:420px){
  .specs{grid-template-columns:1fr}
}

/* -----------------------------------------------------------------------------
   Landscape de poca altura (un teléfono acostado).
   Con 390 px de alto una hoja inferior deja 79 px de mapa: la ficha y los
   filtros pasan a panel lateral, como en escritorio pero angostos. El tope de
   900 px es lo que mantiene a una ventana de escritorio baja fuera de acá.
   -------------------------------------------------------------------------- */
@media (max-width:900px) and (orientation:landscape) and (max-height:520px){
  #detail{
    left:auto;right:0;top:var(--header-clear);bottom:0;
    width:min(360px,46vw);height:auto;
    border-radius:16px 0 0 16px;
    transform:translateX(110%);
  }
  #detail.on{transform:none}
  #detail.is--full{height:auto;width:min(460px,62vw)}
  .dhead .pj,.dhead h2{padding-right:104px}

  #filters{
    left:0;right:auto;top:var(--header-clear);bottom:0;
    width:min(340px,46vw);height:auto;max-height:none;
    border-radius:0 16px 16px 0;
    transform:translateX(-110%);
  }
  #filters.sheet-open,#filters.hide.sheet-open{transform:none}
  #filters.hide{transform:translateX(-110%)}

  /* Acostado la leyenda compite por el poco alto que queda: se recuesta contra
     el borde inferior, entre los dos paneles. */
  #legend{left:50%;transform:translateX(-50%);bottom:calc(var(--mbar-clear) + 8px)}
  #legend.shift{left:50%}
}

/* --- capas ocultas que igual se comían los toques ------------------------- */
/* Estos tres viven fuera de pantalla con `transform` y `opacity:0`, pero eso
   no los saca del hit-test: apoyados sobre la barra inferior interceptaban
   Buscar, Filtrar y Ubicación. Solo reciben eventos cuando están puestos. */
#slbar,#toast,#gps{pointer-events:none}
#slbar.on,#toast.on,#gps.on{pointer-events:auto}

/* La identificación del proyecto en el mapa es un control, no una etiqueta. */
.pjlbl{font:inherit;cursor:pointer;text-align:left;-webkit-tap-highlight-color:transparent}
.pjlbl:hover{border-color:rgba(111,143,114,.8)}
.pjlbl:focus-visible{outline:2px solid var(--primary);outline-offset:3px}

/* Nota de versión en la introducción: informativa y al pie, sin color de
   advertencia — no está pasando nada malo. */
.ibeta{margin-top:16px;padding-top:13px;border-top:1px solid var(--line-soft);
  font-size:11.5px;line-height:1.5;color:var(--text-muted)}
.ibeta b{color:var(--text-secondary);font-weight:600}
.demotag__beta{font-style:normal;margin-left:6px;padding-left:6px;
  border-left:1px solid var(--line);color:var(--primary);font-weight:700}

/* --- recorrido guiado en mobile: modal puro ------------------------------- */
/* En pantalla chica deja de ser un recorrido con foco y pasa a ser una serie
   de tarjetas centradas: anterior, siguiente y listo. El JS ya no ilumina, no
   cambia de modo y no ofrece acciones; acá se le da la forma. */
@media(max-width:900px){
  .tour.is--modal{pointer-events:auto;background:rgba(9,9,9,.72)}
  .tour.is--modal .tour__spot{display:none}
  .tour.is--modal .tour__pop{
    position:absolute;
    left:50%!important;right:auto!important;
    top:50%!important;bottom:auto!important;
    transform:translate(-50%,-50%)!important;
    width:min(420px,calc(100vw - 32px));max-width:none;
    max-height:min(78vh,620px);
    max-height:min(78dvh,620px);
    overflow-y:auto;overscroll-behavior:contain;
  }
  /* El paso ya no tiene tercera acción: los dos botones se reparten el ancho. */
  .tour.is--modal .tour__acts{gap:9px}
  .tour.is--modal .tour__acts .btn{flex:1}
}

/* --- integración final: tres huecos que quedaron entre agentes ------------ */
@media(max-width:900px){
  /* 1. Los avisos se apoyan sobre la franja inferior del mapa. El riel ya es
        `pointer-events:none`, pero el aviso no: con un aviso persistente
        (`timeout:0`) esa franja dejaba de aceptar la pinza. Solo lo que se
        toca de verdad recibe eventos; el texto deja pasar el gesto. */
  .msg{pointer-events:none}
  .msg__a,.msg__x{pointer-events:auto}

  /* 2. Con la ficha abierta la leyenda quedaba debajo de la hoja: ocupaba
        espacio y no se leía. Se repliega mientras haya ficha. */
  body:has(#detail.on) #legend{opacity:0;pointer-events:none}

  /* 3. El teclado virtual no achica el viewport de layout, así que ni `dvh` ni
        `vh` reaccionan: el modal seguía midiendo lo mismo y sus campos bajos
        quedaban tapados. `--vvh` lo publica `ui.js` desde `visualViewport`
        solo mientras el teclado está abierto; sin JS, el fallback deja el
        valor de hoy y no cambia nada. */
  .mdl{max-height:min(88dvh, var(--vvh, 88dvh))}
  .mdl .mbody{overscroll-behavior:contain}
}

/* --- selector de proyectos ------------------------------------------------ */
/* Vive dentro del diálogo genérico y se arma desde `PJ`, así que la lista
   crece sola si mañana hay un tercer desarrollo. */
.pjsel{display:grid;gap:8px}
.pjsel__op{display:grid;gap:2px;text-align:left;width:100%;min-height:56px;
  padding:11px 13px;border-radius:var(--rs);background:var(--surface);
  border:1px solid var(--line);color:var(--text-primary);transition:.14s}
.pjsel__op:hover{background:var(--surface-hover);border-color:var(--primary-line)}
.pjsel__op:focus-visible{outline:2px solid var(--primary);outline-offset:2px}
.pjsel__nm{font-size:14.5px;font-weight:600;letter-spacing:-.2px}
.pjsel__meta{font-size:12px;color:var(--text-muted)}
/* El activo se marca con `aria-current`, no con una clase: el estado ya está
   dicho en el marcado y no hay que mantenerlo en dos lugares. */
.pjsel__op[aria-current="true"]{background:var(--primary-soft);border-color:var(--primary-line)}
.pjsel__op[aria-current="true"] .pjsel__nm{color:var(--primary)}
.pjsel__op[aria-current="true"] .pjsel__meta{color:var(--text-secondary)}

/* --- mini card del asesoramiento ------------------------------------------ */
/* Reusa el encuadre de `.adv`, así que acá solo se la achica: es una antesala
   de dos párrafos, no puede pesar como el asesoramiento entero. */
.advintro .advintro__card{max-width:420px}
.advintro .advintro__body{padding:18px 18px 6px}
.advintro .advintro__ttl{font-size:17.5px;margin-bottom:10px}
.advintro .advintro__txt{margin-bottom:10px}
.advintro .advintro__txt:last-child{margin-bottom:2px}

/* --- descripción del recorrido en párrafos -------------------------------- */
/* `.tour__desc` pasó de `<p>` a `<div>` con varios `<p>` adentro: la
   separación la da el margen entre párrafos, no saltos de línea. Se mantiene
   el cuerpo de 13px — achicar la tipografía para que entre sería resolverlo
   por el lado equivocado. */
.tour__desc p{margin:0 0 9px}
.tour__desc p:last-child{margin-bottom:0}

@media(max-width:900px){
  /* Sin el pie, el panel pierde el único despeje que separaba los últimos
     filtros de la barra inferior: se lo devuelve el cuerpo. */
  #filters.filters--nofoot .fbody{padding-bottom:calc(14px + var(--mbar-clear))}
  /* En el modal del recorrido los párrafos respiran un poco menos: el alto
     está acotado y son dos o tres por paso. */
  .tour.is--modal .tour__desc p{margin-bottom:8px}
}

/* =============================================================================
   MOBILE ≤900 — tercera pasada: que las decisiones entren en el teléfono.
   El criterio que ordena todo el bloque: en mobile ninguna acción principal
   puede depender de descubrir que hay que hacer scroll. Lo accesorio se pliega
   —tabs, acordeones, scroll interno—; lo que hay que decidir queda a la vista.
   Va al final del archivo por la misma razón que las dos pasadas anteriores:
   varias reglas tienen que ganarle por orden a declaraciones más abajo.
   ========================================================================== */

/* --- 1. tooltip: sin mouse no hay hover que valga -------------------------- */
/* Global a propósito. `core.js` ya lo bloquea desde JS en `pointer:coarse`;
   esto es el respaldo, para que un tooltip de hover no aparezca nunca en
   táctil aunque el JS no llegue a correr. */
@media (pointer:coarse){
  #tip{display:none!important}
}

/* --- 2. simulador: componentes nuevos (globales) -------------------------- */
/* Clases acordadas con el agente de `core.js`. Hoy `#ovSim` todavía trae el
   marcado viejo (`.simgrid`, `.idx`, `#simOut`), así que estos selectores no
   enganchan con nada: no mueven un píxel de la pantalla actual, ni en mobile ni
   en escritorio. Quedan escritos para cuando el modal se reestructure.
   OJO: `.simfoot` ya existe arriba (línea ~432) como el pie de letra chica que
   `core.js` imprime dentro de `#simOut`. Esta es OTRA cosa —la zona del CTA—,
   así que todo lo que la trate como barra va acotado con `:has(#simRun)` y el
   disclaimer viejo sigue intacto. */

/* Bloque principal: cuota inicial, ingresos y el resumen del índice. */
.simmain{display:grid;gap:12px}

/* Resumen del índice activo, una sola línea y discreta: "ICAC · promedio
   2,60 %". No compite con los campos que sí hay que completar. */
.simidx{display:flex;align-items:center;gap:8px;min-width:0;
  font-size:var(--fs-sm);color:var(--text-muted);line-height:1.35}
.simidx b{color:var(--text-secondary);font-weight:600;font-variant-numeric:tabular-nums}
.simidx > *{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* Acordeones. Se reusa el criterio de `.more summary`: sin marcador nativo,
   chevron propio que gira al abrir y el texto como control, no como título. */
details.simadv,details.simdet{border-top:1px solid var(--line-soft);margin-top:14px}
details.simadv > summary,details.simdet > summary{
  list-style:none;cursor:pointer;
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  min-height:44px;padding:6px 0;
  font-size:var(--fs-sm);font-weight:600;color:var(--text-secondary);
}
details.simadv > summary::-webkit-details-marker,
details.simdet > summary::-webkit-details-marker{display:none}
details.simadv > summary::after,details.simdet > summary::after{
  content:'';flex:none;width:7px;height:7px;margin-right:3px;
  border-right:1.6px solid currentColor;border-bottom:1.6px solid currentColor;
  transform:rotate(45deg) translate(-2px,-2px);transition:transform .18s;
}
details.simadv[open] > summary::after,details.simdet[open] > summary::after{
  transform:rotate(-135deg) translate(-2px,-2px);
}
details.simadv > summary:hover,details.simdet > summary:hover{color:var(--text-primary)}
details.simadv > summary:focus-visible,details.simdet > summary:focus-visible{
  outline:2px solid var(--primary);outline-offset:2px;border-radius:var(--rs);
}
/* Las filas mensuales y la tabla larga arrancan pegadas al summary. */
details.simadv > :not(summary){padding-top:4px}
details.simdet > :not(summary){padding-top:6px}

/* Resultado esencial: lo que se lee apenas se calcula. */
.simres{margin-top:14px}

/* Zona del CTA: último hijo de `.mbody`, que es lo único que scrollea. El
   fondo y el borde superior la separan del contenido que le pasa por debajo. */
#ovSim .simfoot{
  margin:14px 0 0;padding:12px 0 0;border-top:1px solid var(--line-soft);
  background:var(--solid);
}
#ovSim .simfoot #simRun{width:100%;margin:0}

/* --- 3. ficha con tabs (mobile) ------------------------------------------- */
/* Marcado real, leído de `core.js`: adentro de `#dbody` —que es lo que
   scrollea— van, en este orden, el precio, `dl.dgrid`, `.dtabs[role=tablist]`
   con sus `.dtab[role=tab]`, los `.dpane[role=tabpanel]` (los inactivos con
   `hidden`) y `.dacts` al final. Cada celda de `.dgrid` es un `<div>` con
   `dt.k` y `dd.v` adentro.
   En escritorio `core.js` ni siquiera arma pestañas —la ficha es una columna
   de 352 px que entra entera—, así que todo esto vive dentro del bloque de
   900 px. */

@media (max-width:900px){

  /* ---- 3.0 alto mínimo cuando hay pestañas ----------------------------- */
  /* La hoja de 55dvh alcanzaba para una ficha en columna, no para una con
     cromo fijo arriba y abajo. Medido a 360×640: encabezado 99 + precio 50 +
     grilla 63 + pestañas 61 + acciones 116 = 389 px de cosas que NO scrollean,
     contra 352 de hoja. Las pestañas quedaban debajo de las acciones y
     "Financiación" no se veía.
     El piso se pone en píxeles y no en `dvh` a propósito: lo que hay que
     cubrir es una altura fija, no una proporción. Como `min-height` solo gana
     cuando es mayor, en 390×844 (464 px de hoja) no cambia nada y la decisión
     de "poco más de media pantalla" se conserva donde había lugar. El tope de
     92dvh es el mismo que usa `.is--full`: la hoja nunca tapa la pantalla. */
  #detail:has(.dtabs){min-height:min(92dvh,432px)}
  /* Con tres acciones fijas hacen falta 56 px más. Ver la nota de `.dacts--3`. */
  #detail:has(.dacts--3){min-height:min(92dvh,488px)}

  /* ---- 3.1 tabs -------------------------------------------------------- */
  /* Sticky y no `flex:none`: las pestañas están adentro del contenedor que
     scrollea, así que lo que las deja quietas bajo el encabezado es clavarlas
     al borde superior del scroller. El fondo opaco es lo que hace que el
     precio pase por detrás y no a través. */
  #detail .dtabs{
    position:sticky;top:0;z-index:3;
    display:flex;gap:2px;
    margin:10px -20px 0;padding:5px 20px;
    background:var(--panel);border-bottom:1px solid var(--line-soft);
    overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:none;
  }
  #detail .dtabs::-webkit-scrollbar{display:none}
  /* Un `sticky` no puede subir más allá de la caja de CONTENIDO del scroller,
     así que con el relleno superior de 18 px de `#dbody` las pestañas se
     clavaban 18 px abajo del borde y por esa franja asomaba el precio. El
     relleno se lo pasa el precio, que es el primero de la columna. */
  #dbody:has(.dtabs){padding-top:0}
  #dbody:has(.dtabs) > .price{margin-top:18px}
  #detail .dtab{
    flex:1 1 auto;min-width:max-content;min-height:40px;padding:8px 12px;
    border-radius:var(--rs);background:transparent;border:1px solid transparent;
    font-size:12.5px;font-weight:600;letter-spacing:-.1px;white-space:nowrap;
    color:var(--text-muted);transition:.14s;
  }
  #detail .dtab:active{background:var(--surface)}
  /* El activo se dice con `aria-selected`, que ya está en el marcado: no hace
     falta una clase modificadora que haya que mantener en dos lugares. */
  #detail .dtab[aria-selected="true"]{
    background:var(--primary-soft);border-color:var(--primary-line);color:var(--primary);
  }
  #detail .dtab:focus-visible{outline:2px solid var(--primary);outline-offset:-2px}

  /* ---- 3.2 paneles ------------------------------------------------------ */
  /* Sin relleno lateral propio: el que manda es el de `#dbody`, así el
     sangrado negativo de las pestañas y de las acciones cierra contra el borde
     de la hoja. Los inactivos los apaga `[hidden]`, que está al final. */
  #detail .dpane{display:block;padding:12px 0 0}
  #detail .dpane > :first-child{margin-top:0}

  /* Grilla compacta de superficie, medidas y orientación: tres celdas de
     `<div><dt class="k"><dd class="v">`. `auto-fit` deja las tres en una fila
     desde 340 px y baja a dos abajo de eso. */
  #detail .dgrid{
    display:grid;grid-template-columns:repeat(auto-fit,minmax(94px,1fr));
    gap:1px;margin:12px 0 0;
    background:var(--line-soft);border:1px solid var(--line-soft);
    border-radius:var(--rs);overflow:hidden;
  }
  #detail .dgrid > *{background:var(--panel);padding:7px 9px;margin:0}
  /* La etiqueta baja a 10 px y pierde el interletrado ancho para que
     "Frente × Fondo" entre en un renglón: dos renglones por celda inflaban la
     grilla 18 px que después le faltaban a las pestañas. */
  #detail .dgrid dt{font-size:10px;letter-spacing:.04em;
    text-transform:uppercase;color:var(--text-muted);line-height:1.25}
  #detail .dgrid dd{font-size:13.5px;font-weight:600;margin:2px 0 0;letter-spacing:-.2px}
  /* Abajo de 375 px la celda se queda con ~86 px útiles y "FRENTE × FONDO"
     vuelve a partirse: la grilla saltaba de 51 a 64 px. Se achica la etiqueta,
     no el dato. */
  @media (max-width:374px){
    #detail .dgrid{grid-template-columns:repeat(auto-fit,minmax(80px,1fr))}
    #detail .dgrid > *{padding:7px 7px}
    #detail .dgrid dt{font-size:9.5px;letter-spacing:.02em}
    #detail .dgrid dd{font-size:13px}
  }

  /* ---- 3.3 acciones ----------------------------------------------------- */
  /* Se apoyan en el pie del cuerpo y no se van con el scroll. Dos cuentas que
     hay que tener juntas o no cierra:

     · Un elemento `sticky` no puede salirse de su bloque contenedor, que es la
       CAJA DE CONTENIDO de `#dbody`. Con el relleno inferior de 22 px + barra
       que traía `#dbody`, la barra de acciones quedaba clavada 78 px por
       encima del borde de la hoja: una franja muerta que no se podía usar. Por
       eso el relleno se le saca al cuerpo y se lo pone la propia barra, que sí
       llega hasta abajo y despeja la barra del teléfono con su relleno.
     · Tres botones apilados son 229 px. Clavados abajo tapaban el precio, la
       grilla y las pestañas enteras. La acción principal se queda con el ancho
       completo y las dos secundarias comparten la segunda fila: 172 px, que es
       lo que deja las pestañas a la vista al abrir la ficha. */
  #detail .dacts{
    position:sticky;bottom:0;z-index:2;
    display:grid;grid-template-columns:1fr 1fr;gap:6px;
    margin:12px -20px 0;
    padding:8px 20px calc(8px + var(--mbar-clear));
    background:var(--panel);border-top:1px solid var(--line-soft);
  }
  /* Interlineado corto y relleno chico: "Consultar por WhatsApp" cae en dos
     renglones a media pantalla y sin esto el botón se iba a 61 px, que era lo
     que empujaba la barra por encima de las pestañas. El mínimo táctil de
     44 px sigue en pie. */
  #detail .dacts > *{width:100%;min-height:44px!important;
    font-size:12.5px;line-height:1.15;padding:6px 8px;gap:5px}
  /* La primera acción es la que decide: se queda con la fila entera. Con dos
     botones (`.dacts--2`) van los dos en línea y la barra mide 116 px; con uno
     solo la regla se resuelve igual de bien.
     `.dacts--3` es la variante pedida por el agente de `core.js`: primaria a
     todo el ancho arriba y las dos secundarias abajo, 172 px. Cuesta 56 px de
     cromo fijo, que es lo que sube el piso de `#detail:has(.dacts--3)`. */
  #detail .dacts > :first-child{grid-column:1/-1}
  #detail .dacts--2 > :first-child{grid-column:auto}
  #detail .dacts--3 > :first-child{grid-column:1/-1}
  /* Lo que libera los 78 px de arriba. Sin `:has()` la barra queda un poco más
     alta y sobra un hueco del mismo color: se ve raro, no roto. */
  #dbody:has(.dacts){padding-bottom:0}

  /* ---- 3.4 acciones secundarias: una grilla, no una pila ---------------- */
  /* Las cuatro complementarias —Agendar visita, Comparar, Compartir y
     Proyección de cuotas— viven en `.more__in` adentro del panel Resumen. En
     una sola columna eran 197 px de botones apilados y, con el chrome anterior,
     de anchos distintos: cuatro cosas del mismo rango leyéndose como cuatro
     jerarquías. En 2×2 son 96 px, ocupan la mitad del alto y se leen como un
     bloque.
     `grid-auto-rows:1fr` es lo que iguala las DOS filas entre sí: sin eso,
     "Proyección de cuotas" cae en dos renglones y su fila queda más alta que la
     de arriba. Con él, los cuatro botones miden exactamente lo mismo.
     Siguen siendo secundarios: el tratamiento delineado del componente no
     cambia y las dos acciones que deciden —Reservar y WhatsApp— siguen solas
     en `.dacts`, al pie y con su color. */
  #detail .dpane .more__in{
    grid-template-columns:1fr 1fr;
    grid-auto-rows:1fr;
    gap:8px;
  }
  #detail .dpane .more__in > *{
    width:100%;height:100%;min-height:44px!important;margin:0;
    font-size:12.5px;line-height:1.2;padding:6px 8px;text-align:center;
  }
  /* Por qué hace falta esto y no alcanza con `width:100%`:
     `.btn` trae `justify-content:center`, que en `.button-004` —que es una
     grilla— deja de centrar texto y pasa a CENTRAR LA PISTA. La columna se
     dimensiona al contenido, y como `.button-004__bg` mide `width:100%` DE LA
     PISTA, la píldora visible terminaba con el ancho de su propia etiqueta:
     111 px "Agendar visita", 87 "Comparar", 88 "Compartir", 151 "Proyección
     de cuotas", los cuatro centrados en celdas de 166. Ése era el origen real
     de los anchos distintos, no un margen suelto.
     Con una columna `1fr` la pista ocupa la celda entera y el fondo, el borde
     y el objetivo táctil coinciden con el botón. El centrado del texto lo
     sigue haciendo `.button-004__inner`, que no se toca. */
  #detail .dpane .more__in > .button-004{
    grid-template-columns:1fr;
    place-items:stretch;
  }
  /* La grilla se sostiene hasta 320 px: medido ahí, las celdas quedan en
     131×56, "Proyección de cuotas" cae en dos renglones —completa, sin
     recortes— y `grid-auto-rows:1fr` iguala las dos filas, así que los cuatro
     botones miden lo mismo igual. No hace falta variante de una columna. */

  /* ---- 3.5 el encabezado y el cierre no se van nunca -------------------- */
  /* El alto que le saque el encabezado es alto que pierden las pestañas: se
     aprieta el relleno, no el cuerpo del título. */
  #detail .dhead{flex:none;padding:12px 16px 10px}
  #detail .dhead .chips{margin-top:7px}
  #detail #dbody{flex:1 1 auto;min-height:0}
}

/* --- 4. introducción: entra completa en el viewport visible ---------------- */
@media (max-width:900px){
  /* `inset:0` en un fijo se mide contra el viewport de *layout*: en un iPhone
     eso incluye la franja del navegador y la tarjeta quedaba centrada sobre un
     alto que en realidad no se ve. Con una altura dinámica explícita el
     contenedor mide lo que el usuario tiene delante y el centrado es real.
     `vh` primero para los navegadores que todavía no entienden `dvh`. */
  #entryIntro{
    height:100vh;
    height:100dvh;
    padding:10px 10px calc(10px + env(safe-area-inset-bottom,0px));
    padding-top:calc(10px + env(safe-area-inset-top,0px));
  }
  /* Red de seguridad: si aun así no entrara —tipografía del sistema más
     grande, un idioma más largo, la franja del navegador en su estado más
     alto— la tarjeta scrollea adentro suyo en vez de recortarse contra un
     `overflow:hidden` del que no se vuelve. Los dos CTA están arriba del
     pliegue, así que la acción principal nunca depende de ese scroll. */
  .icard{
    max-height:100%;overflow-y:auto;overscroll-behavior:contain;
    padding:16px 18px 18px;
  }
  /* Ritmo vertical: se aprieta la separación, no la letra. */
  .icard h2{margin:6px 0 8px;line-height:1.12}
  .isub{font-size:13.5px;line-height:1.5}
  /* Los dos CTA en columna y con la altura táctil completa: `.button-004`
     declara `min-height:0!important` y dejaba a "Explorar libremente" en
     38,8 px. El primario crece por su propio token, no por un mínimo externo,
     así que la burbuja sigue siendo redonda. */
  .iacts{flex-direction:column;align-items:flex-start;gap:8px;margin-top:14px}
  .iacts .btn-bubble-arrow{--bba-size:44px}
  #introExplore{min-height:44px!important}
  /* Beneficios y nota de versión: apoyo, no protagonistas. */
  .ifacts{margin-top:12px;padding-top:11px;gap:4px}
  .ifacts li{font-size:12px;line-height:1.4;padding-left:13px}
  .ionsite{margin-top:12px;padding-top:11px}
  .inote{font-size:11px;margin-top:6px;line-height:1.4}
  .ibeta{margin-top:11px;padding-top:9px;font-size:10.5px;line-height:1.45}
  #introErr{margin-top:9px;font-size:12px}

  /* En 320 el título ya usa sus tres renglones y el texto de apoyo se lleva
     casi 200 px. Se aprieta lo accesorio —beneficios y nota de versión—, no el
     título ni los botones. */
  @media (max-width:360px){
    .icard{padding:14px 16px 16px}
    .isub{font-size:13px;line-height:1.45}
    .iacts{margin-top:12px}
    .ifacts{margin-top:11px;padding-top:10px}
    .ifacts li{font-size:11.5px;line-height:1.35;padding-left:12px}
    .ibeta{margin-top:10px;padding-top:8px;font-size:10px;line-height:1.4}
  }
  /* Teléfono bajo de verdad (un SE con la franja del navegador puesta deja
     ~460 px). Ahí la tarjeta no entra por más que se aprieten los márgenes: lo
     que queda garantizado es el orden. Volanta, título, bajada y los dos CTA
     están antes en el documento, así que el recorte cae siempre sobre los
     beneficios y la nota de versión —nunca sobre una acción. */
  @media (max-height:620px){
    .ifacts{margin-top:10px;padding-top:9px}
    .ibeta{margin-top:9px;padding-top:8px}
  }
}

/* --- 5. hoja de filtros: entre 45 % y 52 % del viewport -------------------- */
@media (max-width:900px){
  /* Venía de 54dvh. Con el pie oculto y los grupos apretados, 49dvh alcanza
     para todos los controles y devuelve medio viewport de mapa, que es lo que
     hace que filtrar se entienda mientras se filtra. */
  #filters{
    max-height:49vh;
    max-height:49dvh;
  }
  /* Encabezado fijo: en una columna flex `.fhead` podía encogerse y "Filtros"
     quedaba apretado contra "Limpiar" cuando el cuerpo pedía lugar. */
  /* El relleno vertical baja a 2 px porque la cruz ya aporta los 44 px de alto
     mínimo: sumar los dos habría dejado un encabezado de 62 px en una hoja de
     media pantalla. La fila queda en 44 px justos, con el título, "Limpiar" y
     la cruz centrados en la misma línea. */
  #filters .fhead{flex:none;padding:2px 6px 2px 14px;min-height:44px}
  #filters .fhead h3{font-size:11.5px}
  /* Salida explícita de la hoja. 44×44 reales; el icono se ve chico a
     propósito, igual que las demás cruces del visor. */
  #filters .fclose{
    display:grid;place-items:center;flex:none;
    width:44px;height:44px;border-radius:var(--rs);
    background:transparent;color:var(--text-muted);transition:.14s;
  }
  #filters .fclose:active{background:var(--surface);color:var(--text-primary)}
  #filters .fclose:focus-visible{outline:2px solid var(--primary);outline-offset:-3px;color:var(--text-primary)}
  /* El cuerpo es lo único que scrollea, y solo si hace falta. */
  #filters .fbody{padding:2px 14px 12px}

  /* Menos aire entre Precio, Superficie y Entrega: eran 26 px por grupo de
     relleno más 9 de etiqueta. */
  #filters .fgrp{padding:9px 0}
  #filters .fgrp:first-child{padding-top:6px}
  #filters .flab{margin-bottom:6px}
  #filters .rng{margin-top:2px}

  /* Estado: tres filas apiladas de 32 px se comían 97 px de una hoja de 414.
     Pasan a fichas que envuelven solas —dos renglones en 390, uno en 412— y de
     paso el objetivo táctil sube de 32 a 40 px. El estado se sigue diciendo con
     color, texto y tilde: no queda apoyado solo en el color. */
  #filters .fgrp:has(> .chk){display:flex;flex-wrap:wrap;gap:6px}
  #filters .fgrp:has(> .chk) > .flab{flex:0 0 100%;margin-bottom:1px}
  #filters .chk{
    flex:1 1 108px;max-width:calc(50% - 3px);
    margin:0;min-height:40px;padding:5px 9px;gap:6px;
    border:1px solid var(--line-soft);background:var(--surface);
  }
  #filters .chk:has(input:checked){border-color:var(--primary-line);background:var(--primary-soft)}
  #filters .chk .nm{flex:1 1 auto;min-width:0;font-size:12.5px;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  #filters .chk .ct{flex:none;font-size:11px}
  #filters .chk .dot{width:8px;height:8px}

  /* El pie oculto no puede dejar hueco: `.ffoot` sale con `[hidden]` desde
     `core.js` y `#filters.filters--nofoot .fbody` (más arriba) le devuelve al
     cuerpo el despeje de la barra. Acá solo se confirma que el pie no reserva
     alto ni relleno cuando no está. */
  #filters.filters--nofoot .ffoot{display:none!important;padding:0;border:0}
}

/* Landscape bajo: la hoja no existe, es un panel lateral de arriba abajo. El
   tope de 49dvh de recién lo dejaría en 190 px de alto, así que se le repite
   acá el `max-height:none`. Esta variante viene de antes y se conserva. */
@media (max-width:900px) and (orientation:landscape) and (max-height:520px){
  #filters{height:auto;max-height:none}
  /* La ficha tampoco es una hoja acá: va de arriba abajo contra el borde
     derecho. El piso en píxeles del bloque de pestañas la desbordaría por
     abajo en un teléfono acostado de 390 px de alto. */
  #detail:has(.dtabs),#detail:has(.dacts--3){min-height:0}
  /* Y sin ese piso el cromo fijo no entra: 98 de encabezado + 50 de precio +
     75 de grilla + 61 de pestañas + 117 de acciones son 401 px contra 336 de
     panel. Las acciones sueltan el `sticky`: acostado se llega a ellas
     desplazando, que es mucho mejor que taparle las pestañas al usuario. Las
     pestañas sí siguen clavadas arriba. */
  #detail .dacts{position:static}
  /* Con el ancho de sobra los dos CTA de la intro vuelven a una sola fila:
     ahorran 52 px de alto y la tarjeta entra sin scroll interno. */
  .iacts{flex-direction:row;align-items:center;flex-wrap:wrap}
}

/* --- 6. simulador en mobile: cuota, ingresos y "Ver proyección" de entrada -- */
@media (max-width:900px){
  /* El CTA se apoya en el pie del cuerpo del modal. Con el teclado numérico
     abierto el que se achica es el modal entero —vía `--vvh`, que publica
     `ui.js`—, así que el CTA acompaña y no queda tapado. */
  /* El margen negativo la lleva de borde a borde de `.mbody` (relleno 20 px) y
     también hasta el fondo: si no, un `sticky` se frena en la caja de
     contenido y queda una franja muerta de 20 px abajo del CTA. */
  #ovSim .simfoot{
    position:sticky;bottom:0;z-index:2;
    margin:12px -20px -20px;padding:10px 20px calc(10px + env(safe-area-inset-bottom,0px));
    background:var(--solid);
  }
  /* El cuerpo es lo único que scrollea y el gesto termina ahí. */
  #ovSim .mbody{overscroll-behavior:contain}
  /* Encabezado y pie del modal más ajustados. No es cosmética: con el teclado
     numérico abierto el modal se achica por `--vvh` pero el encabezado y el
     pie no, así que cada píxel que se les saca es píxel que le queda al cuerpo
     —y el cuerpo es lo que sostiene al CTA pegado abajo—. Medido en 390: el
     encabezado baja de 121 a ~105 px y el pie de 71 a ~63. */
  #ovSim .mhead{padding:13px 16px}
  #ovSim .mhead p{font-size:12.5px;line-height:1.45;margin-top:2px}
  #ovSim .mfoot{padding:10px 16px}
  /* Dos campos por fila no entran: cuota e ingresos van uno debajo del otro
     (el marcado viejo ya lo hacía con `.simgrid`; esto cubre el nuevo). */
  .simmain{gap:10px}
  /* El resumen del índice no puede robarle lugar a los dos campos. */
  .simidx{font-size:12px}
  /* La tarjeta del monto de la próxima cuota lleva la cifra a 27 px. Abajo de
     360 px "$ 1.234.567" se pasa del ancho de la tarjeta. */
  @media (max-width:360px){
    .simcard .v,.simcard--money .v{font-size:23px;letter-spacing:-.9px}
  }
  /* En 320 el acordeón de ajustes avanzados puede scrollear adentro suyo:
     es lo accesorio, y así los campos y el CTA no se mueven de lugar. */
  @media (max-height:600px){
    details.simadv[open] > :not(summary){max-height:34vh;overflow-y:auto;overscroll-behavior:contain}
    details.simdet[open] > :not(summary){max-height:38vh;overflow-y:auto;overscroll-behavior:contain}
  }
}

/* `hidden` es un atributo y pierde contra display:flex. Va al final.
   Los componentes de botón declaran su `display` con `!important` y una
   especificidad mayor, así que necesitan su propia línea: sin esto el botón
   de acción del recorrido seguía visible en los pasos que no tienen acción. */
[hidden]{display:none!important}
.button-004[hidden],.btn-bubble-arrow[hidden]{display:none!important}
