/* ==========================================================================
   Tipuana — MP360
   Capa de interfaz externa. El export de 3DVista (/360) no se toca.

   Tokens: PALETA.md
   Criterio UI/UX: DESIGN.md
   Arquitectura: MP360-CORE-SYSTEM.md
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   Prefijados --mp360-* y declarados en :root para que los consuma toda la capa.
   Los valores provienen de PALETA.md; no inventar tokens acá.
   -------------------------------------------------------------------------- */

:root {
    /* Marca — confirmados por el cliente */
    --mp360-primary: #0A3425;
    --mp360-accent: #3D6500;
    --mp360-white: #FFFFFF;

    /* Roles de superficie */
    --mp360-background: var(--mp360-white);
    --mp360-surface: var(--mp360-white);
    --mp360-surface-inverse: var(--mp360-primary);
    --mp360-overlay: #151515;
    --mp360-overlay-opacity: 0.69;

    /* Texto */
    --mp360-text: var(--mp360-primary);
    --mp360-on-primary: var(--mp360-white);
    --mp360-on-accent: var(--mp360-white);

    /*
      Tipografía — Instrument Sans, autoalojada en assets/fonts.

      Una sola familia para display, interfaz y lectura. No hay segunda voz
      tipográfica: el display de la intro es la misma Instrument Sans a gran
      escala, no otra familia.

      Sustituye a Haffer, evaluada en F4.3 y descartada en F4.4 porque los
      archivos disponibles eran TRIAL / Personal Use Only. Instrument Sans es
      SIL Open Font License, apta para uso comercial y web.

      Roboto queda detrás como red de seguridad técnica: ya está autoalojada en
      el export, así que sólo se pide si Instrument Sans fallara — o para el
      único carácter que no cubre (ver §1b).
    */
    --mp360-font: "Instrument Sans", "Roboto", system-ui, -apple-system, "Segoe UI", sans-serif;
    /* El display comparte familia; existe como token para no acoplar el
       titular de la intro a la pila de interfaz si algún día divergen. */
    --mp360-font-display: var(--mp360-font);

    /* El eje wght cubre 400–700 de forma continua; estos son los grados que
       usa la jerarquía. */
    --mp360-weight-regular: 400;
    --mp360-weight-medium: 500;
    --mp360-weight-semibold: 600;

    /* Geometría — radius pequeño, ~4px de referencia (PROJECT-PROFILE.md §13) */
    --mp360-radius: 4px;

    /* Escala de spacing de DESIGN.md §4 */
    --mp360-space-1: 4px;
    --mp360-space-2: 8px;
    --mp360-space-3: 12px;
    --mp360-space-4: 16px;
    --mp360-space-6: 24px;
    --mp360-space-8: 32px;
    --mp360-space-12: 48px;

    /* Icono de WhatsApp como máscara: hereda currentColor y escala sin raster.
       Inline, sin dependencias externas ni assets nuevos. */
    --mp360-wa-icon: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><g fill='%23000'><path d='M25.873,6.069c-2.619-2.623-6.103-4.067-9.814-4.069C8.411,2,2.186,8.224,2.184,15.874c-.001,2.446,.638,4.833,1.852,6.936l-1.969,7.19,7.355-1.929c2.026,1.106,4.308,1.688,6.63,1.689h.006c7.647,0,13.872-6.224,13.874-13.874,.001-3.708-1.44-7.193-4.06-9.815h0Zm-9.814,21.347h-.005c-2.069,0-4.099-.557-5.87-1.607l-.421-.25-4.365,1.145,1.165-4.256-.274-.436c-1.154-1.836-1.764-3.958-1.763-6.137,.003-6.358,5.176-11.531,11.537-11.531,3.08,.001,5.975,1.202,8.153,3.382,2.177,2.179,3.376,5.077,3.374,8.158-.003,6.359-5.176,11.532-11.532,11.532h0Zm6.325-8.636c-.347-.174-2.051-1.012-2.369-1.128-.318-.116-.549-.174-.78,.174-.231,.347-.895,1.128-1.098,1.359-.202,.232-.405,.26-.751,.086-.347-.174-1.464-.54-2.788-1.72-1.03-.919-1.726-2.054-1.929-2.402-.202-.347-.021-.535,.152-.707,.156-.156,.347-.405,.52-.607,.174-.202,.231-.347,.347-.578,.116-.232,.058-.434-.029-.607-.087-.174-.78-1.88-1.069-2.574-.281-.676-.567-.584-.78-.595-.202-.01-.433-.012-.665-.012s-.607,.086-.925,.434c-.318,.347-1.213,1.186-1.213,2.892s1.242,3.355,1.416,3.587c.174,.232,2.445,3.733,5.922,5.235,.827,.357,1.473,.571,1.977,.73,.83,.264,1.586,.227,2.183,.138,.666-.1,2.051-.839,2.34-1.649,.289-.81,.289-1.504,.202-1.649s-.318-.232-.665-.405h0Z' fill-rule='evenodd'></path></g></svg>");

    /*
      Motion. Un solo juego de duraciones y easings para toda la capa, para que
      paneles, drawer, dropdown y galería se sientan del mismo sistema.
      Cortas a propósito: 3DVista sigue renderizando debajo y la interfaz no
      debe competir con el recorrido ni retrasar una acción.
    */
    --mp360-dur-fast: 120ms;
    --mp360-dur-base: 180ms;
    --mp360-dur-panel: 220ms;

    /*
      Tempo del movimiento espacial (F4.5). La curva --ease-mp360-back no
      cambia; lo que cambia es el tiempo que se le da para leerse. Con
      duraciones cortas la anticipación y el overshoot se perciben como un
      tirón; alargadas, el mismo movimiento aterriza.

      El valor sube con el tamaño de lo que se mueve: un caret recorre unos
      grados, un drawer cruza media pantalla.

      Los cierres van ~20% por debajo de su apertura: entrar puede ser
      expresivo, salir tiene que quitarse de en medio.
    */
    --mp360-dur-micro: 220ms;          /* carets, chevrons: giros mínimos */
    --mp360-dur-micro-lg: 260ms;       /* burger, dots, cards: recorrido corto */
    --mp360-dur-surface: 380ms;        /* paneles, cards, modales */
    --mp360-dur-surface-out: 300ms;    /* -21% */
    --mp360-dur-drawer: 440ms;         /* superficie grande, cruza la pantalla */
    --mp360-dur-drawer-out: 340ms;     /* -23% */
    /*
      Disclosure dentro de una superficie que ya está abierta: seis filas de
      contenido, más que una microinteracción y menos que un panel entero.
    */
    --mp360-dur-disclosure: 300ms;
    --mp360-dur-disclosure-out: 260ms; /* -13% */
    --mp360-ease: cubic-bezier(0.22, 0.61, 0.36, 1);   /* salida suave, sin overshoot */
    --mp360-ease-in: cubic-bezier(0.55, 0.06, 0.68, 0.19);
    /*
      Easing de los recursos Osmo. Aparece en tres de los cuatro (botón, wipe
      e intro), así que es la firma de motion del proyecto. Se usa tal cual.
    */
    --mp360-ease-osmo: cubic-bezier(0.625, 0.05, 0, 1);

    /*
      Easing espacial de la interfaz MP360. Anticipación al arrancar y
      overshoot al llegar: es lo que le da carácter al movimiento sin
      volverlo caricaturesco.

      Se usa SÓLO para propiedades espaciales — transform, translate, scale,
      rotate. Nunca para opacity, color, filter, box-shadow ni nada binario:
      esta curva sale del rango 0–1 en Y, y en una opacidad eso significa
      valores negativos o por encima de 1, que se recortan y producen un
      parpadeo. Una misma transición puede combinar esta curva en transform y
      --mp360-ease en opacity; es el patrón correcto.

      Equivalente GSAP: CustomEase "mp360-back-inout"
      ("M0,0 C0.68,-0.7 0.32,1.7 1,1"), registrado una sola vez en boot().
      Existe además una representación linear() de la misma curva; no se
      incorpora porque el cubic-bezier resuelve todos los casos CSS.
    */
    --ease-mp360-back: cubic-bezier(0.68, -0.7, 0.32, 1.7);

    /*
      Internal state transition — cambio de contenido DENTRO de una superficie
      que ya está abierta (stepper, tabs, paginación interna…). El marco
      exterior no se reanima; sólo se mueve lo que cambia.

      Más ágil que abrir una superficie (--mp360-dur-panel, 220ms): cambiar de
      paso tiene que sentirse como respuesta, no como ceremonia.

      El recorrido es corto a propósito. La curva ya aporta anticipación y
      overshoot; con una distancia larga el conjunto se volvería caricaturesco.
    */
    --mp360-ist-dur: 280ms;
    --mp360-ist-shift: 16px;


    /* Iconos de contacto y redes como máscaras SVG inline. */
    --mp360-ico-phone: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M6.6 10.8c1.4 2.8 3.8 5.1 6.6 6.6l2.2-2.2c.3-.3.7-.4 1-.2 1.2.4 2.4.6 3.6.6.6 0 1 .4 1 1V20c0 .6-.4 1-1 1C10.6 21 3 13.4 3 4c0-.6.4-1 1-1h3.5c.6 0 1 .4 1 1 0 1.3.2 2.5.6 3.6.1.4 0 .7-.2 1l-2.3 2.2Z'/></svg>");
    --mp360-ico-mail: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20 4H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2Zm0 4.2-8 4.8-8-4.8V6l8 4.8L20 6v2.2Z'/></svg>");
    --mp360-ico-pin: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12 2a7 7 0 0 0-7 7c0 5.2 7 13 7 13s7-7.8 7-13a7 7 0 0 0-7-7Zm0 9.5a2.5 2.5 0 1 1 0-5 2.5 2.5 0 0 1 0 5Z'/></svg>");
    --mp360-ico-fb: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><g fill='%23000'><path d='M16,2c-7.732,0-14,6.268-14,14,0,6.566,4.52,12.075,10.618,13.588v-9.31h-2.887v-4.278h2.887v-1.843c0-4.765,2.156-6.974,6.835-6.974,.887,0,2.417,.174,3.043,.348v3.878c-.33-.035-.904-.052-1.617-.052-2.296,0-3.183,.87-3.183,3.13v1.513h4.573l-.786,4.278h-3.787v9.619c6.932-.837,12.304-6.74,12.304-13.897,0-7.732-6.268-14-14-14Z'></path></g></svg>");
    --mp360-ico-ig: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><g fill='%23000'><path d='M10.202,2.098c-1.49,.07-2.507,.308-3.396,.657-.92,.359-1.7,.84-2.477,1.619-.776,.779-1.254,1.56-1.61,2.481-.345,.891-.578,1.909-.644,3.4-.066,1.49-.08,1.97-.073,5.771s.024,4.278,.096,5.772c.071,1.489,.308,2.506,.657,3.396,.359,.92,.84,1.7,1.619,2.477,.779,.776,1.559,1.253,2.483,1.61,.89,.344,1.909,.579,3.399,.644,1.49,.065,1.97,.08,5.771,.073,3.801-.007,4.279-.024,5.773-.095s2.505-.309,3.395-.657c.92-.36,1.701-.84,2.477-1.62s1.254-1.561,1.609-2.483c.345-.89,.579-1.909,.644-3.398,.065-1.494,.081-1.971,.073-5.773s-.024-4.278-.095-5.771-.308-2.507-.657-3.397c-.36-.92-.84-1.7-1.619-2.477s-1.561-1.254-2.483-1.609c-.891-.345-1.909-.58-3.399-.644s-1.97-.081-5.772-.074-4.278,.024-5.771,.096m.164,25.309c-1.365-.059-2.106-.286-2.6-.476-.654-.252-1.12-.557-1.612-1.044s-.795-.955-1.05-1.608c-.192-.494-.423-1.234-.487-2.599-.069-1.475-.084-1.918-.092-5.656s.006-4.18,.071-5.656c.058-1.364,.286-2.106,.476-2.6,.252-.655,.556-1.12,1.044-1.612s.955-.795,1.608-1.05c.493-.193,1.234-.422,2.598-.487,1.476-.07,1.919-.084,5.656-.092,3.737-.008,4.181,.006,5.658,.071,1.364,.059,2.106,.285,2.599,.476,.654,.252,1.12,.555,1.612,1.044s.795,.954,1.051,1.609c.193,.492,.422,1.232,.486,2.597,.07,1.476,.086,1.919,.093,5.656,.007,3.737-.006,4.181-.071,5.656-.06,1.365-.286,2.106-.476,2.601-.252,.654-.556,1.12-1.045,1.612s-.955,.795-1.608,1.05c-.493,.192-1.234,.422-2.597,.487-1.476,.069-1.919,.084-5.657,.092s-4.18-.007-5.656-.071M21.779,8.517c.002,.928,.755,1.679,1.683,1.677s1.679-.755,1.677-1.683c-.002-.928-.755-1.679-1.683-1.677,0,0,0,0,0,0-.928,.002-1.678,.755-1.677,1.683m-12.967,7.496c.008,3.97,3.232,7.182,7.202,7.174s7.183-3.232,7.176-7.202c-.008-3.97-3.233-7.183-7.203-7.175s-7.182,3.233-7.174,7.203m2.522-.005c-.005-2.577,2.08-4.671,4.658-4.676,2.577-.005,4.671,2.08,4.676,4.658,.005,2.577-2.08,4.671-4.658,4.676-2.577,.005-4.671-2.079-4.676-4.656h0'></path></g></svg>");

    /*
      Iconografía funcional — Nucleo core / outline, trazo 1,6 (1,7 en ayuda).
      Se toman los SVG originales de la familia y sólo se les fija el trazo
      aprobado: no se redibuja ninguno. Van como máscara, igual que el resto de
      la iconografía del sistema, para que el color salga del componente.
    */
    --mp360-ico-house-pin: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M4 13V20C4 21.1046 4.89543 22 6 22H12.5' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M19 22.75C21.328 21.094 23 19.209 23 17C23 14.791 21.209 13 19 13C16.791 13 15 14.791 15 17C15 19.209 16.672 21.094 19 22.75Z' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M19 18C19.5523 18 20 17.5523 20 17C20 16.4477 19.5523 16 19 16C18.4477 16 18 16.4477 18 17C18 17.5523 18.4477 18 19 18Z' fill='%23000'></path><path d='M9 22V15H11' stroke='%23000' stroke-width='1.6' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M1.5 10.5L12 2L22.5 10.5' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path></svg>");
    --mp360-ico-rotation-360: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M17 12C17 6.47715 14.7614 2 12 2C9.23858 2 7 6.47715 7 12C7 17.5228 9.23858 22 12 22C12.8251 22 13.6036 21.6002 14.2896 20.8923' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M12 7C17.5228 7 22 9.23858 22 12C22 14.7614 17.5228 17 12 17C6.47715 17 2 14.7614 2 12C2 11.1512 2.42301 10.3518 3.16938 9.65161' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12C11 12.5523 11.4477 13 12 13Z' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path></svg>");
    --mp360-ico-blueprint: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M10 9V13' stroke='%23000' stroke-width='1.6' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M18 5L4 5C2.89543 5 2 5.89543 2 7L2 19C2 20.1046 2.89543 21 4 21L12 21' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M18 2L20 2C21.1046 2 22 2.89543 22 4L22 18.5' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' fill='none' stroke-linejoin='var(--nucleo-stroke-linejoin, miter)' stroke-linecap='var(--nucleo-stroke-linecap-butt, butt)'></path><path d='M18 2L18 16L19.5 16C20.8807 16 22 17.1193 22 18.5V18.5C22 19.8807 20.8807 21 19.5 21L12 21' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M6 17V9H14V17H10' stroke='%23000' stroke-width='1.6' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path></svg>");
    --mp360-ico-map-pin: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M15.5 8.5V6V7' stroke='%23000' stroke-width='1.6' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M8.5 2.51807V18' stroke='%23000' stroke-width='1.6' fill='none' stroke-linejoin='var(--nucleo-stroke-linejoin, miter)' stroke-linecap='var(--nucleo-stroke-linecap-butt, butt)'></path><path d='M22 9V3.5L15.5 6L8.5 2.5L2 5V20.5L8.5 18L10.5444 19.0222' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M18 21.75C20.328 20.094 22 18.209 22 16C22 13.791 20.209 12 18 12C15.791 12 14 13.791 14 16C14 18.209 15.672 20.094 18 21.75Z' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M18 17.25C18.6904 17.25 19.25 16.6904 19.25 16C19.25 15.3096 18.6904 14.75 18 14.75C17.3096 14.75 16.75 15.3096 16.75 16C16.75 16.6904 17.3096 17.25 18 17.25Z' fill='%23000'></path></svg>");
    --mp360-ico-construction-crane: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M5 5H3V9H5' stroke='%23000' stroke-width='1.6' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M19 18V9' stroke='%23000' stroke-width='1.6' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M9 9H21V6L9 5V4.5' stroke='%23000' stroke-width='1.6' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M5 21V3H9V21' stroke='%23000' stroke-width='1.6' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M3 21H11' stroke='%23000' stroke-width='1.6' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M21 18L17 18' stroke='%23000' stroke-width='1.6' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path></svg>");
    --mp360-ico-images: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M8 22L16 11L22 18' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' fill='none' stroke-linejoin='var(--nucleo-stroke-linejoin, miter)' stroke-linecap='var(--nucleo-stroke-linecap-butt, butt)'></path><path d='M20 6L4 6C2.89543 6 2 6.89543 2 8L2 20C2 21.1046 2.89543 22 4 22L20 22C21.1046 22 22 21.1046 22 20L22 8C22 6.89543 21.1046 6 20 6Z' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M4 2H20' stroke='%23000' stroke-width='1.6' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M8 14C9.10457 14 10 13.1046 10 12C10 10.8954 9.10457 10 8 10C6.89543 10 6 10.8954 6 12C6 13.1046 6.89543 14 8 14Z' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path></svg>");
    --mp360-ico-chart-trend: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M10 12H14V21H10V12Z' stroke='%23000' stroke-width='1.6' fill='none' stroke-linejoin='var(--nucleo-stroke-linejoin, miter)' stroke-linecap='var(--nucleo-stroke-linecap-butt, butt)'></path><path d='M18 8H22V21H18V8Z' stroke='%23000' stroke-width='1.6' fill='none' stroke-linejoin='var(--nucleo-stroke-linejoin, miter)' stroke-linecap='var(--nucleo-stroke-linecap-butt, butt)'></path><path d='M2 16H6V21H2V16Z' stroke='%23000' stroke-width='1.6' fill='none' stroke-linejoin='var(--nucleo-stroke-linejoin, miter)' stroke-linecap='var(--nucleo-stroke-linecap-butt, butt)'></path><path d='M2 7L6 3L10 7L15 2' stroke='%23000' stroke-width='1.6' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path></svg>");
    --mp360-ico-list-check: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M18 2L6 2C4.89543 2 4 2.89543 4 4L4 20C4 21.1046 4.89543 22 6 22L18 22C19.1046 22 20 21.1046 20 20L20 4C20 2.89543 19.1046 2 18 2Z' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M8 13L11 13' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M8 17L11 17' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M15 13L16 13' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M15 17L16 17' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M15 9L16 9' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M7.5 7.5L9 9L12 6' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path></svg>");
    --mp360-ico-office: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M21 21L21 9L13 9L13 21L21 21Z' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M9 21L9 15L3 13L3 21L9 21Z' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M16 5L16 2L8 4L8 10' stroke='%23000' stroke-width='1.6' stroke-miterlimit='10' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M17.01 13L17 13' stroke='%23000' stroke-width='1.6' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M17.01 17L17 17' stroke='%23000' stroke-width='1.6' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path><path d='M12 1V3V2.64646' stroke='%23000' stroke-width='1.6' stroke-linecap='var(--nucleo-stroke-linecap, square)' fill='none'></path></svg>");
    --mp360-ico-help-circle: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='10' fill='none' stroke='%23000' stroke-linecap='var(--nucleo-stroke-linecap, square)' stroke-miterlimit='10' stroke-width='1.7'></circle><circle cx='12' cy='17.25' r='1.25' fill='%23000' stroke-width='0'></circle><path d='m9.244,8.369c.422-1.608,1.733-2.44,3.201-2.364,1.45.075,2.799.872,2.737,2.722-.089,2.63-2.884,2.273-3.197,4.773h.011' fill='none' stroke='%23000' stroke-linecap='var(--nucleo-stroke-linecap, square)' stroke-miterlimit='10' stroke-width='1.7'></path></svg>");
    --mp360-ico-filter: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><polygon points='3 3 21 3 21 5 14 13 14 20 10 22 10 13 3 5 3 3' fill='none' stroke='%23000' stroke-linecap='var(--nucleo-stroke-linecap, square)' stroke-miterlimit='10' stroke-width='1.7'></polygon></svg>");
    --mp360-ico-info: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='10' fill='none' stroke='%23000' stroke-linecap='var(--nucleo-stroke-linecap, square)' stroke-miterlimit='10' stroke-width='1.7'></circle><path d='m12,17v-5.5c0-.276-.224-.5-.5-.5h-1.5' fill='none' stroke='%23000' stroke-linecap='var(--nucleo-stroke-linecap, square)' stroke-miterlimit='10' stroke-width='1.7'></path><circle cx='12' cy='7.25' r='1.25' fill='%23000' stroke-width='0'></circle></svg>");

    /*
      Variantes FILLED de los diez glifos del drawer (Fase 11).

      Son las variantes `glyph` REALES de Nucleo core, mismo label y mismo
      concepto que su outline — no un outline relleno por CSS ni un icono
      distinto elegido por estar lleno. Los diez tenían equivalente; no hubo
      que forzar ninguno.

      Único cambio sobre el original: `fill="currentColor"` pasa a `%23000`.
      Dentro de una máscara sólo cuenta el alfa, y un `#` sin codificar trunca
      el data-URI en silencio (ver APRENDIZAJES).
    */
    --mp360-ico-house-pin-fill: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M19 12C16.243 12 14 14.243 14 17C14 19.301 15.446 21.449 18.42 23.565L19 23.977L19.58 23.565C22.554 21.449 24 19.301 24 17C24 14.243 21.757 12 19 12ZM19 18.5C18.172 18.5 17.5 17.828 17.5 17C17.5 16.172 18.172 15.5 19 15.5C19.828 15.5 20.5 16.172 20.5 17C20.5 17.828 19.828 18.5 19 18.5Z' fill='%23000'></path><path d='M3 13.2395V19.9999C3 21.6567 4.34315 22.9999 6 22.9999H9V15H12.2907C12.9928 12.6467 14.9013 10.8098 17.2964 10.2094L12 5.87598L3 13.2395Z' fill='%23000'></path><path fill-rule='evenodd' clip-rule='evenodd' d='M11.9999 0.713379L23.9064 10.3519L22.648 11.9064L11.9999 3.28657L1.3519 11.9064L0.0935059 10.3519L11.9999 0.713379Z' fill='%23000'></path></svg>");
    --mp360-ico-rotation-360-fill: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill-rule='evenodd' clip-rule='evenodd' d='M9.35889 5.37615C8.53713 7.01967 8 9.36016 8 12C8 14.6398 8.53713 16.9803 9.35889 18.6239C10.2106 20.3272 11.2021 21 12 21C12.4786 21 13.0135 20.7722 13.5714 20.1964L14.2673 19.4783L15.7036 20.87L15.0077 21.5882C14.1937 22.4283 13.1717 23 12 23C10.0365 23 8.52801 21.4342 7.57004 19.5183C6.58216 17.5425 6 14.883 6 12C6 9.11699 6.58216 6.45748 7.57004 4.48172C8.52801 2.56577 10.0365 1 12 1C13.9635 1 15.472 2.56577 16.43 4.48172C17.4178 6.45748 18 9.11699 18 12V13H16V12C16 9.36016 15.4629 7.01967 14.6411 5.37615C13.7894 3.67281 12.7979 3 12 3C11.2021 3 10.2106 3.67281 9.35889 5.37615Z' fill='%23000'></path><path fill-rule='evenodd' clip-rule='evenodd' d='M18.6239 9.35889C16.9803 8.53713 14.6398 8 12 8L11 8L11 6L12 6C14.883 6 17.5425 6.58216 19.5183 7.57004C21.4342 8.52801 23 10.0365 23 12C23 13.9635 21.4342 15.472 19.5183 16.43C17.5425 17.4178 14.883 18 12 18C9.11699 18 6.45748 17.4178 4.48172 16.43C2.56577 15.472 1 13.9635 1 12C1 10.7942 1.60488 9.74813 2.4852 8.9223L3.21451 8.23812L4.58287 9.69674L3.85356 10.3809C3.24114 10.9554 3 11.5082 3 12C3 12.7979 3.67281 13.7894 5.37615 14.6411C7.01967 15.4629 9.36016 16 12 16C14.6398 16 16.9803 15.4629 18.6239 14.6411C20.3272 13.7894 21 12.7979 21 12C21 11.2021 20.3272 10.2106 18.6239 9.35889Z' fill='%23000'></path><path fill-rule='evenodd' clip-rule='evenodd' d='M10 12C10 10.8954 10.8954 10 12 10C13.1046 10 14 10.8954 14 12C14 13.1046 13.1046 14 12 14C10.8954 14 10 13.1046 10 12Z' fill='%23000'></path></svg>");
    --mp360-ico-blueprint-fill: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M9 8H11V14H9V8Z' fill='%23000'></path><path fill-rule='evenodd' clip-rule='evenodd' d='M4 22C2.34315 22 1 20.6569 1 19L0.999999 7C0.999999 5.34315 2.34315 4 4 4L17 4L17 1L20 0.999999C21.6569 0.999999 23 2.34314 23 4L23 18.5C23 20.433 21.433 22 19.5 22L4 22ZM19.5 20C20.3284 20 21 19.3284 21 18.5C21 17.6716 20.3284 17 19.5 17L17 17L17 6L4 6C3.44772 6 3 6.44772 3 7L3 19C3 19.5523 3.44772 20 4 20L19.5 20Z' fill='%23000'></path><path d='M5 8H15V18H9V16H13V10H7V18H5V8Z' fill='%23000'></path></svg>");
    --mp360-ico-map-pin-fill: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 2.00562L1 4.31331V21.9561L7 19.6484V2.00562Z' fill='%23000'></path><path d='M18 11C15.243 11 13 13.243 13 16C13 18.301 14.446 20.449 17.42 22.565L18 22.977L18.58 22.565C21.554 20.449 23 18.301 23 16C23 13.243 20.757 11 18 11ZM18 17.5C17.172 17.5 16.5 16.828 16.5 16C16.5 15.172 17.172 14.5 18 14.5C18.828 14.5 19.5 15.172 19.5 16C19.5 16.828 18.828 17.5 18 17.5Z' fill='%23000'></path><path d='M13.1985 21.4674L9 19.3681V1.63208L15 4.63208L15 9.6754C12.6365 10.8003 11 13.2117 11 16.0001C11 18.037 11.8114 19.8446 13.1985 21.4674Z' fill='%23000'></path><path d='M23 11.1043V2.04395L17 4.35164L17 9.0711C17.3267 9.02423 17.6605 8.99998 18 8.99998C19.9573 8.99998 21.7288 9.80627 23 11.1043Z' fill='%23000'></path></svg>");
    --mp360-ico-construction-crane-fill: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill-rule='evenodd' clip-rule='evenodd' d='M20 7V18H18V7H20Z' fill='%23000'></path><path fill-rule='evenodd' clip-rule='evenodd' d='M4.31653 3.63245L22 5.0742V8.00001L4.31663 8L4.31653 3.63245Z' fill='%23000'></path><path fill-rule='evenodd' clip-rule='evenodd' d='M4 2H9V21H4V2Z' fill='%23000'></path><path fill-rule='evenodd' clip-rule='evenodd' d='M2 20H11V22H2V20Z' fill='%23000'></path><path fill-rule='evenodd' clip-rule='evenodd' d='M4 4V8H2V4H4Z' fill='%23000'></path><path fill-rule='evenodd' clip-rule='evenodd' d='M22 19L16 19L16 17L22 17L22 19Z' fill='%23000'></path></svg>");
    --mp360-ico-images-fill: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M6.76355 22L15.9357 10L22 16.4634L22 20.5L20.5 22H6.76355Z' fill='%23000'></path><path fill-rule='evenodd' clip-rule='evenodd' d='M1 8C1 6.34315 2.34315 5 4 5L20 5C21.6569 5 23 6.34315 23 8L23 20C23 21.6569 21.6569 23 20 23L4 23C2.34315 23 1 21.6569 1 20L1 8ZM4 7C3.44772 7 3 7.44772 3 8L3 20C3 20.5523 3.44772 21 4 21L20 21C20.5523 21 21 20.5523 21 20L21 8C21 7.44772 20.5523 7 20 7L4 7Z' fill='%23000'></path><path fill-rule='evenodd' clip-rule='evenodd' d='M3 1H21V3H3V1Z' fill='%23000'></path><path d='M8 14.5C9.38071 14.5 10.5 13.3807 10.5 12C10.5 10.6193 9.38071 9.5 8 9.5C6.61929 9.5 5.5 10.6193 5.5 12C5.5 13.3807 6.61929 14.5 8 14.5Z' fill='%23000'></path></svg>");
    --mp360-ico-chart-trend-fill: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M10 11H14V22H10V11Z' fill='%23000'></path><path d='M18 7H22V22H18V7Z' fill='%23000'></path><path d='M2 15H6V22H2V15Z' fill='%23000'></path><path fill-rule='evenodd' clip-rule='evenodd' d='M16.4142 2L10 8.41421L6 4.41421L2 8.41421L0.585785 7L6 1.58578L10 5.58579L15 0.585785L16.4142 2Z' fill='%23000'></path></svg>");
    --mp360-ico-list-check-fill: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill-rule='evenodd' clip-rule='evenodd' d='M21 4C21 2.34315 19.6569 1 18 1H6C4.34315 1 3 2.34315 3 4V20C3 21.6569 4.34314 23 6 23H18C19.6569 23 21 21.6569 21 20V4ZM7 14V12H12V14H7ZM7 16V18H12V16H7ZM14 12H17V14H14V12ZM14 16V18H17V16H14ZM14 8H17V10H14V8ZM13.4142 6L12 4.58579L9 7.58579L7.5 6.08579L6.08579 7.5L9 10.4142L13.4142 6Z' fill='%23000'></path></svg>");
    --mp360-ico-office-fill: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill-rule='evenodd' clip-rule='evenodd' d='M13 0V3H11V0H13Z' fill='%23000'></path><path fill-rule='evenodd' clip-rule='evenodd' d='M22 22L22 8H12V22H22ZM18.01 12H16L16 14H18.01V12ZM16 18L16 16L18.01 16L18.01 18L16 18Z' fill='%23000'></path><path d='M7 3.21924L17 0.719238V6H12C10.8954 6 10 6.89543 10 8V12.171L7 11.171V3.21924Z' fill='%23000'></path><path fill-rule='evenodd' clip-rule='evenodd' d='M2 11.6125L10 14.2792L10 22H2V11.6125ZM7.01001 16V18H5.00001V16H7.01001Z' fill='%23000'></path></svg>");
    --mp360-ico-help-circle-fill: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='m12,1C5.935,1,1,5.935,1,12s4.935,11,11,11,11-4.935,11-11S18.065,1,12,1Zm0,17.5c-.689,0-1.25-.561-1.25-1.25s.561-1.25,1.25-1.25,1.25.561,1.25,1.25-.561,1.25-1.25,1.25Zm2.19-6.482c-.702.518-1.087.829-1.2,1.515l.005.968h-2.133l.13-1.124c.205-1.639,1.25-2.407,2.014-2.969.774-.57,1.148-.881,1.177-1.715.044-1.317-.948-1.646-1.788-1.688-1.092-.059-1.901.549-2.184,1.619l-.253.967-1.935-.507.254-.968c.522-1.995,2.18-3.218,4.22-3.109,2.311.119,3.757,1.593,3.684,3.755-.062,1.839-1.176,2.659-1.99,3.257Z' fill='%23000'></path></svg>");

    /*
      Cerrar. Un solo recurso para TODOS los controles de cierre del sistema
      —superficies, drawer, navegador de plan, filtros y avisos—, que antes
      eran tres dibujos CSS distintos con la misma intención. Geometría Nucleo
      core/outline sin redibujar: las dos líneas 5→19 del original, con el
      trazo del sistema.
    */
    --mp360-ico-close: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><line x1='19' y1='19' x2='5' y2='5' fill='none' stroke='%23000' stroke-linecap='var(--nucleo-stroke-linecap, square)' stroke-miterlimit='10' stroke-width='1.7'></line><line x1='19' y1='5' x2='5' y2='19' fill='none' stroke='%23000' stroke-linecap='var(--nucleo-stroke-linecap, square)' stroke-miterlimit='10' stroke-width='1.7'></line></svg>");

    /*
      Agendar visita. La ENTRADA al flujo es una intención —coordinar una
      visita—, no un canal: por eso calendario y no WhatsApp. El envío final
      sigue siendo por WhatsApp y ahí el canal sí se nombra.
    */
    --mp360-ico-visit: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><line x1='2' y1='9' x2='22' y2='9' fill='none' stroke='%23000' stroke-linecap='var(--nucleo-stroke-linecap, square)' stroke-miterlimit='10' stroke-width='1.7'></line><line x1='7' y1='1' x2='7' y2='4' fill='none' stroke='%23000' stroke-linecap='var(--nucleo-stroke-linecap, square)' stroke-miterlimit='10' stroke-width='1.7'></line><line x1='17' y1='1' x2='17' y2='4' fill='none' stroke='%23000' stroke-linecap='var(--nucleo-stroke-linecap, square)' stroke-miterlimit='10' stroke-width='1.7'></line><path d='m22,11.5v-5.5c0-1.105-.895-2-2-2H4c-1.105,0-2,.895-2,2v12c0,1.105.895,2,2,2h5' fill='none' stroke='%23000' stroke-linecap='var(--nucleo-stroke-linecap, square)' stroke-miterlimit='10' stroke-width='1.7'></path><polyline points='13 19.5 15.5 22 22 15.5' fill='none' stroke='%23000' stroke-linecap='var(--nucleo-stroke-linecap, square)' stroke-miterlimit='10' stroke-width='1.7'></polyline></svg>");

    /* Safe areas */
    --mp360-safe-top: env(safe-area-inset-top, 0px);
    --mp360-safe-right: env(safe-area-inset-right, 0px);
    --mp360-safe-bottom: env(safe-area-inset-bottom, 0px);
    --mp360-safe-left: env(safe-area-inset-left, 0px);
}

/* --------------------------------------------------------------------------
   1b. Faces tipográficas — Instrument Sans

   Origen oficial: google/fonts, carpeta OFL `ofl/instrumentsans`.
   Diseño de Rodrigo Fuenzalida y Jordan Egstad; upstream en
   github.com/Instrument/instrument-sans. Licencia SIL Open Font License 1.1,
   copiada en assets/fonts/instrument-sans/OFL.txt. Apta para uso comercial y
   web. Servida desde el propio dominio: sin fonts.googleapis.com ni
   fonts.gstatic.com en runtime.

   UN SOLO ARCHIVO, y es una decisión medida. El original es un variable font
   de dos ejes (`wdth` 75–100, `wght` 400–700). De ahí se construye el .woff2
   servido:

     · se fija `wdth` a 100 —la interfaz nunca condensa— y se conserva `wght`
       variable de 400 a 700;
     · se subsetea a Latin (U+0000–024F) más puntuación, monedas y los signos
       que la interfaz usa: − ° · — “ ”.

   Resultado: 194 KB TTF → 29 KB WOFF2, cubriendo TODOS los pesos de la
   jerarquía en una sola petición. Tres faces estáticas equivalentes habrían
   pesado más y costado tres requests, así que acá la variable gana clara.

   La itálica oficial existe pero no se descarga: la experiencia no usa
   cursiva en ningún punto.

   Salvedad conocida: Instrument Sans no incluye `²` (U+00B2), que aparece una
   vez en el copy aprobado ("Lotes desde 450 m²"). Ese carácter cae en Roboto
   por fallback normal del navegador —local, ya autoalojada en el export— y a
   tamaño de superíndice la diferencia no es perceptible. No se altera el copy
   ni se sintetiza el glifo.
   -------------------------------------------------------------------------- */

@font-face {
    font-family: "Instrument Sans";
    src: url("assets/fonts/derived/instrument-sans-var.woff2") format("woff2-variations"),
         url("assets/fonts/derived/instrument-sans-var.woff2") format("woff2");
    /* Rango del eje: el navegador interpola 400, 500, 600 y 700 de este mismo
       archivo. Declararlo mal haría que sintetizara pesos. */
    font-weight: 400 700;
    font-style: normal;
    font-display: swap;
}

/* Roboto: sigue declarada como fallback. Ya está autoalojada en el export, y
   al ir detrás de Instrument Sans en la pila sólo se pide si ésta fallara o
   para un carácter que no cubra. No se agrega ninguna dependencia externa. */
@font-face {
    font-family: "Roboto";
    src: url("360/fonts/Roboto Regular.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "Roboto";
    src: url("360/fonts/Roboto Bold.woff2") format("woff2");
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

/* --------------------------------------------------------------------------
   2. Base
   -------------------------------------------------------------------------- */

* {
    box-sizing: border-box;
}

html,
body {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;
    background: var(--mp360-primary);
    font-family: var(--mp360-font);
    font-weight: var(--mp360-weight-regular);
    color: var(--mp360-text);
    -webkit-text-size-adjust: 100%;
    /*
      Sólo existen las faces registradas arriba. Sin esto, un `font-weight`
      sin face —700 heredado de un h2, por ejemplo— haría que el navegador
      falsee el trazo, y una cursiva accidental se inclinaría por software.
      La experiencia no usa cursiva en ningún punto: nunca sintetizarla.
    */
    font-synthesis: none;
    -webkit-font-synthesis: none;
}

/* --------------------------------------------------------------------------
   3. Estructura wrapper / motor

   .mp360-app      contenedor raíz; usa dvh para no pelear con el chrome móvil
   .mp360-tour     iframe del export 3DVista — ocupa siempre el 100%
   .mp360-root     capa de interfaz MP360, por encima del motor
   -------------------------------------------------------------------------- */

.mp360-app {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
}

.mp360-tour {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
    display: block;
    z-index: 1;
}

/*
  La capa de UI cubre el viewport pero es transparente al puntero: el tour debe
  seguir siendo arrastrable en todo el espacio que la UI no ocupe realmente.
  Cada componente de F2 en adelante reactiva pointer-events sobre sí mismo.
*/
.mp360-root {
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
}

.mp360-root > * {
    pointer-events: auto;
}

/* --------------------------------------------------------------------------
   4. Navbar (F2)

   Layout canónico MP360: la navbar ocupa la franja superior y las acciones
   globales viven en ella. El resto del viewport queda para el panorama.

   Colapsa a drawer por debajo de 1200px: con 6 ítems centrales más dos CTA,
   comprimir tipografía o targets rompería DESIGN.md §4 y §7 antes que el
   layout. Se transforma la composición en vez de apretarla.
   -------------------------------------------------------------------------- */

[hidden] {
    display: none !important;
}

.mp360-navbar {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--mp360-space-4);
    height: 72px;
    padding: 0 var(--mp360-space-6);
    padding-left: max(var(--mp360-space-6), var(--mp360-safe-left));
    padding-right: max(var(--mp360-space-6), var(--mp360-safe-right));
    background: var(--mp360-background);
    box-shadow: 0 1px 3px rgba(10, 52, 37, 0.12);
    font-family: var(--mp360-font);
}

.mp360-navbar__left,
.mp360-navbar__right {
    display: flex;
    align-items: center;
    gap: var(--mp360-space-4);
    flex: 0 0 auto;
}

.mp360-navbar__center {
    display: flex;
    align-items: center;
    gap: var(--mp360-space-2);
    flex: 1 1 auto;
    justify-content: center;
    min-width: 0;
}

.mp360-navbar__divider {
    width: 1px;
    height: 32px;
    background: rgba(10, 52, 37, 0.18);
}

/* --- logo --- */

.mp360-logo {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* El área tocable puede superar el tamaño visible del logo (DESIGN.md §7). */
    min-width: 44px;
    min-height: 44px;
    padding: var(--mp360-space-1);
    border: 0;
    background: none;
    cursor: pointer;
    border-radius: var(--mp360-radius);
}

/*
  El PNG de marca es de 443×269 y no hay SVG. Se limita el alto para no
  superar su resolución nativa (nítido hasta ~220px de ancho a 2× DPR) y se
  usa contain para no deformarlo nunca.
*/
.mp360-logo__img {
    display: block;
    height: 44px;
    width: auto;
    max-width: 140px;
    object-fit: contain;
}

/* --- links centrales --- */

.mp360-nav__link {
    display: inline-flex;
    align-items: center;
    gap: var(--mp360-space-1);
    min-height: 44px;
    padding: 0 var(--mp360-space-3);
    border: 0;
    border-radius: var(--mp360-radius);
    background: none;
    color: var(--mp360-text);
    font-family: inherit;
    font-size: 16px;
    font-weight: var(--mp360-weight-medium);
    line-height: 1.2;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-nav__link:hover,
.mp360-nav__link.is-open {
    background: rgba(10, 52, 37, 0.07);
}

.mp360-nav__link:active {
    background: rgba(10, 52, 37, 0.12);
}

.mp360-caret {
    width: 0;
    height: 0;
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
    border-top: 6px solid currentColor;
    transition: transform var(--mp360-dur-micro) var(--ease-mp360-back);
}

.mp360-nav__link.is-open .mp360-caret {
    transform: rotate(180deg);
}

/* --- CTAs --- */

/* --------------------------------------------------------------------------
   CTA — Osmo "Button with CSS Character Stagger"

   Mecánica del recurso, conservada: fondo independiente que se contrae con
   `inset`, texto partido carácter por carácter que sube usando `text-shadow`
   como segunda copia, stagger por `transition-delay` y el easing del recurso.

   Adaptado: colores Tipuana, radius 4px en vez de .25em, y feedback :active
   para touch, porque el original depende sólo de :hover.
   -------------------------------------------------------------------------- */

.mp360-cta {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--mp360-space-2);
    min-height: 44px;
    padding: 0 var(--mp360-space-4);
    border: 0;
    border-radius: var(--mp360-radius);
    background: none;
    font-family: inherit;
    font-size: 16px;
    /* Rol D. SemiBold separa la acción comercial de la navegación, que va en
       Medium, sin recurrir a Bold. */
    font-weight: var(--mp360-weight-semibold);
    /*
      AJUSTE MÉTRICO POR INSTRUMENT SANS (F4.4).

      El recurso Osmo recorta el texto con `overflow: hidden` y lo desplaza una
      distancia fija, dejando una copia hecha con `text-shadow` esperando justo
      debajo del recorte. Para que funcione hacen falta dos cosas:

          altura del glifo  ≤  caja recortante  <  recorrido

      Instrument Sans tiene ascendente + descendente de 1.220 em —más que
      Roboto (1.172) y que Haffer (1.190)—, y medido en runtime ocupa 1.262 em
      reales. Con el `line-height: 1.2` original la caja quedaba en 1.2 em y
      recortaba 1 px por arriba: se comía la punta de mayúsculas y tildes.

      Se sube la caja a 1.28 em y el recorrido a 1.45 em. Es un ajuste de
      métrica, no de coreografía: el easing, la duración, el stagger por
      carácter y la naturaleza de la animación quedan intactos.
    */
    --mp360-cta-travel: 1.45em;
    line-height: 1.28;
    white-space: nowrap;
    cursor: pointer;
}

/* Fondo independiente del recurso Osmo. */
.mp360-cta__bg {
    position: absolute;
    inset: 0;
    border-radius: var(--mp360-radius);
    transition: inset 0.6s var(--mp360-ease-osmo);
}

.mp360-cta:hover .mp360-cta__bg,
.mp360-cta:focus-visible .mp360-cta__bg { inset: 2px; }

/* En touch no hay hover: el mismo gesto se resuelve con :active. */
.mp360-cta:active .mp360-cta__bg { inset: 3px; }

/* El contenido va por encima del fondo. */
.mp360-cta > *:not(.mp360-cta__bg) { position: relative; z-index: 1; }

/*
  Caracteres.

  El efecto se comparte con "Volver al inicio" (.mp360-home) extendiendo estos
  mismos selectores en lugar de escribir una segunda versión: misma mecánica de
  split, mismo recorte, mismo easing Osmo y mismos estados. Lo que no se
  comparte es la jerarquía — el color, el tamaño y el peso los define cada
  componente por su cuenta.
*/
.mp360-cta [data-button-animate-chars],
.mp360-home [data-button-animate-chars] {
    overflow: hidden;
    position: relative;
    display: inline-block;
}

/* La copia y el desplazamiento comparten el mismo valor: si divergen, o se ve
   la copia asomando, o el carácter no termina de recorrer su altura. */
.mp360-cta [data-button-animate-chars] span,
.mp360-home [data-button-animate-chars] span {
    display: inline-block;
    position: relative;
    text-shadow: 0px var(--mp360-cta-travel) currentColor;
    transform: translateY(0em) rotate(0.001deg);
    /* Easing propio del recurso Osmo: no se sustituye por el token espacial. */
    transition: transform 0.6s var(--mp360-ease-osmo);
}

.mp360-cta:hover [data-button-animate-chars] span,
.mp360-cta:focus-visible [data-button-animate-chars] span,
.mp360-cta:active [data-button-animate-chars] span,
.mp360-home:hover [data-button-animate-chars] span,
.mp360-home:focus-visible [data-button-animate-chars] span,
.mp360-home:active [data-button-animate-chars] span {
    transform: translateY(calc(-1 * var(--mp360-cta-travel))) rotate(0.001deg);
}

/* CTA principal — 13.72:1 */
.mp360-cta--primary { color: var(--mp360-on-primary); }
.mp360-cta--primary .mp360-cta__bg { background: var(--mp360-primary); }

/* CTA de contacto — 6.86:1. Sustituye al naranja #F58634, que daba 2.52:1. */
.mp360-cta--accent { color: var(--mp360-on-accent); }
.mp360-cta--accent .mp360-cta__bg { background: var(--mp360-accent); }

.mp360-cta__dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--mp360-accent);
}

/*
  Métrica compartida por todos los iconos de CTA: lo único que cambia entre
  uno y otro es la máscara. Antes "accent" implicaba WhatsApp por
  construcción, lo que confundía la jerarquía del botón con el canal de la
  acción.
*/
.mp360-cta__icon--wa,
.mp360-cta__icon--visit {
    width: 20px;
    height: 20px;
    flex: 0 0 auto;
    background: currentColor;
}

.mp360-cta__icon--wa {
    -webkit-mask: var(--mp360-wa-icon) center / contain no-repeat;
    mask: var(--mp360-wa-icon) center / contain no-repeat;
}

/* Agendar visita: la intención de coordinar, no el canal por el que se envía. */
.mp360-cta__icon--visit {
    -webkit-mask: var(--mp360-ico-visit) center / contain no-repeat;
    mask: var(--mp360-ico-visit) center / contain no-repeat;
}

/* --- dropdown --- */

.mp360-nav__dropdown-wrap {
    position: relative;
    display: inline-flex;
}

.mp360-dropdown {
    position: absolute;
    top: calc(100% + var(--mp360-space-2));
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    gap: var(--mp360-space-6);
    padding: var(--mp360-space-4);
    background: var(--mp360-surface);
    border-radius: var(--mp360-radius);
    box-shadow: 0 6px 20px rgba(10, 52, 37, 0.20);
    z-index: 10;
}

.mp360-dropdown__col {
    min-width: 180px;
}

.mp360-dropdown__title {
    margin: 0 0 var(--mp360-space-2);
    padding: 0 var(--mp360-space-2);
    font-size: 14px;
    font-weight: var(--mp360-weight-medium);
    color: var(--mp360-primary);
    opacity: 0.72;
}

.mp360-dropdown__list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.mp360-dropdown__item {
    display: block;
    width: 100%;
    min-height: 44px;
    padding: 0 var(--mp360-space-2);
    border: 0;
    border-radius: var(--mp360-radius);
    background: none;
    color: var(--mp360-text);
    font-family: inherit;
    font-size: 15px;
    font-weight: var(--mp360-weight-medium);
    text-align: left;
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-dropdown__item:hover { background: rgba(10, 52, 37, 0.07); }

/* --- botón de icono (ayuda) --- */

.mp360-iconbtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border: 1px solid rgba(10, 52, 37, 0.18);
    border-radius: var(--mp360-radius);
    background: none;
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease),
                border-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-iconbtn:hover { background: rgba(10, 52, 37, 0.07); border-color: rgba(10, 52, 37, 0.35); }
.mp360-iconbtn:active { background: rgba(10, 52, 37, 0.12); }

/*
  Ayuda. Era el carácter "?" de la tipografía de interfaz: se leía como texto
  suelto al lado de un símbolo, no como un control. Pasa al mismo mecanismo de
  máscara que WhatsApp, con el que comparte fila.
*/
.mp360-iconbtn--help .mp360-iconbtn__glyph {
    display: block;
    width: 20px;
    height: 20px;
    background: var(--mp360-primary);
    -webkit-mask: var(--mp360-ico-help-circle) center / contain no-repeat;
            mask: var(--mp360-ico-help-circle) center / contain no-repeat;
}

/* --- hamburguesa --- */

.mp360-burger {
    display: none;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border: 0;
    border-radius: var(--mp360-radius);
    background: none;
    cursor: pointer;
}

.mp360-burger__bars,
.mp360-burger__bars::before,
.mp360-burger__bars::after {
    display: block;
    width: 22px;
    height: 2px;
    background: var(--mp360-primary);
    transition: transform var(--mp360-dur-micro-lg) var(--ease-mp360-back),
                opacity var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-burger__bars { position: relative; }

.mp360-burger__bars::before,
.mp360-burger__bars::after { content: ""; position: absolute; left: 0; }
.mp360-burger__bars::before { top: -7px; }
.mp360-burger__bars::after { top: 7px; }

.mp360-burger.is-open .mp360-burger__bars { background: transparent; }
.mp360-burger.is-open .mp360-burger__bars::before { transform: translateY(7px) rotate(45deg); }
.mp360-burger.is-open .mp360-burger__bars::after { transform: translateY(-7px) rotate(-45deg); }

/* --------------------------------------------------------------------------
   Drawer

   El skin resolvía el menú mobile con una pila de rectángulos del mismo peso.
   Acá hay tres niveles de lectura: rótulo de sección, fila de navegación y
   pie con las dos acciones comerciales, que no scrollea para seguir siendo
   alcanzable con el pulgar.
   -------------------------------------------------------------------------- */

.mp360-drawer {
    position: absolute;
    inset: 0;
    z-index: 9;
}

.mp360-drawer__scrim {
    position: absolute;
    inset: 0;
    background: var(--mp360-overlay);
    opacity: 0;
    transition: opacity var(--mp360-dur-panel) var(--mp360-ease);
}

.mp360-drawer.is-open .mp360-drawer__scrim { opacity: 0.55; }

.mp360-drawer__panel {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(340px, 86vw);
    /*
      El panel llega hasta el borde derecho a propósito —el fondo tiene que
      cubrirlo—, así que el inset lateral va como padding del contenido y no
      como offset. En apaisado ese borde puede ser el del notch.
    */
    padding-right: var(--mp360-safe-right);
    display: flex;
    flex-direction: column;
    background: var(--mp360-surface);
    box-shadow: -8px 0 32px rgba(10, 52, 37, 0.28);
    transform: translateX(100%);
    /*
      Sin overshoot. El drawer usaba `--ease-mp360-back`, la curva con
      anticipación y rebote, y en un panel que cruza la pantalla entera eso no
      se lee como carácter sino como un golpe: la superficie pasa de largo y
      vuelve. Esa curva sigue siendo la correcta para lo que recorre poco —un
      caret, un dot, un chevron—, donde el rebote se percibe como elasticidad.

      Acá va `--mp360-ease`, la salida suave sin overshoot que ya existe en el
      sistema. Las duraciones no se tocaron: 440ms de entrada y 340ms de salida
      ya estaban en el rango correcto, y el cierre ya era un 23 % más rápido.
    */
    transition: transform var(--mp360-dur-drawer-out) var(--mp360-ease);
}

.mp360-drawer.is-open .mp360-drawer__panel {
    transform: translateX(0);
    transition-duration: var(--mp360-dur-drawer);
}

.mp360-drawer__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--mp360-space-3);
    padding: var(--mp360-space-3) var(--mp360-space-4);
    padding-top: max(var(--mp360-space-3), var(--mp360-safe-top));
    border-bottom: 1px solid rgba(10, 52, 37, 0.12);
}

/* Rótulo discreto: el drawer no vuelve a identificar la marca. */
.mp360-drawer__caption {
    margin: 0;
    font-size: 13px;
    font-weight: var(--mp360-weight-medium);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--mp360-primary);
    opacity: 0.5;
}

.mp360-drawer__close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border: 0;
    border-radius: var(--mp360-radius);
    background: none;
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-drawer__close:hover { background: rgba(10, 52, 37, 0.07); }

/* --------------------------------------------------------------------------
   GLIFO DE CIERRE — uno solo para todo el sistema

   Antes había tres dibujos distintos de la misma X: dos pseudo-elementos en
   `surface`/`drawer` (18px, trazo 2px), otro par en el navegador de plan
   (13px, trazo 1,5px) y ningún criterio que explicara la diferencia. Una X
   repetida por toda la interfaz es un icono, no una decoración: pasa a ser
   parte del sistema Nucleo como el resto.

   El botón que lo contiene no cambia — ni tamaño, ni superficie táctil, ni
   `aria-label`, ni foco, ni hover, ni posición—. Lo único que cambia es la
   geometría, y sale de un único recurso: `--mp360-ico-close`.

   POR QUÉ 22px Y NO 20. La caja de la máscara no es la tinta: en el original
   Nucleo la X ocupa 14 de 24 unidades, así que a 22px mide 12,8px, que es
   exactamente lo que medía el glifo CSS anterior. A 20px habría quedado más
   chica que lo que el usuario ya conocía sin ninguna razón de diseño.
   -------------------------------------------------------------------------- */

.mp360-close-glyph {
    display: block;
    flex: 0 0 auto;
    width: var(--mp360-close-size, 22px);
    height: var(--mp360-close-size, 22px);
    background: currentColor;
    -webkit-mask: var(--mp360-ico-close) center / contain no-repeat;
            mask: var(--mp360-ico-close) center / contain no-repeat;
}

.mp360-drawer__close { color: var(--mp360-primary); }

.mp360-drawer__scroll {
    flex: 1 1 auto;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    padding: var(--mp360-space-2) var(--mp360-space-3) var(--mp360-space-4);
}

.mp360-drawer__section + .mp360-drawer__section { margin-top: var(--mp360-space-6); }

.mp360-drawer__eyebrow {
    margin: 0 0 var(--mp360-space-1);
    padding: 0 var(--mp360-space-2);
    font-size: 12px;
    font-weight: var(--mp360-weight-medium);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--mp360-primary);
    opacity: 0.55;
}

/*
  Fila de navegación: texto, no bloque. La marca izquierda aparece al
  interactuar y da el feedback táctil sin necesidad de un fondo pesado.
*/
.mp360-drawer__row {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--mp360-space-2);
    width: 100%;
    min-height: 48px;
    padding: 0 var(--mp360-space-2);
    border: 0;
    border-radius: var(--mp360-radius);
    background: none;
    color: var(--mp360-text);
    font-family: inherit;
    font-size: 16px;
    font-weight: var(--mp360-weight-medium);
    text-align: left;
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-drawer__row::before {
    content: "";
    position: absolute;
    left: 0;
    top: 50%;
    width: 3px;
    height: 0;
    background: var(--mp360-accent);
    border-radius: 0 2px 2px 0;
    transform: translateY(-50%);
    transition: height var(--mp360-dur-base) var(--mp360-ease);
}

.mp360-drawer__row:hover { background: rgba(10, 52, 37, 0.06); }
.mp360-drawer__row:hover::before,
.mp360-drawer__row:active::before,
.mp360-drawer__row.is-open::before { height: 22px; }
.mp360-drawer__row:active { background: rgba(10, 52, 37, 0.11); }

/*
  Glifo de la fila. Diez filas de texto plano se escanean por lectura; con una
  columna de símbolos se escanean por reconocimiento. Cubre las diez: una
  columna incompleta se lee como error, no como jerarquía.

  20 px y no 24: la fila mide 48 con texto de 16, y a 24 el símbolo compite con
  la palabra en vez de anticiparla. Opacidad 0,6 para que guíe sin dominar.
*/
/*
  DOS CAPAS, UNA ENCIMA DE LA OTRA (Fase 11).

  Una máscara no se puede interpolar de una geometría a otra, así que el paso
  outline → filled no es una transición de `mask-image`: son dos capas
  superpuestas que se cruzan en opacidad. El span deja de pintar por sí mismo y
  pasa a ser sólo la caja que las contiene.

  Se cruzan en direcciones opuestas —la de outline se va mientras la de filled
  llega— para que en ningún fotograma se vean las dos sumadas, que es lo que
  ensuciaría el trazo.
*/
.mp360-drawer__row-ico {
    position: relative;
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    opacity: 0.6;
}

.mp360-drawer__row-ico::before,
.mp360-drawer__row-ico::after {
    content: "";
    position: absolute;
    inset: 0;
    background: currentColor;
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    /* 220ms del Motion System: inmediato pero no brusco. */
    transition: opacity var(--mp360-dur-panel) var(--mp360-ease);
}

.mp360-drawer__row-ico::before {
    -webkit-mask-image: var(--mp360-ico-outline);
    mask-image: var(--mp360-ico-outline);
    opacity: 1;
}

.mp360-drawer__row-ico::after {
    -webkit-mask-image: var(--mp360-ico-filled);
    mask-image: var(--mp360-ico-filled);
    opacity: 0;
}

/*
  El press es el ÚNICO estado que enciende el relleno.

  No hay estado "sección activa" en este drawer, y no es un olvido: abrir una
  Surface cierra el drawer y abrir el drawer cierra la Surface —son
  mutuamente excluyentes por `UI.closeAll()`—, así que no existe un momento en
  el que el menú pueda mostrar cuál es la sección vigente. Marcar un ítem como
  activo sería un estado que nadie llega a ver y un `aria-current` que miente.
*/
.mp360-drawer__row.is-pressed .mp360-drawer__row-ico::before { opacity: 0; }
.mp360-drawer__row.is-pressed .mp360-drawer__row-ico::after  { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
    .mp360-drawer__row-ico::before,
    .mp360-drawer__row-ico::after { transition: none; }
}

/* La etiqueta toma el espacio libre para que el chevron siga a la derecha. */
.mp360-drawer__row-label { flex: 1 1 auto; }

.mp360-drawer__row-ico--lotes      { --mp360-ico-outline: var(--mp360-ico-house-pin); --mp360-ico-filled: var(--mp360-ico-house-pin-fill); }
.mp360-drawer__row-ico--vistas     { --mp360-ico-outline: var(--mp360-ico-rotation-360); --mp360-ico-filled: var(--mp360-ico-rotation-360-fill); }
.mp360-drawer__row-ico--plano      { --mp360-ico-outline: var(--mp360-ico-blueprint); --mp360-ico-filled: var(--mp360-ico-blueprint-fill); }
.mp360-drawer__row-ico--ubicacion  { --mp360-ico-outline: var(--mp360-ico-map-pin); --mp360-ico-filled: var(--mp360-ico-map-pin-fill); }
.mp360-drawer__row-ico--avances    { --mp360-ico-outline: var(--mp360-ico-construction-crane); --mp360-ico-filled: var(--mp360-ico-construction-crane-fill); }
.mp360-drawer__row-ico--galeria    { --mp360-ico-outline: var(--mp360-ico-images); --mp360-ico-filled: var(--mp360-ico-images-fill); }
.mp360-drawer__row-ico--proyeccion { --mp360-ico-outline: var(--mp360-ico-chart-trend); --mp360-ico-filled: var(--mp360-ico-chart-trend-fill); }
.mp360-drawer__row-ico--servicios  { --mp360-ico-outline: var(--mp360-ico-list-check); --mp360-ico-filled: var(--mp360-ico-list-check-fill); }
.mp360-drawer__row-ico--nosotros   { --mp360-ico-outline: var(--mp360-ico-office); --mp360-ico-filled: var(--mp360-ico-office-fill); }
.mp360-drawer__row-ico--ayuda      { --mp360-ico-outline: var(--mp360-ico-help-circle); --mp360-ico-filled: var(--mp360-ico-help-circle-fill); }

.mp360-drawer__row-chev {
    width: 7px;
    height: 7px;
    border-top: 2px solid currentColor;
    border-right: 2px solid currentColor;
    transform: rotate(45deg);
    opacity: 0.35;
    flex: 0 0 auto;
}

.mp360-drawer__row-caret {
    width: 8px;
    height: 8px;
    border-left: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(-45deg);
    opacity: 0.5;
    flex: 0 0 auto;
    transition: transform var(--mp360-dur-micro) var(--ease-mp360-back);
}

.mp360-drawer__row--toggle.is-open .mp360-drawer__row-caret { transform: rotate(135deg); }

.mp360-drawer__sub { padding: var(--mp360-space-1) 0 var(--mp360-space-2); }

.mp360-drawer__subtitle {
    margin: var(--mp360-space-2) 0 2px;
    padding: 0 var(--mp360-space-2) 0 var(--mp360-space-4);
    font-size: 12px;
    font-weight: var(--mp360-weight-medium);
    color: var(--mp360-accent);
}

.mp360-drawer__subrow {
    display: flex;
    align-items: center;
    width: 100%;
    min-height: 44px;
    padding: 0 var(--mp360-space-2) 0 var(--mp360-space-4);
    border: 0;
    border-radius: var(--mp360-radius);
    background: none;
    color: var(--mp360-text);
    font-family: inherit;
    font-size: 15px;
    font-weight: var(--mp360-weight-medium);
    text-align: left;
    cursor: pointer;
    opacity: 0.88;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-drawer__subrow:hover { background: rgba(10, 52, 37, 0.06); opacity: 1; }

/* Pie fijo con las acciones comerciales. */
.mp360-drawer__foot {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    gap: var(--mp360-space-2);
    padding: var(--mp360-space-3) var(--mp360-space-4);
    padding-bottom: max(var(--mp360-space-3), var(--mp360-safe-bottom));
    border-top: 1px solid rgba(10, 52, 37, 0.12);
    background: var(--mp360-surface);
}

.mp360-drawer__foot .mp360-cta { width: 100%; }

/*
  Stagger de entrada. Sutil y corto; sólo mientras el drawer abre.
  Las filas no animan al cerrar, para que la salida se sienta inmediata.
*/
.mp360-drawer.is-open .mp360-drawer__row {
    animation: mp360-row-in var(--mp360-dur-base) var(--mp360-ease) backwards;
    animation-delay: calc(40ms + var(--i, 0) * 22ms);
}

@keyframes mp360-row-in {
    from { opacity: 0; transform: translateX(10px); }
    to   { opacity: 1; transform: translateX(0); }
}

/* --- foco visible: token aprobado, 13.72:1 sobre blanco --- */

.mp360-root :focus-visible {
    outline: 2px solid var(--mp360-primary);
    outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   5. Responsive de la navbar
   -------------------------------------------------------------------------- */

/*
  La etiqueta del CTA de contacto es UN solo nodo y su contenido lo decide
  ResponsiveCtaLabel (mp360.js §2c) con los mismos breakpoints de acá:

    > 1520px   texto completo
    ≤ 1520px   texto corto
    ≤ 1279px   sólo ícono

  No hay reglas de `display` para las etiquetas en CSS a propósito. La versión
  anterior mantenía dos spans y los alternaba por media query, y la regla de
  los caracteres Osmo —`.mp360-cta [data-button-animate-chars]`, (0,2,0)— le
  ganaba a la que ocultaba la etiqueta corta (0,1,0): por encima de 1520px se
  veían las dos a la vez. Con un solo nodo el conflicto no puede repetirse.
*/

/*
  HISTORIA. En Fase 4 la navbar pasó a nueve ítems y el colapso subió a 1713px,
  porque ése es el ancho real que necesitan los nueve en una sola fila: 1015px
  de links + 8 gaps = 1080px de franja, más 285px del bloque izquierdo, 289px
  del derecho y 80px de gap+padding → 1734px medidos hoy.

  El costo estaba documentado y aceptado, pero era mayor de lo que parecía: por
  debajo de 1734px NO hay laptop que se salve. 1680, 1600, 1512, 1440, 1366 y
  1280 caían todos al drawer. Una MacBook con viewport de 1280 CSS px veía la
  hamburguesa, que es exactamente el síntoma reportado. Nunca fue un problema
  de macOS ni de DPR: era el breakpoint.

  AHORA la fila no se apaga por umbral fijo. `NavOverflow` (mp360.js §2d) mide
  los ítems y muestra los que entran; el resto vive en "Más". El único umbral
  que queda en CSS es el límite con tablet/mobile, donde la composición sí
  cambia de verdad y la navegación pasa al drawer.
*/
@media (max-width: 1023px) {
    .mp360-navbar__center { display: none; }
    .mp360-burger { display: inline-flex; }
}

/*
  Salida de emergencia de NavOverflow: si no entran ni los ítems mínimos —por
  un viewport muy angosto en desktop, o un zoom de navegador alto— se vuelve al
  drawer en vez de dejar una fila de dos links y un "Más". La clase la pone JS.
*/
.mp360-navbar.is-nav-collapsed .mp360-navbar__center { display: none; }
.mp360-navbar.is-nav-collapsed .mp360-burger { display: inline-flex; }

/* --- "Más": los ítems que no entran en la fila -------------------------- */

/*
  Hereda la identidad del dropdown de "Vistas del Proyecto": mismo botón, mismo
  caret, mismo panel. No es un componente nuevo, es el mismo con una columna.
*/
.mp360-nav__more-wrap {
    position: relative;
    display: none;
    flex: 0 0 auto;
}

.mp360-nav__more-wrap.is-visible { display: inline-flex; }

.mp360-dropdown--more {
    flex-direction: column;
    gap: 2px;
    padding: var(--mp360-space-2);
    min-width: 208px;

    /*
      El panel se acomoda debajo de "Más": baja los últimos 6px y aparece. Nada
      de scale, blur ni rebote — con apertura por hover, un overshoot se
      dispararía cada vez que el puntero roza el botón y sería ruido.

      La `transform` base del dropdown es `translateX(-50%)` para centrarse; hay
      que conservarla o el panel salta a la derecha al animar.

      Cierre más rápido que la apertura: la duración que se aplica es la del
      estado al que se va, así que 140ms vive en la regla base y 200ms en
      `.is-open`.
    */
    opacity: 0;
    transform: translateX(-50%) translateY(-6px);
    transition: opacity 140ms var(--mp360-ease),
                transform 140ms var(--mp360-ease);
}

.mp360-dropdown--more.is-open {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
    transition-duration: 200ms;
}

@media (prefers-reduced-motion: reduce) {
    .mp360-dropdown--more,
    .mp360-dropdown--more.is-open { transition: none; }
}

/*
  Los ítems que se mueven acá son los MISMOS nodos de la fila, con sus
  listeners intactos. Sólo cambian de contenedor, así que basta con que dejen
  de comportarse como pastilla horizontal.
*/
.mp360-dropdown--more .mp360-nav__link {
    width: 100%;
    justify-content: flex-start;
    text-align: left;
}

@media (max-width: 767px) {
    .mp360-navbar {
        height: 60px;
        padding-left: max(var(--mp360-space-4), var(--mp360-safe-left));
        padding-right: max(var(--mp360-space-4), var(--mp360-safe-right));
        gap: var(--mp360-space-2);
    }
    .mp360-logo__img { height: 36px; max-width: 110px; }
    .mp360-navbar__divider { display: none; }
    /* Con el ancho de un móvil vertical, el CTA principal pasa al drawer. */
    .mp360-navbar__left .mp360-cta--primary { display: none; }
    /*
      Y "Agendar visita" también: el topbar mobile se queda con logo, ayuda,
      WhatsApp y hamburguesa, que es lo que cabe legible. La acción no se
      pierde —vive arriba de todo en el pie del drawer, donde es lo primero
      que se ve al abrirlo—.
    */
    .mp360-navbar__right .mp360-cta--accent { display: none; }
}

/* Móvil apaisado: la altura es el recurso escaso (DESIGN.md §9). */
@media (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .mp360-navbar { height: 52px; }
    .mp360-logo__img { height: 32px; }
    .mp360-drawer { top: 52px; }
    .mp360-drawer__link { min-height: 44px; }

    /*
      "Conocer valores" pasa al drawer, igual que en vertical. La regla vivía
      sólo en `max-width: 767px` y no llegaba acá, así que un CTA de 172px
      quedaba dentro de una barra de 52 — el mismo control que en vertical se
      considera que no entra. Ya vive en el pie del drawer, no se pierde.

      "Agendar visita" SÍ se conserva: es la conversión y en apaisado hay ancho
      de sobra para sostenerla. Es la diferencia deliberada con vertical, donde
      el ancho no da y también baja al drawer.
    */
    .mp360-navbar__left .mp360-cta--primary { display: none; }
    .mp360-navbar__divider { display: none; }

    /*
      Y se RESTITUYE la conversión. Por debajo de 768px de ancho la regla de
      vertical la baja al drawer porque ahí no hay ancho; acostado sobran ~380px
      después del logo, los iconos y la hamburguesa, así que vuelve a la barra.
      Es la diferencia deliberada entre las dos orientaciones.
    */
    .mp360-navbar__right .mp360-cta--accent { display: inline-flex; }
}

/* --------------------------------------------------------------------------
   5b. Selector de panoramas y rótulo de escena (F3)

   Zona inferior central del layout canónico. Se centra con translateX para no
   depender del ancho del contenido, que cambia entre grupos de 5 y 6 pasos.

   La leyenda (inferior izquierda) y "Cómo usar" (inferior derecha) siguen
   siendo del skin de 3DVista hasta F5/F4: el ancho máximo evita invadirlas.
   -------------------------------------------------------------------------- */

.mp360-scene {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    bottom: calc(var(--mp360-space-8) + var(--mp360-safe-bottom));
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--mp360-space-3);
    max-width: min(560px, calc(100vw - 320px));
}

/* Rótulo: mismo tratamiento que los Label del skin (fondo de marca, radius 3). */
.mp360-scene__label {
    margin: 0;
    padding: var(--mp360-space-2) var(--mp360-space-4);
    border-radius: var(--mp360-radius);
    background: var(--mp360-primary);
    color: var(--mp360-on-primary);
    font-size: 16px;
    font-weight: var(--mp360-weight-medium);
    line-height: 1.2;
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

.mp360-selector {
    display: flex;
    align-items: center;
    gap: var(--mp360-space-1);
    padding: var(--mp360-space-1) var(--mp360-space-2);
    background: var(--mp360-surface);
    border-radius: var(--mp360-radius);
    box-shadow: 0 2px 10px rgba(10, 52, 37, 0.22);
}

.mp360-selector__arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border: 0;
    border-radius: var(--mp360-radius);
    background: none;
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease),
                opacity var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-selector__arrow:hover:not(:disabled) { background: rgba(10, 52, 37, 0.08); }

.mp360-selector__arrow:disabled {
    opacity: 0.3;
    cursor: default;
}

.mp360-selector__chev {
    width: 10px;
    height: 10px;
    border-top: 2px solid var(--mp360-primary);
    border-right: 2px solid var(--mp360-primary);
}

.mp360-selector__chev--prev { transform: rotate(-135deg); margin-left: 3px; }
.mp360-selector__chev--next { transform: rotate(45deg); margin-right: 3px; }

.mp360-selector__steps {
    display: flex;
    align-items: center;
}

/*
  El punto mide 10px pero su área tocable llega a 44×44 (DESIGN.md §7).
*/
.mp360-selector__dot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 44px;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
}

.mp360-selector__dot-mark {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: rgba(10, 52, 37, 0.28);
    transition: background-color 160ms var(--mp360-ease), transform var(--mp360-dur-micro-lg) var(--ease-mp360-back), box-shadow 160ms var(--mp360-ease);
}

.mp360-selector__dot:hover .mp360-selector__dot-mark {
    background: rgba(10, 52, 37, 0.5);
}

/*
  Selección: no depende solo del color. Cambia relleno, tamaño y suma un anillo
  (DESIGN.md §3 — "no depender solo del color cuando la selección sea importante").
*/
.mp360-selector__dot.is-active .mp360-selector__dot-mark {
    background: var(--mp360-primary);
    transform: scale(1.3);
    box-shadow: 0 0 0 3px rgba(61, 101, 0, 0.35);
}

/* --------------------------------------------------------------------------
   Selector compacto en móvil

   En un teléfono la franja inferior acumula disponibilidad + rótulo + selector,
   y entre las tres se comían un tercio de la pantalla. El selector es el que
   puede ceder: es navegación secundaria —el recorrido se explora sobre todo con
   los hotspots— mientras que la disponibilidad es contenido y no se toca.

   De dónde sale el alto, y por qué se recorta así: los 52px eran 44 de control
   más 4+4 de padding. Se quita el padding vertical —el control ya define el
   alto— y el control baja a 40. El resultado son 40px, un 23 % menos, sin que
   nada quede por debajo de lo que un dedo puede tocar con comodidad: la fila
   completa sigue siendo superficie táctil y las flechas conservan 40×40.

   El dot no baja de tamaño táctil: mantiene los 40px de alto de la fila y sólo
   se estrecha; lo que se achica es la MARCA, que es dibujo, no objetivo.
   -------------------------------------------------------------------------- */

@media (max-width: 767px) {
    .mp360-scene {
        bottom: calc(var(--mp360-space-4) + var(--mp360-safe-bottom));
        /* El rótulo pertenece al selector: pegarlos also recupera altura. */
        gap: var(--mp360-space-1);
        max-width: calc(100vw - var(--mp360-space-8));
    }
    .mp360-scene__label { font-size: 14px; padding: var(--mp360-space-1) var(--mp360-space-3); }

    .mp360-selector { padding: 0 var(--mp360-space-1); }
    .mp360-selector__arrow { width: 40px; height: 40px; }
    .mp360-selector__dot { width: 26px; height: 40px; }
    .mp360-selector__dot-mark { width: 8px; height: 8px; }
}

/* Apaisado: la altura es el recurso escaso; el rótulo y el selector se juntan. */
@media (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .mp360-scene {
        bottom: calc(var(--mp360-space-2) + var(--mp360-safe-bottom));
        gap: var(--mp360-space-1);
    }
    /* El clamp de ancho vivía sólo en vertical; sin él el rótulo puede
       cruzarse con la leyenda de la columna izquierda. */
    .mp360-scene { max-width: calc(100vw - var(--mp360-space-8)); }
    .mp360-scene__label { font-size: 13px; padding: 2px var(--mp360-space-3); }
    /*
      Acá el recorte importa más que en vertical: quedan ~390px de alto. Mismas
      medidas que en móvil vertical — antes esta regla volvía a subir la flecha
      a 44 y dejaba el selector en su alto completo justo donde menos sobra.
    */
    .mp360-selector { padding: 0 var(--mp360-space-1); }
    .mp360-selector__arrow { width: 40px; height: 40px; }
    .mp360-selector__dot { width: 26px; height: 40px; }
    .mp360-selector__dot-mark { width: 8px; height: 8px; }
}

/* --------------------------------------------------------------------------
   6. Superficies de contenido (F4)

   Un solo contenedor modal para bienvenida, servicios, nosotros, plano,
   ubicación, instrucciones y galería. Que compartan caja, motion y cierre es
   lo que hace que se lean como un sistema y no como siete pantallas sueltas.

   El panel Nosotros del skin era un cajón lateral fijo de 362px con grandes
   zonas verticales vacías. Acá todas las superficies usan la misma caja
   centrada, que crece con su contenido hasta un tope y recién ahí scrollea.
   -------------------------------------------------------------------------- */

.mp360-surface {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--mp360-space-6);
    padding-top: max(var(--mp360-space-6), calc(var(--mp360-safe-top) + var(--mp360-space-4)));
    padding-bottom: max(var(--mp360-space-6), calc(var(--mp360-safe-bottom) + var(--mp360-space-4)));
    z-index: 20;
}

.mp360-surface__scrim {
    position: absolute;
    inset: 0;
    background: var(--mp360-overlay);
    opacity: 0;
    transition: opacity var(--mp360-dur-panel) var(--mp360-ease);
}

.mp360-surface.is-open .mp360-surface__scrim { opacity: var(--mp360-overlay-opacity); }

.mp360-surface__body {
    position: relative;
    display: flex;
    flex-direction: column;
    width: min(560px, 100%);
    max-height: 100%;
    background: var(--mp360-surface);
    border-radius: var(--mp360-radius);
    box-shadow: 0 18px 60px rgba(0, 0, 0, 0.4);
    overflow: hidden;
    opacity: 0;
    transform: translateY(12px) scale(0.985);
    transition: opacity var(--mp360-dur-surface-out) var(--mp360-ease),
                transform var(--mp360-dur-surface-out) var(--ease-mp360-back);
}

.mp360-surface.is-open .mp360-surface__body {
    opacity: 1;
    transform: none;
    transition-duration: var(--mp360-dur-surface);
}

/* Las superficies que muestran medios necesitan más ancho. */
.mp360-surface__body[data-type="gallery"] { width: min(1000px, 100%); }

/*
  El plano es el contenido, no un adjunto: en desktop aprovecha casi todo el
  ancho. Como el alto ahora sale de la proporción real de la imagen, ensanchar
  no genera superficie vacía — sólo un plano más grande.
*/
.mp360-surface__body[data-type="viewer"] { width: min(1400px, 100%); }
.mp360-surface__body[data-type="map"] { width: min(860px, 100%); }

/*
  Selección de vistas: doce miniaturas en dos grupos. Encolumnadas en 560px
  quedaba una franja alta y angosta con scroll, desaprovechando todo el ancho.
  Con esta caja los dos grupos entran lado a lado, cada uno con su 3×2.

  En desktop se ensancha todavía más (F5.1): acá la miniatura ES el contenido,
  así que cuanto más ancha la superficie, más grande se lee cada escena. Ronda
  el 85% del viewport y topa en 1520px para que en pantallas muy anchas no se
  estire sin sentido. No es full-screen: sigue leyéndose como superficie.

  El ensanche queda acotado a ≥1024px a propósito: tablet y teléfono conservan
  la composición aprobada, que ya está resuelta con otro criterio.
*/
.mp360-surface__body[data-type="panoramas"] { width: min(1180px, 100%); }

@media (min-width: 1024px) {
    .mp360-surface__body[data-type="panoramas"] { width: min(1520px, 85vw); }
}

/*
  El visor del plano no tiene alto intrínseco: si sólo crece con el contenido
  queda una franja baja e inútil para leer un plano. Toma el alto disponible.
*/
.mp360-surface__body[data-type="viewer"] { height: 100%; }

/* --- botón cerrar común --- */

.mp360-surface__close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    flex: 0 0 auto;
    border: 0;
    border-radius: var(--mp360-radius);
    background: var(--mp360-primary);
    color: var(--mp360-on-primary);
    cursor: pointer;
    transition: filter var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-surface__close:hover { filter: brightness(1.25); }

/* --------------------------------------------------------------------------
   card — bienvenida y servicios
   -------------------------------------------------------------------------- */

.mp360-card { display: flex; flex-direction: column; min-height: 0; }

.mp360-card__media { position: relative; flex: 0 0 auto; }

.mp360-card__img {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
}

/* Sobre la foto el botón necesita su propia superficie para tener contraste. */
.mp360-card__media .mp360-surface__close {
    position: absolute;
    top: var(--mp360-space-3);
    right: var(--mp360-space-3);
}

.mp360-card__content {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--mp360-space-6);
}

.mp360-card__title {
    margin: 0 0 var(--mp360-space-3);
    font-size: 26px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1.2;
    color: var(--mp360-primary);
}

.mp360-card__intro {
    margin: 0 0 var(--mp360-space-2);
    font-size: 16px;
    line-height: 1.5;
    color: var(--mp360-text);
}

.mp360-card__text {
    margin: 0 0 var(--mp360-space-2);
    font-size: 16px;
    line-height: 1.55;
    color: var(--mp360-text);
}

.mp360-card__list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.mp360-card__item {
    position: relative;
    padding: 6px 0 6px var(--mp360-space-4);
    font-size: 16px;
    line-height: 1.45;
}

.mp360-card__item::before {
    content: "";
    position: absolute;
    left: 2px;
    top: 15px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--mp360-accent);
}

/*
  Cierre comercial de la card. El aire de arriba y la línea son lo que hace
  que se lea como paso siguiente y no como un ítem más de la lista.
*/
.mp360-card__actions {
    display: flex;
    margin-top: var(--mp360-space-6);
    padding-top: var(--mp360-space-6);
    border-top: 1px solid rgba(10, 52, 37, 0.12);
}

.mp360-card__actions .mp360-cta { width: 100%; }

.mp360-card__hint {
    margin: var(--mp360-space-4) 0 0;
    padding-top: var(--mp360-space-3);
    border-top: 1px solid rgba(10, 52, 37, 0.12);
    font-size: 14px;
    line-height: 1.45;
    color: var(--mp360-text);
    opacity: 0.75;
}

.mp360-card__flag {
    margin: 0 0 var(--mp360-space-3);
    font-size: 12px;
    font-weight: var(--mp360-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--mp360-accent);
}

.mp360-card--staging { padding-top: var(--mp360-space-4); }
.mp360-card--staging .mp360-surface__close { position: absolute; top: var(--mp360-space-3); right: var(--mp360-space-3); }

/* --------------------------------------------------------------------------
   about — Nosotros
   -------------------------------------------------------------------------- */

.mp360-about { display: flex; flex-direction: column; min-height: 0; }

.mp360-about__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--mp360-space-3);
    flex: 0 0 auto;
    padding: var(--mp360-space-3) var(--mp360-space-3) var(--mp360-space-3) var(--mp360-space-6);
    background: var(--mp360-surface-inverse);
}

.mp360-about__eyebrow {
    margin: 0;
    font-size: 14px;
    font-weight: var(--mp360-weight-medium);
    letter-spacing: 0.02em;
    color: var(--mp360-on-primary);
}

.mp360-about__head .mp360-surface__close {
    background: rgba(255, 255, 255, 0.14);
    color: var(--mp360-on-primary);
}

.mp360-about__scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--mp360-space-6);
}

.mp360-about__title {
    margin: 0 0 var(--mp360-space-3);
    font-size: 26px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1.2;
    color: var(--mp360-primary);
}

.mp360-about__text {
    margin: 0 0 var(--mp360-space-3);
    font-size: 16px;
    line-height: 1.55;
}

.mp360-about__cta { margin: var(--mp360-space-2) 0 var(--mp360-space-6); width: 100%; }

.mp360-about__data {
    padding-top: var(--mp360-space-4);
    border-top: 1px solid rgba(10, 52, 37, 0.14);
}

.mp360-about__row {
    display: flex;
    align-items: center;
    gap: var(--mp360-space-3);
    width: 100%;
    min-height: 48px;
    padding: var(--mp360-space-1) var(--mp360-space-2);
    border: 0;
    border-radius: var(--mp360-radius);
    background: none;
    color: var(--mp360-text);
    font-family: inherit;
    font-size: 15px;
    line-height: 1.35;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-about__row:hover { background: rgba(10, 52, 37, 0.06); }

.mp360-about__icon {
    position: relative;
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    background: var(--mp360-accent);
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
}

.mp360-about__icon--phone {
    -webkit-mask-image: var(--mp360-ico-phone);
    mask-image: var(--mp360-ico-phone);
}
.mp360-about__icon--mail {
    -webkit-mask-image: var(--mp360-ico-mail);
    mask-image: var(--mp360-ico-mail);
}
.mp360-about__icon--pin {
    -webkit-mask-image: var(--mp360-ico-pin);
    mask-image: var(--mp360-ico-pin);
}

.mp360-about__social {
    display: flex;
    gap: var(--mp360-space-2);
    margin-top: var(--mp360-space-3);
    padding-left: var(--mp360-space-2);
}

.mp360-about__social-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: var(--mp360-radius);
    background: var(--mp360-primary);
    transition: filter var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-about__social-link:hover { filter: brightness(1.3); }

.mp360-about__social-glyph {
    width: 20px;
    height: 20px;
    background: var(--mp360-on-primary);
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
}

.mp360-about__social-link--facebook .mp360-about__social-glyph {
    -webkit-mask-image: var(--mp360-ico-fb);
    mask-image: var(--mp360-ico-fb);
}
.mp360-about__social-link--instagram .mp360-about__social-glyph {
    -webkit-mask-image: var(--mp360-ico-ig);
    mask-image: var(--mp360-ico-ig);
}

/* --------------------------------------------------------------------------
   map — Ubicación
   -------------------------------------------------------------------------- */

.mp360-map { display: flex; flex-direction: column; min-height: 0; }
/* Cabecera común de las superficies con barra propia. */
.mp360-map__head,
.mp360-steps__head,
.mp360-panoramas__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--mp360-space-3);
    flex: 0 0 auto;
    padding: var(--mp360-space-3) var(--mp360-space-3) var(--mp360-space-3) var(--mp360-space-6);
    border-bottom: 1px solid rgba(10, 52, 37, 0.12);
}

.mp360-map__title,
.mp360-steps__title,
.mp360-panoramas__title {
    margin: 0;
    font-size: 20px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1.2;
    color: var(--mp360-primary);
}

.mp360-map__titles { min-width: 0; }

.mp360-map__subtitle {
    margin: 2px 0 0;
    font-size: 14px;
    line-height: 1.3;
    color: var(--mp360-text);
    opacity: 0.7;
}

/*
  Capa editorial de Ubicación. Una línea, no un banner: si creciera empezaría
  a competir con el mapa, que es el contenido de la superficie.
*/
.mp360-map__lead {
    flex: 0 0 auto;
    margin: 0;
    padding: var(--mp360-space-4) var(--mp360-space-6);
    max-width: 68ch;
    font-size: 15px;
    line-height: 1.5;
    color: var(--mp360-text);
}

.mp360-map__frame {
    flex: 1 1 auto;
    min-height: 0;
    /* Alto útil real: sin esto el iframe colapsa dentro del flex. */
    height: min(60vh, 520px);
}

.mp360-map__iframe { display: block; width: 100%; height: 100%; border: 0; }

/* --------------------------------------------------------------------------
   poi — contenido embebido de un punto de interés (Fase 6)

   Misma estructura que `map`, con dos diferencias deliberadas: acá no hay
   capa editorial que leer antes —el destino se entiende con el título— y por
   eso el embed toma toda la altura que sobra; y el rótulo de sección dice de
   qué tipo de contenido se trata antes de nombrarlo.
   -------------------------------------------------------------------------- */

.mp360-map__eyebrow {
    margin: 0 0 2px;
    font-size: 12px;
    font-weight: var(--mp360-weight-medium);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--mp360-primary);
    opacity: 0.55;
}

/*
  El contenido es el mapa, no la superficie que lo contiene: en desktop se
  ensancha respecto de Ubicación y el marco crece con el viewport en vez de
  toparse en 520px.
*/
.mp360-surface__body[data-type="poi"] { width: min(980px, 100%); }
.mp360-map--poi .mp360-map__frame { height: min(68vh, 640px); }

/* --------------------------------------------------------------------------
   steps — Cómo usar esta experiencia
   -------------------------------------------------------------------------- */

.mp360-steps { display: flex; flex-direction: column; min-height: 0; }

.mp360-steps__stage {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--mp360-space-6);
    /* Contexto de posicionamiento del panel saliente. */
    position: relative;
}

/*
  Internal state transition. Clases genéricas a propósito: hoy el único
  consumidor es el stepper de "Cómo usar esta experiencia", pero el patrón no
  tiene nada específico de él. Un segundo consumidor sólo necesita marcar su
  contenido con .mp360-ist y alternar --in / --out.

  `--mp360-ist-dir` la escribe JS con 1 (siguiente) o -1 (anterior); de ahí
  sale la dirección del movimiento sin duplicar reglas.
*/
.mp360-ist {
    transition: transform var(--mp360-ist-dur) var(--ease-mp360-back),
                opacity var(--mp360-ist-dur) var(--mp360-ease);
}

/* Estado inicial del entrante: llega desde el lado hacia el que se avanza. */
.mp360-ist--in {
    transform: translateX(calc(var(--mp360-ist-dir, 1) * var(--mp360-ist-shift)));
    opacity: 0;
}

/*
  El saliente se va del flujo antes de moverse. Así el contenedor adopta de
  inmediato la altura del contenido nuevo en vez de crecer al máximo de los dos
  y volver a encogerse a mitad de la transición.
*/
.mp360-ist--out {
    position: absolute;
    transform: translateX(calc(var(--mp360-ist-dir, 1) * var(--mp360-ist-shift) * -1));
    opacity: 0;
    pointer-events: none;
}


.mp360-steps__count {
    margin: 0 0 var(--mp360-space-2);
    font-size: 12px;
    font-weight: var(--mp360-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--mp360-accent);
}

.mp360-steps__subtitle {
    margin: 0 0 var(--mp360-space-3);
    font-size: 22px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1.2;
    color: var(--mp360-primary);
}

.mp360-steps__text {
    margin: 0 0 var(--mp360-space-2);
    font-size: 16px;
    line-height: 1.55;
}

.mp360-steps__bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--mp360-space-2);
    flex: 0 0 auto;
    padding: var(--mp360-space-2) var(--mp360-space-3);
    border-top: 1px solid rgba(10, 52, 37, 0.12);
}

.mp360-steps__arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border: 0;
    border-radius: var(--mp360-radius);
    background: none;
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-steps__arrow:hover:not(:disabled) { background: rgba(10, 52, 37, 0.08); }
.mp360-steps__arrow:disabled { opacity: 0.3; cursor: default; }

.mp360-steps__dots { display: flex; align-items: center; }

.mp360-steps__dot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 44px;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
}

.mp360-steps__dot .mp360-selector__dot-mark {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: rgba(10, 52, 37, 0.28);
    transition: background-color var(--mp360-dur-base) var(--mp360-ease),
                transform var(--mp360-dur-micro-lg) var(--ease-mp360-back);
}

.mp360-steps__dot.is-active .mp360-selector__dot-mark {
    background: var(--mp360-primary);
    transform: scale(1.4);
}

/* --------------------------------------------------------------------------
   5b-bis. Volver al inicio (F5.1)

   Navegación contextual, no acción comercial: superficie clara, peso medio,
   sin Character Stagger. Va bajo la navbar, del lado izquierdo — donde el
   skin ponía su botón nativo—, lejos de la franja inferior donde conviven
   leyenda, selector y minimapa.
   -------------------------------------------------------------------------- */

.mp360-home {
    position: absolute;
    left: max(var(--mp360-space-6), var(--mp360-safe-left));
    /*
      Alto de la navbar + un paso de la escala de spacing. Antes eran 76px
      medidos contra una navbar de 72 y quedaban 4px de aire: se leía pegado.
    */
    top: calc(var(--mp360-safe-top) + 72px + var(--mp360-space-6));
    z-index: 8;
    display: inline-flex;
    align-items: center;
    gap: var(--mp360-space-2);
    min-height: 44px;
    padding: 0 var(--mp360-space-4) 0 var(--mp360-space-3);
    /*
      IDENTIDAD PROPIA, PERO SECUNDARIA (5.1 §9).

      Sobre el panorama conviven seis superficies blancas —navbar, minimapa,
      disponibilidad, selector, navegador de plan y este botón— y encontrarlo
      costaba. Se le da una tinta verde muy suave y un borde de marca en vez de
      blanco puro: se localiza de un vistazo y sigue siendo reconocible como
      parte del mismo sistema.

      Deliberadamente NO se convierte en un CTA verde sólido: compitiendo con
      "Conocer valores" y "Agendar visita" desordenaría la jerarquía comercial.
      Es navegación, y se lee como navegación.
    */
    border: 1px solid rgba(10, 52, 37, 0.18);
    border-radius: var(--mp360-radius);
    background: #EDF2E8;
    box-shadow: 0 2px 10px rgba(10, 52, 37, 0.18);
    color: var(--mp360-primary);
    font-family: inherit;
    font-size: 14px;
    font-weight: var(--mp360-weight-medium);
    /* Métrica del Character Stagger, igual que en .mp360-cta: la caja tiene
       que ser mayor que el glifo y menor que el recorrido. */
    --mp360-cta-travel: 1.45em;
    line-height: 1.28;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color var(--mp360-dur-base) var(--mp360-ease);
}

/* Un paso más de tinta, no un cambio de color: el estado se nota sin saltar. */
.mp360-home:hover,
.mp360-home:focus-visible { background: #E2EAD9; border-color: rgba(10, 52, 37, 0.32); }

/*
  Flecha dibujada con bordes: sin asset nuevo y hereda currentColor. Se desplaza
  unos píxeles con el token espacial — la microinteracción que ya usa el resto
  de la interfaz—, sin agregar un segundo efecto encima del stagger.
*/
.mp360-home__icon {
    width: 8px;
    height: 8px;
    flex: 0 0 auto;
    margin-left: 2px;
    border-left: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg);
    transition: transform var(--mp360-dur-micro) var(--ease-mp360-back);
}

.mp360-home:hover .mp360-home__icon,
.mp360-home:focus-visible .mp360-home__icon,
.mp360-home:active .mp360-home__icon { transform: rotate(45deg) translate(2px, -2px); }

.mp360-home__label { white-space: nowrap; }

/*
  Teléfono: el control baja a un tamaño compacto pero conserva el texto — un
  ícono solo sería ambiguo— y no invade la franja central del panorama.
*/
@media (max-width: 767px) {
    .mp360-home {
        left: var(--mp360-space-3);
        /* Navbar de 60px + un paso de la escala. */
        top: calc(var(--mp360-safe-top) + 60px + var(--mp360-space-4));
        min-height: 40px;
        padding: 0 var(--mp360-space-3) 0 var(--mp360-space-2);
        font-size: 13px;
    }
}

/*
  Apaisado. Dos cosas distintas: la posición y el peso.

  POSICIÓN — navbar de 52px, con el aire achicado. En apaisado el notch va al
  COSTADO, así que el inset lateral tiene que sobrevivir al override.

  PESO — sigue siendo el mismo control, con la misma tinta y la misma etiqueta:
  un ícono solo sería ambiguo y quitarle la tinta lo devolvería al montón de
  superficies blancas. Lo que baja es la SOMBRA. Con 375px de alto, cinco
  componentes reclamando profundidad hacen que ninguno se lea como secundario;
  el minimapa ya no está y la disponibilidad quedó en una fila, así que este
  botón no necesita levantarse tanto del panorama para encontrarse.
  DESIGN.md §1: reducir primero el peso de lo secundario, no su legibilidad.
*/
@media (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .mp360-home {
        left: max(var(--mp360-space-3), var(--mp360-safe-left));
        top: calc(var(--mp360-safe-top) + 52px + var(--mp360-space-3));
        min-height: 36px;
        padding: 0 var(--mp360-space-3) 0 var(--mp360-space-2);
        box-shadow: 0 1px 4px rgba(10, 52, 37, 0.14);
        font-size: 12px;
    }
}

/* --------------------------------------------------------------------------
   5b-ter. Minimapa / plano interactivo (Fase 1B)

   Superior derecha, que es donde vive el MapViewer del export —`top: 9.99%`,
   `right: 0%`, `width: 23.72%`—. Se preserva la ubicación y la proporción; lo
   único que se moderniza es el margen, para que respire como el resto de las
   superficies MP360 en lugar de pegarse al borde.

   No aparece en móvil vertical: `script_mobile.js` no declara ningún MapViewer,
   así que ahí el minimapa nunca existió y no se agrega ahora.
   -------------------------------------------------------------------------- */

.mp360-minimap {
    position: absolute;
    right: max(var(--mp360-space-6), var(--mp360-safe-right));
    top: calc(var(--mp360-safe-top) + 72px + var(--mp360-space-6));
    z-index: 8;
    width: min(380px, 24vw);
    border-radius: var(--mp360-radius);
    overflow: hidden;
    background: var(--mp360-surface);
    box-shadow: 0 2px 10px rgba(10, 52, 37, 0.22);
}

/*
  La regla geométrica del módulo: imagen, marcadores y cono comparten
  exactamente esta caja. La proporción es la del asset del export —la declara
  el JS desde `minimap.source`—, así que no puede haber letterboxing entre
  capas y las coordenadas caen donde tienen que caer.
*/
.mp360-minimap__stage {
    position: relative;
    aspect-ratio: var(--mp360-minimap-ar, 1382 / 751);
}

.mp360-minimap__img {
    display: block;
    width: 100%;
    height: 100%;
    /* Cubre la diferencia de 0.13% entre derivadas sin desplazar la caja. */
    object-fit: cover;
}

.mp360-minimap__layer { position: absolute; inset: 0; }

/*
  Marcador. El área táctil es mayor que el punto visible: el punto tiene que
  ser discreto sobre el plano, pero el objetivo no puede serlo.
*/
.mp360-minimap__marker {
    position: absolute;
    transform: translate(-50%, -50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: none;
    cursor: pointer;
}

.mp360-minimap__dot {
    display: block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--mp360-surface);
    box-shadow: 0 0 0 2px var(--mp360-primary), 0 1px 3px rgba(0, 0, 0, 0.4);
    transition: transform var(--mp360-dur-micro-lg) var(--ease-mp360-back),
                background-color var(--mp360-dur-base) var(--mp360-ease),
                box-shadow var(--mp360-dur-base) var(--mp360-ease);
}

.mp360-minimap__marker:hover .mp360-minimap__dot,
.mp360-minimap__marker:focus-visible .mp360-minimap__dot { transform: scale(1.35); }

/*
  Vista actual: no sólo color. Cambia el tamaño, se rellena y suma un anillo,
  así que se distingue igual en escala de grises.
*/
.mp360-minimap__marker.is-current .mp360-minimap__dot {
    width: 14px;
    height: 14px;
    background: var(--mp360-accent);
    box-shadow: 0 0 0 3px var(--mp360-surface), 0 0 0 5px var(--mp360-accent),
                0 1px 4px rgba(0, 0, 0, 0.45);
}

/*
  Cono de campo de visión.

  El SVG es cuadrado y su centro —el (0,0) del viewBox, que es el vértice del
  sector— se lleva sobre el marcador con translate(-50%, -50%). Por eso el
  `transform-origin` va al centro y no a un borde: origen de giro y punto de
  anclaje son el mismo, así que rotar no desplaza el vértice ni un píxel.

  El tamaño se expresa en porcentaje del escenario, no en píxeles: así el cono
  guarda la misma proporción con el plano en todos los breakpoints donde el
  minimapa existe.

  SIN transición y sin overshoot. La dirección es un dato espacial preciso: una
  curva con rebote lo dejaría apuntando unos grados fuera de donde el usuario
  está mirando, y cualquier interpolación introduce retraso respecto de la
  cámara. Se actualiza por rAF mientras el yaw cambia, que ya es suave.
*/
.mp360-minimap__cone {
    position: absolute;
    width: clamp(84px, 34%, 150px);
    aspect-ratio: 1;
    height: auto;
    transform-origin: 50% 50%;
    /* El degradado del sector hereda este color. */
    color: var(--mp360-primary);
    pointer-events: none;
    overflow: visible;
}

@media (max-width: 1279px) {
    .mp360-minimap { width: min(300px, 30vw); }
}

/* Móvil vertical: el minimapa no existe en este export y no se introduce. */
@media (max-width: 767px) {
    .mp360-minimap { display: none; }
}

/*
  APAISADO DE TELÉFONO: sin minimapa.

  Medido a 812x375: ocupaba 230x125 en la esquina superior derecha, un 9 % del
  área de pantalla, sobre un viewport donde entre la navbar y el primer control
  quedaban 12px de panorama limpio.

  No es una reubicación —la esquina superior derecha sigue siendo su casilla
  aprobada (PROJECT-PROFILE §15)—, es la misma transformación que ya rige en
  vertical, donde el minimapa tampoco existe. La orientación espacial en
  apaisado queda a cargo del rótulo de escena y del selector, que sí están.

  DESIGN.md §1: preservar el protagonismo del panorama reduciendo primero el
  contenido secundario. Decisión de producto tomada explícitamente.
*/
@media (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .mp360-minimap { display: none; }
}

/* --------------------------------------------------------------------------
   5c. Leyenda de disponibilidad y referencias comerciales (F5)

   Zona inferior izquierda del layout canónico. Reemplaza al bitmap
   "Disp - No Disp" del skin y a su modal.

   Dos niveles: estados siempre visibles, valores detrás de un disclosure
   cerrado por defecto — una leyenda persistente no puede convertirse en una
   tabla de precios permanente sobre el panorama.
   -------------------------------------------------------------------------- */

.mp360-legend {
    position: absolute;
    /* En apaisado el notch va al COSTADO: el inset lateral no es decorativo. */
    left: max(var(--mp360-space-6), var(--mp360-safe-left));
    bottom: calc(var(--mp360-space-8) + var(--mp360-safe-bottom));
    /* Por debajo de navbar (10), drawer (9) y superficies (20). */
    z-index: 8;
    display: flex;
    flex-direction: column;
    width: min(320px, calc(100vw - 2 * var(--mp360-space-6)));
    max-height: calc(100vh - 160px);
    /*
      El scroll vive acá y no en el bloque de valores: si el recorte del
      disclosure también scrolleara, la fila `1fr` no tendría alto que repartir
      y la apertura quedaría en cero.
    */
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--mp360-space-3) var(--mp360-space-4);
    border-radius: var(--mp360-radius);
    background: var(--mp360-surface);
    box-shadow: 0 2px 10px rgba(10, 52, 37, 0.22);
    color: var(--mp360-text);
}

/* --------------------------------------------------------------------------
   Micro-onboarding comercial — spotlight

   La primera entrada de la sesión a lotes atenúa el resto de la experiencia
   para que se lea la leyenda. Es una AYUDA VISUAL: `pointer-events: none`, así
   que no bloquea el recorrido, no es un modal y no captura nada.

   Capas, dentro de la escala que ya existe (selector/leyenda 8 · drawer 9 ·
   navbar 10 · superficies 20 · tooltip 30):

       12  el velo — por encima de la navbar, por debajo de las superficies
       13  la leyenda mientras dura el foco

   No se altera el stacking general para resolver este caso.
   -------------------------------------------------------------------------- */

/*
  El velo entra y sale con su propia transición, asimétrica: entrar puede ser
  algo más ágil, irse tiene que quitarse de en medio sin llamar la atención.
  Easing SIMPLE — la curva con overshoot sobre una opacidad sale del rango 0–1
  y produce un parpadeo.
*/
.mp360-spotlight {
    position: absolute;
    inset: 0;
    z-index: 12;
    background: var(--mp360-overlay);
    opacity: 0;
    pointer-events: none;
    /* Salida; la entrada la acorta `.is-on`. Debe coincidir con VELO_OUT_MS. */
    transition: opacity 420ms var(--mp360-ease);
}

.mp360-spotlight.is-on {
    opacity: var(--mp360-spotlight-opacity, 0.36);
    transition-duration: 340ms;
}

.mp360-spotlight[hidden] { display: none; }

/*
  Dos clases, no una, porque hacen cosas distintas en momentos distintos:

    is-lifted   sube la leyenda por encima del velo. Se aplica en el MISMO
                frame que el velo: si esperara al énfasis, la leyenda se vería
                oscurecida un instante y después saltaría al frente.
    is-spotlit  el énfasis espacial, ~120ms después.

  La posición final NO cambia: el usuario tiene que descubrir la leyenda donde
  realmente vive.
*/
.mp360-legend.is-lifted { z-index: 13; }

/*
  Microentrada con peso: sube 11px y crece desde 0.988. El scale es mínimo a
  propósito —lo justo para que la card se sienta densa al aterrizar y no como
  un pop—. La curva espacial del sistema aporta la anticipación; con
  reduced-motion se neutraliza sola y queda sólo el oscurecimiento.
*/
.mp360-legend.is-spotlit {
    animation: mp360-spotlit-in 420ms var(--ease-mp360-back);
    transform-origin: left bottom;
}

@keyframes mp360-spotlit-in {
    from { transform: translateY(11px) scale(0.988); }
    to   { transform: none; }
}

.mp360-legend__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--mp360-space-2);
}

.mp360-legend__title {
    margin: 0;
    font-size: 13px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1.2;
    color: var(--mp360-primary);
}

/* Qué etapa se está mirando: sin esto la tabla de valores es ambigua. */
.mp360-legend__stage {
    margin: 0;
    font-size: 11px;
    font-weight: var(--mp360-weight-medium);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    line-height: 1.2;
    color: var(--mp360-accent);
}

.mp360-legend__states {
    margin: var(--mp360-space-3) 0 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: var(--mp360-space-2);
}

.mp360-legend__state {
    display: flex;
    align-items: center;
    gap: var(--mp360-space-2);
    font-size: 13px;
    line-height: 1.2;
}

/*
  El borde no es decorativo: sin él, las bandas más claras (#CCFFCC, #FEFEFE)
  desaparecen contra la superficie blanca.
*/
.mp360-legend__swatch {
    display: block;
    width: 14px;
    height: 14px;
    flex: 0 0 auto;
    border-radius: 50%;
    background: var(--mp360-band, transparent);
    box-shadow: inset 0 0 0 1px rgba(10, 52, 37, 0.35);
}

/* "Disponible" no es un color sino seis: se muestran los seis. */
.mp360-legend__swatches { display: flex; gap: 2px; flex: 0 0 auto; }
.mp360-legend__swatch--mini { width: 10px; height: 10px; }

.mp360-legend__note {
    margin: var(--mp360-space-3) 0 0;
    font-size: 12px;
    line-height: 1.4;
    color: var(--mp360-text);
    opacity: 0.75;
}

.mp360-legend__toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--mp360-space-2);
    width: 100%;
    min-height: 44px;
    margin-top: var(--mp360-space-2);
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
    font-family: inherit;
    font-size: 13px;
    font-weight: var(--mp360-weight-medium);
    color: var(--mp360-accent);
    text-align: left;
}

/* Comparte duración con el disclosure para no terminar de girar antes. */
.mp360-legend__chev {
    width: 8px;
    height: 8px;
    flex: 0 0 auto;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg);
    transition: transform var(--mp360-dur-disclosure-out) var(--ease-mp360-back);
}

.mp360-legend__toggle.is-open .mp360-legend__chev,
.mp360-legend__compact.is-open .mp360-legend__chev {
    transform: rotate(-135deg);
    /* La apertura es la más larga: el giro acompaña, no se adelanta. */
    transition-duration: var(--mp360-dur-disclosure);
}

/*
  Fila compacta y nota en línea: existen sólo para móvil vertical. En el resto
  de los viewports la leyenda queda exactamente como está aprobada.
*/
.mp360-legend__compact,
.mp360-legend__note--inline { display: none; }

/*
  DISCLOSURE TRANSITION (F5.2)

  La superficie de Disponibilidad no se vuelve a animar: sigue en pantalla y lo
  único que cambia es su estado interno, compacto ↔ expandido.

  El alto lo interpola la rejilla, de 0fr a 1fr. Es la vía estable para animar
  una altura desconocida sin medirla en JS y sin recurrir a max-height con un
  valor inventado. Deliberadamente con easing SIMPLE: la curva con overshoot
  sobre una dimensión haría rebotar el layout —y con `0fr` puede llegar a
  valores negativos—, así que el carácter lo aporta el transform del contenido,
  no la geometría.
*/
.mp360-legend__values {
    flex: 0 0 auto;
    /* Recorta el contenido mientras el alto se contrae. */
    overflow: hidden;
    height: 0;
    border-top: 1px solid rgba(10, 52, 37, 0.12);
    transition: height var(--mp360-dur-disclosure-out) var(--mp360-ease);
}

/*
  El alto lo escribe Legend.setOpen() en píxeles, medido del contenido, y lo
  suelta a `auto` al terminar de abrir. La primera implementación usaba la
  rejilla 0fr→1fr, que evita medir, pero acá la fila `1fr` se resolvía a cero:
  la altura medida es la vía que se puede comprobar en runtime y degrada igual
  en cualquier navegador.

  Easing SIMPLE a propósito: la curva con overshoot sobre una dimensión haría
  rebotar el layout. El carácter lo pone el transform del contenido.
*/
.mp360-legend__values.is-open { transition-duration: var(--mp360-dur-disclosure); }

/* `hidden` sólo en reposo: durante la salida cortaría la transición. */
.mp360-legend__values[hidden] { display: none; }

/*
  Recorta lo que sobra mientras la fila se cierra, y además es lo que se mueve:
  el contenido entra desde arriba y se desvanece. Acá sí va el token espacial —
  es un transform, no una dimensión, así que el overshoot se lee como carácter
  y no mueve el layout de alrededor.
*/
.mp360-legend__values-inner {
    overflow: hidden;
    opacity: 0;
    transform: translateY(-6px);
    transition: opacity var(--mp360-dur-disclosure-out) var(--mp360-ease),
                transform var(--mp360-dur-disclosure-out) var(--ease-mp360-back);
}

.mp360-legend__values.is-open .mp360-legend__values-inner {
    opacity: 1;
    transform: none;
    transition-duration: var(--mp360-dur-disclosure);
}

.mp360-legend__caption {
    margin: var(--mp360-space-3) 0 var(--mp360-space-2);
    font-size: 12px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1.3;
    color: var(--mp360-primary);
}

.mp360-legend__bands { margin: 0; padding: 0; list-style: none; }

/*
  Una fila por banda: muestra de color + cuota. Nada más. Con las cuatro
  cifras esto se leía como una tabla financiera, que es el rol del cotizador y
  no el de una leyenda — cuya función es orientar de un vistazo.
*/
.mp360-legend__row {
    display: flex;
    align-items: center;
    gap: var(--mp360-space-3);
    padding: 6px 0;
    font-size: 13px;
    line-height: 1.25;
}

.mp360-legend__row + .mp360-legend__row { border-top: 1px solid rgba(10, 52, 37, 0.08); }

.mp360-legend__v { font-variant-numeric: tabular-nums; white-space: nowrap; }

.mp360-legend__foot {
    margin: var(--mp360-space-3) 0 0;
    font-size: 11px;
    line-height: 1.4;
    color: var(--mp360-text);
    opacity: 0.6;
}

/*
  Tablet vertical. Acá la leyenda conserva su forma completa —hay alto de
  sobra— pero a 768px de ancho la columna izquierda de 320px ya no pasa de
  largo junto al selector centrado: su esquina inferior derecha se montaba
  sobre la flecha izquierda del stepper. Defecto preexistente, detectado al
  medir esta pasada.

  Se resuelve con la misma elevación medida que usa móvil, sin cambiar nada
  más de su composición.
*/
@media (min-width: 768px) and (max-width: 1023px) {
    .mp360-legend {
        bottom: calc(var(--mp360-space-6) + var(--mp360-safe-bottom) + var(--mp360-legend-lift, 0px));
        max-height: calc(100dvh - var(--mp360-legend-lift, 0px) - 160px);
    }
}

@media (max-width: 767px) {
    .mp360-legend {
        left: var(--mp360-space-3);
        right: var(--mp360-space-3);
        width: auto;
        /*
          El selector ocupa la banda inferior central; la leyenda se apoya
          sobre él. El alto lo mide Legend.lift() porque cambia con el rótulo
          de escena.
        */
        bottom: calc(var(--mp360-space-4) + var(--mp360-safe-bottom) + var(--mp360-legend-lift, 0px));
        /*
          Nunca por encima de la navbar, cualquiera sea la elevación. Con las
          bandas ya simplificadas a una cifra, 52dvh alcanza para que las seis
          entren sin scroll y sigue dejando media pantalla de panorama.
        */
        max-height: min(52dvh, calc(100dvh - var(--mp360-legend-lift, 0px) - 120px));
        padding: var(--mp360-space-2) var(--mp360-space-3);
    }

}

/* --------------------------------------------------------------------------
   ESTADO COMPACTO DE LA LEYENDA

   Se aplica donde el alto es el recurso en disputa: móvil vertical y apaisado.
   Cerrada, la leyenda ocupaba 188px de 844 en vertical —un cuarto de la
   pantalla— y 154 de 390 en apaisado —un 39%— para información que es
   contextual, no protagonista. Acá el panorama recupera ese espacio: los dos
   estados pasan a una sola fila, y esa fila es el disparador.

   Lo que se retira NO se pierde. La nota explicativa —lo único que aclara que
   el color es PRECIO y no disponibilidad— y los valores de referencia vuelven
   al desplegar, con la misma animación de siempre. En una superficie chica ese
   texto se lee cuando se lo pide, que es mejor que competir permanentemente
   con el recorrido.

   Tablet y escritorio no entran acá: ahí la leyenda funciona como está
   aprobada y no hay altura que disputar.
   -------------------------------------------------------------------------- */

@media (max-width: 767px),
       (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .mp360-legend__states,
    .mp360-legend__note,
    .mp360-legend__toggle { display: none; }

    .mp360-legend__compact {
        display: flex;
        align-items: center;
        gap: var(--mp360-space-3);
        width: 100%;
        /* Bajo los 44px de referencia, pero es una fila de una superficie
           secundaria y el alto es justamente el recurso en disputa. */
        min-height: 40px;
        margin: 0;
        padding: 0;
        border: 0;
        background: none;
        color: inherit;
        font: inherit;
        cursor: pointer;
        text-align: left;
    }

    /* Los dos estados, en fila. */
    .mp360-legend__states--compact {
        display: flex;
        flex-direction: row;
        align-items: center;
        flex-wrap: wrap;
        gap: var(--mp360-space-2) var(--mp360-space-4);
        flex: 1 1 auto;
        min-width: 0;
        margin: 0;
    }

    .mp360-legend__states--compact .mp360-legend__state { font-size: 12px; }

    /* El chevron es lo único que dice "esto se abre": queda al margen derecho
       y con el color de acción del sistema. */
    .mp360-legend__compact .mp360-legend__chev {
        margin-left: auto;
        color: var(--mp360-accent);
    }

    /* La nota vuelve dentro del desplegable, no sobre la fila compacta. */
    .mp360-legend__note--inline {
        display: block;
        margin: 0 0 var(--mp360-space-2);
        font-size: 11px;
    }

    .mp360-legend__caption { margin-top: 0; }
}

/* --------------------------------------------------------------------------
   APAISADO — DISPONIBILIDAD EN UNA SOLA FILA (disclosure compacto)

   El alto es lo escaso. Cerrada, la leyenda ocupaba 116px de 375 —un 31% de la
   pantalla— apilando cuatro bloques que en apaisado no tienen por qué convivir:
   identidad, estados, acciones y disclosure.

   Acá quedan visibles únicamente las dos cosas que se hacen desde la
   disponibilidad —leer los estados y filtrar— en una fila de 40px que, con el
   padding de la card, da 56px. El resto —qué superficie es, de qué etapa, la
   nota que aclara que el color es PRECIO y la tabla de valores— pasa al
   desplegable: se lee cuando se lo pide.

   Por qué NO se amontonó todo en una fila única (DESIGN.md §4): la variante con
   identidad + estados + filtro en línea pedía 555px, el 83% del ancho a 667, y
   cruzaba la franja central del selector. Medido, no estimado.

   La composición es una rejilla y no una columna flex porque la fila compacta y
   el filtro son HERMANOS en el DOM —el filtro lo cuelga LotFilterUI de
   `__actions`— y tenían que terminar en la misma línea sin mover el marcado.
   -------------------------------------------------------------------------- */

@media (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .mp360-legend {
        /* En apaisado el notch va al COSTADO: el inset lateral no es decorativo. */
        left: max(var(--mp360-space-3), var(--mp360-safe-left));
        right: auto;
        /*
          La fila necesita ~349px para entrar en una sola línea: 217 de los dos
          estados con sus muestras, el chevron, el filtro de 84 y los pasos de
          separación. Los 400 dejan aire; el 60vw evita que en un teléfono
          angosto la card se coma la mitad útil del panorama —por debajo de
          ~350px de card los estados se apilan en dos líneas dentro de la misma
          fila de 40, que sigue entrando—.
        */
        width: min(400px, 60vw);
        bottom: calc(var(--mp360-space-2) + var(--mp360-safe-bottom) + var(--mp360-legend-lift, 0px));
        /*
          Cuánto puede crecer hacia arriba al desplegarse. Dos topes:

          El desplazamiento inferior propio —el mismo que fija `bottom`— se
          descuenta también: sin eso el tope se corría 8px y la separación
          contra lo de arriba se comía dos tercios.

            piso   dónde termina "Volver al inicio" más un paso de la escala.
                   Se escribe con SU misma expresión —navbar de 52 + paso +
                   alto de 36— en lugar de un 112 suelto: si el home se mueve,
                   esta línea se mueve con él, y el safe-top entra solo.
            guard  lo que reserva el navegador de plan cuando está abierto, que
                   vive en ESTA MISMA columna y por encima. Lo mide Legend.lift()
                   con el mismo mecanismo que ya usa para el selector, porque su
                   alto cambia con el rótulo del plan.

          Cerrada la leyenda ya no llega hasta ahí —son 56px—, así que el solape
          de 27px con la tarjeta de plan desaparece por composición. Este tope
          es lo que impide que vuelva al desplegarse.
        */
        max-height: calc(100dvh
                         - var(--mp360-space-2) - var(--mp360-safe-bottom)
                         - var(--mp360-legend-lift, 0px)
                         - max(calc(var(--mp360-safe-top) + 52px + var(--mp360-space-3)
                                    + 36px + var(--mp360-space-3)),
                               var(--mp360-legend-guard, 0px)));
        padding: var(--mp360-space-2) var(--mp360-space-3);

        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        grid-template-areas:
            "identidad identidad"
            "estados   filtro"
            "valores   valores";
        /* Sin row-gap: la fila de identidad no existe mientras esté cerrada y
           un gap sobre una pista vacía dejaría aire fantasma sobre la fila. */
        gap: 0 var(--mp360-space-3);
    }

    /*
      Identidad bajo demanda. "Disponibilidad" + la etapa contestan qué se está
      mirando, y eso importa al leer la tabla de valores —no al mirar el
      panorama, donde los dos estados con su color ya se explican solos—.
      Así que aparece con el desplegable, junto a lo que contextualiza.
    */
    .mp360-legend__head { grid-area: identidad; display: none; }

    .mp360-legend.is-open .mp360-legend__head {
        display: flex;
        margin-bottom: var(--mp360-space-2);
    }

    .mp360-legend__compact { grid-area: estados; min-height: 36px; }

    /* Ya no es una fila propia: es la segunda columna de la fila compacta.
       El `margin-top` se anula más abajo, junto a la regla base —misma
       especificidad, y la base se declara después—. */
    .mp360-legend__actions { grid-area: filtro; }

    .mp360-legend__values { grid-area: valores; }

    /*
      El chevron deja de irse al margen derecho: pegado a los estados dice de
      qué control depende. Con `margin-left: auto` quedaba lamido contra
      "Filtrar" y se leía como si abriera el filtro.
    */
    .mp360-legend__compact .mp360-legend__chev { margin-left: 0; }

    /*
      Cuatro píxeles menos entre estados —es lo que separa que la fila entre en
      una línea o pase a dos en los apaisados más angostos— y sin `flex-grow`,
      para que el sobrante de la columna quede DESPUÉS del chevron y no entre
      los estados y él.
    */
    .mp360-legend__states--compact {
        flex: 0 1 auto;
        gap: var(--mp360-space-2) var(--mp360-space-3);
    }
}

/* --------------------------------------------------------------------------
   panoramas — selección visual de vistas (F4.1)
   -------------------------------------------------------------------------- */

.mp360-panoramas { display: flex; flex-direction: column; min-height: 0; }

.mp360-panoramas__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--mp360-space-3);
    flex: 0 0 auto;
    padding: var(--mp360-space-3) var(--mp360-space-3) var(--mp360-space-3) var(--mp360-space-6);
    border-bottom: 1px solid rgba(10, 52, 37, 0.12);
}

.mp360-panoramas__title { margin: 0; font-size: 20px; line-height: 1.2; color: var(--mp360-primary); }

.mp360-panoramas__scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--mp360-space-6);
}

/*
  Los dos grupos, uno al lado del otro. `align-items: start` evita que el
  grupo más corto estire sus miniaturas para igualar al otro.
*/
.mp360-panoramas__groups {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
    gap: var(--mp360-space-8);
}

/* Separación entre grupos sin cerrar cajas: una línea fina, no un marco. */
.mp360-panoramas__group + .mp360-panoramas__group {
    padding-left: var(--mp360-space-8);
    border-left: 1px solid rgba(10, 52, 37, 0.12);
}

.mp360-panoramas__group-title {
    margin: 0;
    font-size: 17px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1.2;
    color: var(--mp360-primary);
}

.mp360-panoramas__group-desc {
    margin: var(--mp360-space-1) 0 var(--mp360-space-4);
    max-width: 42ch;
    font-size: 14px;
    line-height: 1.4;
    color: var(--mp360-text);
    opacity: 0.7;
}

/* Seis miniaturas por grupo: 3 × 2 fija, no auto-fill. */
.mp360-panoramas__grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--mp360-space-3);
}

/* La miniatura es la información principal; el rótulo, secundario. */
.mp360-panoramas__item {
    position: relative;
    display: block;
    padding: 0;
    border: 2px solid transparent;
    border-radius: var(--mp360-radius);
    overflow: hidden;
    background: #EDEFEA;
    cursor: pointer;
    transition: transform var(--mp360-dur-micro-lg) var(--ease-mp360-back),
                border-color var(--mp360-dur-base) var(--mp360-ease),
                box-shadow var(--mp360-dur-base) var(--mp360-ease);
}

.mp360-panoramas__item:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 20px rgba(10, 52, 37, 0.28);
}

.mp360-panoramas__item:active { transform: translateY(0); }

/* Vista actual: borde + ordinal lleno + rótulo con palabras, no sólo color. */
.mp360-panoramas__item.is--current { border-color: var(--mp360-accent); }
.mp360-panoramas__item.is--current .mp360-panoramas__cap { background: var(--mp360-accent); }

.mp360-panoramas__img {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    background: #EDEFEA;
}

/*
  El ordinal va sobre la miniatura, no en una franja debajo: con doce
  miniaturas cada franja de texto costaba una fila entera de alto y el
  encabezado del grupo ya dice de qué tipo de vista se trata.
*/
.mp360-panoramas__cap {
    position: absolute;
    top: var(--mp360-space-2);
    left: var(--mp360-space-2);
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 24px;
    height: 24px;
    padding: 0 6px;
    border-radius: var(--mp360-radius);
    font-family: inherit;
    font-size: 13px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1;
    color: var(--mp360-on-primary);
    background: var(--mp360-primary);
    transition: background-color var(--mp360-dur-base) var(--mp360-ease);
}

.mp360-panoramas__now {
    position: absolute;
    right: var(--mp360-space-2);
    bottom: var(--mp360-space-2);
    padding: 3px var(--mp360-space-2);
    border-radius: var(--mp360-radius);
    font-size: 11px;
    font-weight: var(--mp360-weight-medium);
    line-height: 1.2;
    color: var(--mp360-on-accent);
    background: var(--mp360-accent);
}

/*
  Tablet. Las dos columnas de grupo dejarían miniaturas por debajo de 130px,
  así que los grupos se apilan — pero cada uno pasa a una sola fila de seis.
  Sigue aprovechando todo el ancho, mantiene la miniatura en un tamaño donde
  la escena se reconoce y evita que las doce necesiten scroll.
*/
@media (max-width: 1023px) {
    .mp360-panoramas__groups { grid-template-columns: minmax(0, 1fr); gap: var(--mp360-space-6); }
    .mp360-panoramas__group + .mp360-panoramas__group {
        padding-left: 0;
        padding-top: var(--mp360-space-6);
        border-left: 0;
        border-top: 1px solid rgba(10, 52, 37, 0.12);
    }
    .mp360-panoramas__grid { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--mp360-space-2); }
}

/* Teléfono: dos por fila para no bajar de un touch target cómodo. */
@media (max-width: 767px) {
    .mp360-panoramas__scroll { padding: var(--mp360-space-4); }
    .mp360-panoramas__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .mp360-panoramas__group-desc { font-size: 13px; margin-bottom: var(--mp360-space-3); }
}

/*
  Apaisado: el alto es el recurso escaso. Vuelven las dos columnas de grupo
  —cuestan ancho, que sobra— y el conjunto se compacta.
*/
@media (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .mp360-panoramas__scroll { padding: var(--mp360-space-3) var(--mp360-space-4); }
    .mp360-panoramas__groups { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--mp360-space-4); }
    .mp360-panoramas__group + .mp360-panoramas__group {
        padding-left: var(--mp360-space-4);
        padding-top: 0;
        border-left: 1px solid rgba(10, 52, 37, 0.12);
        border-top: 0;
    }
    .mp360-panoramas__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--mp360-space-2); }
    .mp360-panoramas__group-title { font-size: 15px; }
    .mp360-panoramas__group-desc { font-size: 12px; margin-bottom: var(--mp360-space-2); }
}

/* --------------------------------------------------------------------------
   gallery — Osmo Parallax Image Gallery with Thumbnails

   La mecánica del recurso está intacta en mp360.js. Lo que se rehízo en F4.2
   es la presentación: la galería dejó de ser un modal con cabecera, título y
   epígrafe —tres capas compitiendo con la foto— y pasó a ser fotografía a
   sangre sobre un velo dominante, con los thumbnails inmediatamente debajo.

   Dos desviaciones respecto del recurso, ambas pedidas:
   · la fotografía principal usa `contain` en vez de `cover`, para verse
     completa y sin deformar; los thumbnails conservan el crop;
   · el escenario adopta la proporción de la foto activa en lugar de ocupar
     todo el alto disponible. Ese era el origen de las franjas negras en
     móvil: una foto 16:9 encajada en una caja casi vertical.
   -------------------------------------------------------------------------- */

/*
  Velo dominante: con la galería abierta el recorrido no debe competir. No es
  un rectángulo negro dentro de la pantalla — es la pantalla.
*/
.mp360-surface[data-surface="gallery"] { padding: 0; }
.mp360-surface[data-surface="gallery"] .mp360-surface__scrim { background: #0B0B0B; }
.mp360-surface[data-surface="gallery"].is-open .mp360-surface__scrim { opacity: 0.97; }

.mp360-surface__body[data-type="gallery"] {
    width: 100%;
    height: 100%;
    background: none;
    border-radius: 0;
    box-shadow: none;
}

.mp360-gallery {
    display: flex;
    flex-direction: column;
    min-height: 0;
    padding: var(--mp360-space-4);
    padding-top: max(var(--mp360-space-4), calc(var(--mp360-safe-top) + var(--mp360-space-4)));
    padding-bottom: max(var(--mp360-space-4), var(--mp360-safe-bottom));
}

/* Cerrar flotante: el único cromo persistente sobre la fotografía. */
.mp360-gallery > .mp360-surface__close {
    position: absolute;
    top: max(var(--mp360-space-3), var(--mp360-safe-top));
    right: max(var(--mp360-space-3), var(--mp360-safe-right));
    z-index: 3;
    background: rgba(255, 255, 255, 0.14);
    color: #FFFFFF;
    backdrop-filter: blur(6px);
}

.mp360-gallery > .mp360-surface__close:hover { background: rgba(255, 255, 255, 0.26); }

/*
  Columna: escenario arriba, thumbnails debajo. En el recurso los thumbs van
  absolutos sobre la foto; acá van en flujo para que queden pegados a la
  fotografía sea cual sea su proporción, en vez de anclados al fondo de una
  caja vacía. Mecánica y `data-slideshow` sin cambios.
*/
.img-slider {
    grid-column-gap: 1rem;
    grid-row-gap: 1rem;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    width: 100%;
    /* El recurso usa 100vh; acá vive dentro de una superficie. */
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    position: relative;
    touch-action: pan-y;
}

/*
  Escenario. `--mp360-slide-ar` lo escribe mp360.js con la proporción natural
  de la fotografía activa; el 16/9 es sólo el valor de arranque.
*/
.img-slider__list {
    grid-template-rows: 100%;
    grid-template-columns: 100%;
    place-items: center;
    aspect-ratio: var(--mp360-slide-ar, 16 / 9);
    width: 100%;
    height: auto;
    max-width: 100%;
    max-height: 100%;
    display: grid;
    overflow: hidden;
    border-radius: var(--mp360-radius);
}

/*
  Cuando el alto es el recurso escaso —desktop apaisado, móvil horizontal— la
  proporción manda desde el alto para que la foto no se recorte contra el
  borde inferior ni empuje los thumbnails fuera de pantalla.
*/
@media (min-aspect-ratio: 3 / 2) {
    .img-slider__list { width: auto; height: 100%; }
}

.img-slide {
    opacity: 0;
    pointer-events: none;
    will-change: transform, opacity;
    grid-area: 1 / 1 / -1 / -1;
    place-items: center;
    width: 100%;
    height: 100%;
    display: grid;
    position: relative;
    overflow: hidden;
}

.img-slide.is--current { opacity: 1; pointer-events: auto; }

/*
  DESVIACIÓN respecto del recurso: `contain` en vez de `cover`.
  La fotografía se ve completa, centrada y sin deformar; el matte negro
  aparece cuando la proporción del viewport no coincide con la de la foto.
*/
.img-slide__inner {
    object-fit: contain;
    will-change: transform;
    width: 100%;
    height: 100%;
    position: absolute;
    user-select: none;
    -webkit-user-drag: none;
}

/*
  Thumbnails en flujo, pegados a la fotografía. El ancho fluido hace que las
  ocho entren en una sola fila en desktop y envuelvan sólo cuando realmente no
  caben, en vez de partirse por un ancho fijo.
*/
.img-slider__nav {
    z-index: 2;
    grid-column-gap: .5rem;
    grid-row-gap: .5rem;
    flex-flow: wrap;
    justify-content: center;
    align-items: center;
    flex: 0 0 auto;
    max-width: 100%;
    display: flex;
    position: relative;
}

.img-slider__thumb {
    aspect-ratio: 1.5;
    pointer-events: auto;
    cursor: pointer;
    border: 1px solid #fff3;
    border-radius: var(--mp360-radius);
    width: clamp(4rem, 8vw, 7rem);
    transition: border-color var(--mp360-dur-fast) var(--mp360-ease);
    position: relative;
    overflow: hidden;
}

.img-slider__thumb:hover { border-color: #fff6; }
.img-slider__thumb.is--current { border-color: #fff; }
.img-slider__thumb:focus-visible { outline: 2px solid var(--mp360-accent); outline-offset: 2px; }

/* Los thumbnails sí recortan: es lo que les da consistencia. */
.slider-thumb__img { object-fit: cover; width: 100%; height: 100%; display: block; }

@media screen and (max-width: 767px) {
    .mp360-gallery { padding: var(--mp360-space-2); }
    .img-slider { grid-row-gap: .75rem; }
    /* Reconocible y cómodo al pulgar sin comerse media pantalla. */
    .img-slider__thumb { width: clamp(4.25rem, 22vw, 6rem); }
}

/* Móvil apaisado: el alto es el recurso escaso, los thumbs se achican. */
@media (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .img-slider__thumb { width: clamp(3rem, 7vw, 4.5rem); }
    /* Target táctil del lightbox: la regla estaba sólo en vertical y acá
       conservaba el tamaño de escritorio, pensado para mouse. */
    .mp360-lightbox__nav { width: 44px; height: 44px; }
    .mp360-gallery { padding: var(--mp360-space-2); }
    .img-slider { grid-row-gap: .75rem; }
}

/* --------------------------------------------------------------------------
   viewer — Plano

   Rediseñado en F4.1: el problema no era el asset sino la composición. Antes
   era una card alta con la imagen arriba y mucho blanco debajo. Ahora es un
   visor: fondo neutro oscuro, imagen protagonista ocupando todo el escenario
   y controles flotando encima en vez de reservar una franja propia.
   -------------------------------------------------------------------------- */

/*
  El visor ya NO reserva el alto completo. Antes tomaba `height: 100%` porque
  sin alto intrínseco colapsaba a una franja; el efecto colateral era que en
  móvil el plano —horizontal, ≈1.87:1— quedaba arriba y debajo sobraba media
  pantalla oscura. Ahora el alto lo fija la proporción real del contenido
  (ver `--mp360-viewer-ar` más abajo) y la superficie crece con él.
*/
.mp360-surface__body[data-type="viewer"] {
    height: auto;
    background: #14181A;
}

/*
  El wrapper interno es un flex item del body: sin esto no hereda la altura
  y el escenario se desborda por debajo de la superficie.
*/
.mp360-surface__body > .mp360-viewer,
.mp360-surface__body > .mp360-gallery,
.mp360-surface__body > .mp360-panoramas,
.mp360-surface__body > .mp360-map,
.mp360-surface__body > .mp360-steps,
.mp360-surface__body > .mp360-about,
.mp360-surface__body > .mp360-card {
    flex: 1 1 auto;
    min-height: 0;
}

/*
  Sin cabecera. Antes había una barra con el rótulo "Plano de Tipuana" y su
  scrim; el rótulo era redundante —se llega desde el ítem "Plano" del menú— y
  la barra ocupaba ~60px sobre un escenario que en móvil mide ~190px. Queda
  sólo el cerrar, flotante sobre la imagen, igual que en la galería.
*/
.mp360-viewer > .mp360-surface__close {
    position: absolute;
    top: var(--mp360-space-3);
    right: var(--mp360-space-3);
    z-index: 3;
    background: rgba(255, 255, 255, 0.16);
    color: #FFFFFF;
    backdrop-filter: blur(6px);
}

.mp360-viewer > .mp360-surface__close:hover { background: rgba(255, 255, 255, 0.28); }

.mp360-viewer {
    display: flex;
    flex-direction: column;
    min-height: 0;
    /* Ancla de los controles flotantes: quedan sobre el plano, no al fondo
       de una superficie que ya no ocupa toda la pantalla. */
    position: relative;
}

/* El visor se ajusta a su contenido en vez de estirarse. */
.mp360-surface__body[data-type="viewer"] > .mp360-viewer { flex: 0 1 auto; }

/* El plano se ve completo y sin deformar; el matte lo da el fondo del visor. */
.mp360-viewer__img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
    transform-origin: center center;
    transition: transform var(--mp360-dur-base) var(--mp360-ease-osmo);
    will-change: transform;
    user-select: none;
    -webkit-user-drag: none;
}

/*
  El escenario toma la proporción real del plano —mp360.js escribe
  `--mp360-viewer-ar` desde naturalWidth/naturalHeight— en vez de un alto
  arbitrario. El fallback 16/9 sólo aplica si la imagen todavía no cargó.
  `max-height` evita que en móvil apaisado se salga de la pantalla; ahí
  `object-fit: contain` se ocupa del resto.
*/
.mp360-viewer__stage {
    position: relative;
    flex: 0 1 auto;
    aspect-ratio: var(--mp360-viewer-ar, 16 / 9);
    width: 100%;
    max-height: 100%;
    min-height: 0;
    overflow: hidden;
    background: #14181A;
    cursor: grab;
    touch-action: none;
}

/* Controles flotantes: no reservan alto propio. */
.mp360-viewer__controls {
    position: absolute;
    left: 50%;
    bottom: var(--mp360-space-4);
    transform: translateX(-50%);
    z-index: 2;
    display: flex;
    gap: var(--mp360-space-2);
    padding: var(--mp360-space-1);
    border-top: 0;
    border-radius: var(--mp360-radius);
    background: rgba(0, 0, 0, 0.55);
}

.mp360-viewer__zoom {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    min-width: 44px;
    min-height: 44px;
    flex: 0 0 auto;
    border: 1px solid rgba(255, 255, 255, 0.28);
    border-radius: var(--mp360-radius);
    background: none;
    color: #FFFFFF;
    font-family: inherit;
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
}

.mp360-viewer__zoom:disabled { opacity: 0.35; cursor: default; }

.mp360-viewer__zoom:hover:not(:disabled) { background: rgba(255, 255, 255, 0.16); }

/* --------------------------------------------------------------------------
   Intro — Osmo Dropping Cards Loading Animation

   CSS del recurso. Adaptado: fondo #0A3425, wordmark "Tipuana" en Roboto en
   lugar del SVG original, y radius bajo en vez de .5em para no romper la
   geometría recta del proyecto.
   -------------------------------------------------------------------------- */

.loading-container {
    z-index: 100;
    pointer-events: none;
    position: fixed;
    inset: 0;
}

.loading-screen {
    pointer-events: auto;
    color: var(--mp360-white);
    justify-content: center;
    align-items: center;
    width: 100%;
    height: 100%;
    display: flex;
    position: absolute;
    top: 0;
    left: 0;
    overflow: clip;
}

.loading-screen__background {
    background-color: var(--mp360-primary);
    width: 100%;
    height: 100%;
    position: absolute;
}

/* Wordmark en texto: no se usan assets del recurso original. */
.loading-screen__logo {
    position: absolute;
    bottom: 2em;
    font-family: var(--mp360-font);
    font-size: clamp(1.25rem, 3vw, 2rem);
    font-weight: var(--mp360-weight-medium);
    letter-spacing: 0.08em;
    color: var(--mp360-white);
}

.loading-screen__list {
    grid-column-gap: .5em;
    grid-row-gap: .5em;
    opacity: 0;
    justify-content: center;
    align-items: center;
    display: flex;
    position: relative;
}

.loading-screen__card {
    aspect-ratio: 3 / 4;
    border-radius: var(--mp360-radius);
    width: 10em;
    font-size: max(1.5vw, 2em);
    position: absolute;
    overflow: hidden;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45);
    /*
      Las cards se animan sólo por transform. Promoverlas a capa propia evita
      repintar las cinco fotografías en cada frame mientras el motor 3DVista
      inicializa en el mismo hilo. El contenedor se elimina al terminar la
      intro, así que no queda ninguna capa viva después.
    */
    will-change: transform;
}

.cover-image {
    object-fit: cover;
    border-radius: inherit;
    width: 100%;
    height: 100%;
    display: block;
    position: absolute;
    top: 0;
    left: 0;
}

/* Evita barras de scroll mientras el contenido escala durante el reveal. */
html.mp360-intro-active,
html.mp360-intro-active body { overflow: clip; }

/* --- escena B: reveal editorial "Tipuana" --- */

/*
  El recurso lo resuelve con una `section` de 100svh en flujo. Acá la intro
  vive por encima del recorrido, así que va fija sobre él —por debajo de la
  pantalla de carga, que es la que se retira para descubrirla.
*/
.loading-header {
    z-index: 90;
    position: fixed;
    inset: 0;
    justify-content: center;
    align-items: center;
    min-height: 100svh;
    display: flex;
    overflow: clip;
    background-color: var(--mp360-primary);
    will-change: transform, opacity;
}

/*
  Alto 130%, como en el recurso: el desplazamiento vertical del reveal no
  descubre el borde de la fotografía.
*/
.cover-image.is--bg { height: 130%; will-change: transform; }

/*
  Espera y salida en CSS, no en GSAP, y a propósito.

  En esa ventana exacta el motor está inicializando y J3DV pinta ~1900
  hotspots de disponibilidad: medido, el hilo principal queda ocupado varios
  segundos seguidos y cualquier tween del ticker se arrastra —la salida de
  0.8 s llegó a tardar 5.6 s—. Una transición de opacity y una animación de
  transform las resuelve el compositor y salen fluidas igual. El export no se
  toca; el problema se absorbe desde la capa MP360.
*/
.loading-header.is-holding .cover-image.is--bg {
    animation: mp360-reveal-drift 14s linear forwards;
}

@keyframes mp360-reveal-drift {
    from { transform: scale(1); }
    to   { transform: scale(1.06); }
}

/* 0.6s: permanencia editorial de la escena final, acortada un 25% en F4.3.
   Debe coincidir con EXIT_MS en mp360.js. */
.loading-header { transition: opacity 0.6s var(--mp360-ease-osmo); }

/*
  `pointer-events: none` desde el primer frame de la salida: la transición la
  resuelve el compositor, pero el nodo se retira del DOM en el hilo principal,
  que en ese momento puede estar ocupado por la inicialización del motor. Sin
  esto, una capa ya invisible seguiría interceptando el toque unos segundos.
*/
.loading-header.is-leaving { opacity: 0; pointer-events: none; }

/*
  Velo suave: la palabra tiene que leerse sobre una aérea con mucho detalle.
  Blanco puro sobre el velo queda muy por encima de AA.
*/
.loading-header::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(to bottom,
                rgba(21, 21, 21, 0.15),
                rgba(21, 21, 21, 0.45));
}

/*
  Rol A · Display. Instrument Sans a gran escala, con sus propias métricas: no
  se imita ninguna otra fuente por transform ni por font-stretch.
  Regular, no Bold — a 19vw el peso lo aporta la escala— y el tracking cerrado
  del recurso Osmo (-.04em) es lo que cierra la palabra.
*/
.loading-header__h1 {
    position: relative;
    z-index: 1;
    color: var(--mp360-white);
    text-align: center;
    letter-spacing: -.04em;
    white-space: nowrap;
    margin-top: 0;
    margin-bottom: 10dvh;
    font-family: var(--mp360-font-display);
    font-size: min(19vw, 9em);
    font-weight: var(--mp360-weight-regular);
    line-height: 1;
    text-shadow: 0 2px 24px rgba(0, 0, 0, 0.35);
}

@media (max-width: 767px) {
    .loading-screen__card { font-size: max(3.4vw, 1.5em); }
    .loading-screen__logo { bottom: 1.5em; }
    .loading-header__h1 { margin-bottom: 6dvh; }
}

@media (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .loading-screen__card { font-size: max(2vw, 1.1em); }
    .loading-screen__logo { bottom: 1em; font-size: 1.1rem; }
    .loading-header__h1 { font-size: min(14vw, 5em); margin-bottom: 4dvh; }
}

/* --------------------------------------------------------------------------
   Wipe de cambio de panorama — Osmo Page Name Transition
   -------------------------------------------------------------------------- */

.transition {
    z-index: 60;
    pointer-events: none;
    position: absolute;
    inset: 0;
    overflow: clip;
}

.transition__panel {
    background-color: var(--mp360-primary);
    justify-content: center;
    align-items: center;
    width: 100%;
    height: 100%;
    display: flex;
    position: absolute;
    top: 100%;
    left: 0;
    visibility: hidden;
}

.transition__label {
    color: var(--mp360-on-primary);
    font-family: var(--mp360-font);
    font-size: clamp(1.5rem, 5vw, 2.5em);
    font-weight: var(--mp360-weight-medium);
    text-align: center;
    padding: 0 var(--mp360-space-6);
    letter-spacing: 0.01em;
}

@media (max-width: 767px) {
    .transition__label { font-size: clamp(1.25rem, 6vw, 2rem); }
}

/* --------------------------------------------------------------------------
   Responsive de las superficies
   -------------------------------------------------------------------------- */

@media (max-width: 767px) {
    .mp360-surface {
        padding: var(--mp360-space-3);
        padding-top: max(var(--mp360-space-3), calc(var(--mp360-safe-top) + var(--mp360-space-2)));
        padding-bottom: max(var(--mp360-space-3), calc(var(--mp360-safe-bottom) + var(--mp360-space-2)));
    }
    .mp360-surface__body,
    .mp360-surface__body[data-type="viewer"],
    .mp360-surface__body[data-type="gallery"],
    .mp360-surface__body[data-type="poi"],
    .mp360-surface__body[data-type="map"] { width: 100%; }

    /*
      El caso que motivó la fase: en móvil el mapa del POI llegaba dentro de la
      UI del player y compartía pantalla con el minimapa, la disponibilidad y
      el selector. Acá toma la altura completa de la superficie —cabecera
      compacta arriba, mapa abajo— y el resto de la interfaz queda debajo del
      velo, como cualquier otra superficie MP360.
    */
    .mp360-surface__body[data-type="poi"] { height: 100%; }
    .mp360-map--poi .mp360-map__head { padding: var(--mp360-space-3) var(--mp360-space-3) var(--mp360-space-3) var(--mp360-space-4); }
    .mp360-map--poi .mp360-map__title { font-size: 18px; }
    .mp360-map--poi .mp360-map__frame { height: auto; }

    .mp360-card__content,
    .mp360-about__scroll,
    .mp360-steps__stage { padding: var(--mp360-space-4); }

    .mp360-card__title,
    .mp360-about__title { font-size: 22px; }
    .mp360-steps__subtitle { font-size: 20px; }
    .mp360-card__text,
    .mp360-about__text,
    .mp360-steps__text,
    .mp360-card__item { font-size: 15px; }

    .mp360-map__head,
    .mp360-steps__head,
    .mp360-about__head { padding-left: var(--mp360-space-4); }

    /*
      Copy + mapa se reparten la altura: el mapa cede lo justo para que la
      línea de contexto entre, y sigue siendo el elemento dominante.
    */
    .mp360-map__lead {
        padding: var(--mp360-space-3) var(--mp360-space-4);
        font-size: 14px;
    }
    .mp360-map__frame { height: min(50dvh, 420px); }
    .mp360-lightbox__nav { width: 44px; height: 44px; }
}

/*
  Apaisado: la altura es el recurso escaso. La imagen de las cards deja de
  competir con el texto y todo lo que crece pasa a scrollear internamente.
*/
@media (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .mp360-surface {
        padding: var(--mp360-space-2);
        padding-top: max(var(--mp360-space-2), var(--mp360-safe-top));
        padding-bottom: max(var(--mp360-space-2), var(--mp360-safe-bottom));
    }
    .mp360-surface__body { width: min(680px, 100%); }

    .mp360-card { flex-direction: row; }
    .mp360-card__media { flex: 0 0 40%; }
    .mp360-card__img { height: 100%; aspect-ratio: auto; }
    .mp360-card__content { padding: var(--mp360-space-4); }
    .mp360-card__title { font-size: 20px; margin-bottom: var(--mp360-space-2); }
    .mp360-card__text, .mp360-card__item { font-size: 14px; }

    .mp360-about__scroll, .mp360-steps__stage { padding: var(--mp360-space-3) var(--mp360-space-4); }
    .mp360-about__title { font-size: 20px; }
    .mp360-steps__subtitle { font-size: 18px; }

    .mp360-map__lead {
        padding: var(--mp360-space-2) var(--mp360-space-4);
        font-size: 13px;
        line-height: 1.4;
    }
    .mp360-map__frame { height: auto; min-height: 180px; }

    /* Apaisado: la cabecera se reduce a una línea y el embed toma el resto. */
    .mp360-surface__body[data-type="poi"] { height: 100%; }
    .mp360-map--poi .mp360-map__head { padding: var(--mp360-space-2) var(--mp360-space-2) var(--mp360-space-2) var(--mp360-space-4); }
    .mp360-map--poi .mp360-map__title { font-size: 17px; }
    .mp360-map--poi .mp360-map__eyebrow { font-size: 11px; }
}

/* --------------------------------------------------------------------------
   7. Accesibilidad
   -------------------------------------------------------------------------- */

.mp360-visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* ==========================================================================
   14. Experiencia nativa de lote (Fase 3)

   Dos superficies nuevas: el tooltip rápido de hover y la ficha del lote.
   Ninguna introduce tokens, curvas ni tipografías propias — todo sale del
   sistema ya aprobado.
   ========================================================================== */

/* --------------------------------------------------------------------------
   14a. m² con superíndice real

   Instrument Sans no incluye U+00B2, así que el carácter caería en Roboto por
   fallback. Con <sup> el glifo es un 2 de la misma familia y la línea se lee
   homogénea. Se le quita el desplazamiento vertical del <sup> por defecto,
   que en cuerpos pequeños descoloca la línea base.
   -------------------------------------------------------------------------- */

.mp360-root .mp360-m2 { white-space: nowrap; }

.mp360-root .mp360-m2 sup {
    font-size: 0.66em;
    line-height: 0;
    vertical-align: 0.42em;
    margin-left: 0.02em;
}

/* --------------------------------------------------------------------------
   14b. Tooltip de lote

   UN solo elemento para los 987 hotspots. Se posiciona con transform sobre
   coordenadas ya calculadas: nada de layout por frame.

   `pointer-events: none` es obligatorio: el tooltip sigue al cursor y si
   capturara el puntero se interpondría entre el usuario y el propio hotspot,
   rompiendo el drag del panorama.
   -------------------------------------------------------------------------- */

/*
  El fondo y la tinta los escribe LotTooltip.paint() como variables, a partir
  del color de banda del lote y de la misma función de contraste que decide el
  número del marcador. Los valores de aquí son sólo el respaldo si algo no
  llegara a resolverse: el verde de marca, que es el lenguaje base de MP360.

  Geometría, radius, sombra, tipografía, densidad y motion no cambian: el color
  comercial ya aporta suficiente personalidad y no hace falta nada más.
*/
.mp360-lottip {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 30;
    max-width: 260px;
    padding: var(--mp360-space-2) var(--mp360-space-3);
    border-radius: var(--mp360-radius);
    background: var(--mp360-lottip-bg, var(--mp360-primary));
    color: var(--mp360-lottip-ink, var(--mp360-on-primary));
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.32);
    pointer-events: none;
    opacity: 0;
    /* Micro transición: entra desde su propia posición, sin recorrido. */
    transform-origin: top left;
    transition: opacity var(--mp360-dur-fast) var(--mp360-ease);
    will-change: transform;
}

/*
  Disponible sin plan asignado. Sobre un panorama claro, una card blanca sin
  definición se pierde: el anillo interior le devuelve el borde sin agregar un
  borde grueso ni un color que no le corresponde. Se dibuja con la propia tinta
  del tooltip, así que no introduce un valor nuevo.
*/
.mp360-lottip[data-variant="unassigned"] {
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.32),
                inset 0 0 0 1px rgba(10, 52, 37, 0.22);
}

.mp360-lottip.is-visible { opacity: 1; }

.mp360-lottip__id {
    margin: 0;
    font-size: 13px;
    font-weight: var(--mp360-weight-semibold);
    letter-spacing: 0.01em;
    line-height: 1.25;
}

/*
  Los tres niveles se separan por peso y opacidad, no por color propio: heredan
  la tinta que resolvió el contraste, así que la jerarquía se sostiene igual
  sobre el amarillo que sobre el azul o el verde oscuro.
*/
.mp360-lottip__meta {
    margin: 2px 0 0;
    font-size: 12px;
    line-height: 1.3;
    /* Un escalón por debajo de la identidad, que es lo prioritario. Con la
       tinta ya elegida por contraste, 0.82 sigue muy por encima del mínimo
       legible en cualquiera de las nueve variantes. */
    opacity: 0.82;
}

/*
  El plan cierra el tooltip y es lo que le da sentido al color de fondo. Se
  separa del bloque de identidad por peso y opacidad plena, no por un filete:
  se probó uno y sumaba 12px de alto, y el tamaño del tooltip estaba aprobado.
  Con la tinta ya resuelta por contraste, el escalón se lee igual.
*/
.mp360-lottip__plan {
    margin: var(--mp360-space-1) 0 0;
    font-size: 12px;
    font-weight: var(--mp360-weight-medium);
    line-height: 1.3;
}

.mp360-lottip__plan[hidden] { display: none; }

/* --------------------------------------------------------------------------
   14c. Ficha de lote

   Reutiliza el host modal de §6. Lo que cambia por `data-surface="lot"`:

     · en desktop se alinea a un lado y el velo se aligera, para que el
       recorrido siga siendo lo que domina la pantalla — la ficha acompaña al
       360, no lo reemplaza;
     · en móvil se comporta como sheet inferior, que es el patrón ya usado por
       el drawer.
   -------------------------------------------------------------------------- */

.mp360-surface[data-surface="lot"] .mp360-surface__scrim { background: var(--mp360-overlay); }

.mp360-surface[data-surface="lot"].is-open .mp360-surface__scrim { opacity: 0.34; }

.mp360-surface__body[data-type="lot"] { width: min(420px, 100%); }

/*
  Desde tablet en adelante la ficha se recuesta a un lado en vez de ocupar el
  centro: deja libre la mayor parte del panorama, incluidos el selector y la
  leyenda de la esquina inferior. La ficha acompaña al recorrido; no lo tapa.
*/
@media (min-width: 641px) {
    .mp360-surface[data-surface="lot"] {
        justify-content: flex-end;
        /*
          Y arranca por debajo de la navbar. A diferencia de los demás paneles
          —que son modales y toman la pantalla entera— la ficha convive con el
          recorrido, así que no puede taparle al usuario el logo, el menú ni el
          CTA de contacto. 72px es el alto de la navbar en este rango.
        */
        align-items: flex-start;
        padding-top: calc(72px + var(--mp360-space-3));
    }
    .mp360-surface__body[data-type="lot"] { width: 400px; }
}

/* Entre 641 y 767px la navbar mide 60px, no 72. */
@media (min-width: 641px) and (max-width: 767px) {
    .mp360-surface[data-surface="lot"] { padding-top: calc(60px + var(--mp360-space-3)); }
}

/*
  Móvil apaisado: 390px de alto es todo lo que hay, y la navbar se lleva 52.
  La ficha se alinea arriba y arranca por debajo de la navbar en lugar de
  centrarse sobre ella, que es donde están el logo y el acceso al menú.
*/
@media (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .mp360-surface[data-surface="lot"] {
        align-items: flex-start;
        padding-top: calc(52px + var(--mp360-space-2));
        padding-bottom: var(--mp360-space-2);
    }
}

@media (max-width: 640px) {
    .mp360-surface[data-surface="lot"] {
        align-items: flex-end;
        padding: 0;
    }

    .mp360-surface__body[data-type="lot"] {
        width: 100%;
        max-height: min(86vh, 100%);
        border-radius: var(--mp360-radius) var(--mp360-radius) 0 0;
        /* Entra desde abajo, como el drawer. */
        transform: translateY(24px);
    }

    .mp360-surface[data-surface="lot"].is-open .mp360-surface__body { transform: none; }
}

/*
  La ficha es una columna de tres piezas: identidad arriba, contenido
  scrolleable en el medio y cierre comercial abajo. El pie NO scrollea —es
  hermano del contenedor, no hijo—, así que el CTA queda siempre a la vista sin
  `position: sticky`, sin doble scroll y sin tapar nada.
*/
.mp360-lot {
    display: flex;
    flex-direction: column;
    min-height: 0;
    color: var(--mp360-text);
}

/* --------------------------------------------------------------------------
   Cabecera — identidad

   Tres niveles y ninguno le pelea el renglón al anterior: identidad, estado y
   características. El badge bajó a la línea del metadato; en la fila del
   título competía por el ancho con el botón de cierre y dejaba la esquina
   apretada.
   -------------------------------------------------------------------------- */

.mp360-lot__head {
    position: relative;
    flex: 0 0 auto;
    padding: var(--mp360-space-6) var(--mp360-space-6) var(--mp360-space-4);
    border-bottom: 1px solid rgba(10, 52, 37, 0.1);
}

.mp360-lot__title {
    margin: 0;
    /* Deja libre la esquina del botón de cierre. */
    padding-right: 52px;
    font-size: 22px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1.15;
    letter-spacing: -0.015em;
}

.mp360-lot__head-meta {
    display: flex;
    align-items: center;
    gap: var(--mp360-space-2);
    margin-top: var(--mp360-space-2);
    flex-wrap: wrap;
}

.mp360-lot__badge {
    display: inline-flex;
    align-items: center;
    padding: 2px var(--mp360-space-2);
    border-radius: var(--mp360-radius);
    font-size: 10px;
    font-weight: var(--mp360-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.07em;
}

.mp360-lot__badge[data-state="available"] {
    background: var(--mp360-accent);
    color: var(--mp360-on-accent);
}

/*
  El badge "Vendido" de la ficha sigue al marcador. El tinte se escribe con el
  rojo literal y no con `--mp360-primary`: ese token es el verde de MARCA y
  reusarlo acá fue lo que ató el badge al color equivocado.
*/
.mp360-lot__badge[data-state="sold"] {
    background: rgba(206, 106, 106, 0.14);
    color: #8E3B3B;
}

.mp360-lot__meta {
    margin: 0;
    font-size: 13px;
    opacity: 0.7;
}

.mp360-lot__head .mp360-surface__close {
    position: absolute;
    top: var(--mp360-space-4);
    right: var(--mp360-space-4);
}

/* --------------------------------------------------------------------------
   Cuerpo — ritmo entre bloques

   La separación la hace el espacio, no una línea por bloque: el aire agrupa
   igual de bien y mantiene la ficha ligera. La única superficie interna es la
   del plan, y está porque marca el momento comercial, no por decoración.
   -------------------------------------------------------------------------- */

/*
  Con la sección de intención retirada quedan dos bloques, y la separación se
  reajustó: 32px entre tres secciones daba ritmo, entre dos —y con el plan
  llevando su propia caja con 16px de aire interno— dejaba un vacío de 48px que
  se leía como algo faltante. Con 24 el salto visual queda en 40: sigue
  separando plan de proyección, sin que parezcan una sola sección.
*/
.mp360-lot__scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--mp360-space-6);
    display: flex;
    flex-direction: column;
    gap: var(--mp360-space-6);
}

.mp360-lot__block { display: flex; flex-direction: column; gap: var(--mp360-space-3); }

/* Rótulo de sección: presente, nunca protagonista. */
.mp360-lot__block-title {
    margin: 0;
    font-size: 11px;
    font-weight: var(--mp360-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.09em;
    opacity: 0.55;
}

/* --------------------------------------------------------------------------
   Plan de financiación — el momento comercial más fuerte
   -------------------------------------------------------------------------- */

.mp360-lot__block--plan {
    padding: var(--mp360-space-4);
    border-radius: var(--mp360-radius);
    background: rgba(10, 52, 37, 0.045);
}

.mp360-lot__lead {
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.mp360-lot__lead-count {
    font-size: 13px;
    opacity: 0.7;
}

/* La cifra más fuerte de toda la ficha. */
.mp360-lot__lead-amount {
    font-size: 34px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1;
    letter-spacing: -0.025em;
    font-variant-numeric: tabular-nums;
}

.mp360-lot__consult {
    margin: 0;
    font-size: 17px;
    font-weight: var(--mp360-weight-medium);
}

/* Tres cifras de apoyo, en lista simple. No tres tarjetas. */
.mp360-lot__figures {
    margin: var(--mp360-space-1) 0 0;
    display: flex;
    flex-direction: column;
    gap: var(--mp360-space-2);
    padding-top: var(--mp360-space-3);
    border-top: 1px solid rgba(10, 52, 37, 0.1);
}

.mp360-lot__figure {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--mp360-space-4);
    font-size: 14px;
}

.mp360-lot__figure dt { margin: 0; opacity: 0.64; }
.mp360-lot__figure dd { margin: 0; font-weight: var(--mp360-weight-medium); font-variant-numeric: tabular-nums; }

.mp360-lot__foot {
    margin: 0;
    font-size: 11px;
    line-height: 1.4;
    opacity: 0.5;
}

/* Enlace de acción sobria: los disparadores de los disclosures. */
.mp360-lot__link {
    align-self: flex-start;
    padding: 0;
    border: 0;
    background: none;
    color: var(--mp360-accent);
    font: inherit;
    font-size: 13px;
    font-weight: var(--mp360-weight-medium);
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}

/* --------------------------------------------------------------------------
   Proyección

   `Proyectá tu cuota` es un titular de sección, distinto del rótulo pequeño de
   `Plan de financiación`: uno nombra una herramienta y el otro etiqueta un
   dato. Esa diferencia tipográfica es lo que evita que la cuota proyectada
   compita con la cuota real.
   -------------------------------------------------------------------------- */

.mp360-lot__proj-heading {
    margin: 0;
    font-size: 16px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1.25;
    letter-spacing: -0.005em;
}

.mp360-lot__proj-sub {
    margin: -6px 0 0;
    font-size: 12px;
    line-height: 1.45;
    opacity: 0.65;
}

.mp360-lot__proj-form { display: flex; flex-direction: column; gap: var(--mp360-space-2); }

.mp360-lot__proj-label { font-size: 13px; opacity: 0.72; }

.mp360-lot__proj-row { display: flex; gap: var(--mp360-space-2); flex-wrap: wrap; }

.mp360-lot__proj-input {
    flex: 1 1 150px;
    min-width: 0;
    padding: var(--mp360-space-3);
    border: 1px solid rgba(10, 52, 37, 0.2);
    border-radius: var(--mp360-radius);
    background: var(--mp360-surface);
    color: inherit;
    font: inherit;
    font-size: 15px;
    font-variant-numeric: tabular-nums;
}

.mp360-lot__proj-input:focus-visible { outline: 2px solid var(--mp360-accent); outline-offset: 1px; }

.mp360-lot__proj-cta {
    flex: 0 0 auto;
    min-height: 44px;
    padding: var(--mp360-space-3) var(--mp360-space-4);
    border: 0;
    border-radius: var(--mp360-radius);
    background: var(--mp360-primary);
    color: var(--mp360-on-primary);
    font: inherit;
    font-size: 14px;
    font-weight: var(--mp360-weight-medium);
    cursor: pointer;
    transition: filter var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-lot__proj-cta:hover { filter: brightness(1.25); }

.mp360-lot__proj-error { margin: 0; font-size: 12px; color: #A6301A; }

/*
  Microcopy explicativo (4.1 §5 y §8). Un solo tono para las dos apariciones
  —junto al input y bajo la grilla— porque cumplen la misma función: aclarar
  algo que el número de al lado no dice por sí solo. Nunca es un dato.
*/
.mp360-lot__proj-hint { margin: 0; font-size: 12px; line-height: 1.4; opacity: 0.6; }

/*
  El aumento en pesos (5.0 §14). Es la respuesta a "¿cuánto más voy a pagar?",
  así que se lee como un dato propio y no como un pie de la comparación: aire
  arriba y abajo, y el importe con el mismo peso que las dos cifras de la
  grilla. Sin card dentro de card — lo separa el espacio, no un borde.
*/
.mp360-lot__proj-delta {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-top: var(--mp360-space-2);
}

.mp360-lot__proj-delta-amount {
    margin: 0;
    font-size: 19px;
    font-weight: var(--mp360-weight-semibold);
    font-variant-numeric: tabular-nums;
    line-height: 1.15;
    letter-spacing: -0.015em;
}

.mp360-lot__proj-result {
    display: flex;
    flex-direction: column;
    gap: var(--mp360-space-3);
    margin-top: var(--mp360-space-2);
    padding-top: var(--mp360-space-4);
    border-top: 1px solid rgba(10, 52, 37, 0.1);
}

.mp360-lot__proj-title {
    margin: 0;
    font-size: 11px;
    font-weight: var(--mp360-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.09em;
    opacity: 0.55;
}

/*
  Hoy vs En N meses. Dos columnas comparables, con un filete entre ellas para
  que se lean como una comparación y no como dos datos sueltos.
*/
.mp360-lot__proj-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--mp360-space-4); }

.mp360-lot__proj-col { display: flex; flex-direction: column; gap: 2px; }

.mp360-lot__proj-col + .mp360-lot__proj-col {
    padding-left: var(--mp360-space-4);
    border-left: 1px solid rgba(10, 52, 37, 0.12);
}

.mp360-lot__proj-when {
    margin: 0;
    font-size: 11px;
    font-weight: var(--mp360-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    opacity: 0.5;
}

.mp360-lot__proj-cap { margin: 0; font-size: 12px; opacity: 0.7; }

.mp360-lot__proj-amount {
    margin: 1px 0 0;
    font-size: 21px;
    font-weight: var(--mp360-weight-semibold);
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
    letter-spacing: -0.015em;
}

/* Ahora es una frase completa, no un dato suelto: necesita interlínea de texto. */
.mp360-lot__proj-ratio { margin: 2px 0 0; font-size: 12px; opacity: 0.72; line-height: 1.45; }

/*
  La frase que cierra el resultado. Es lo que hay que leer, no un pie, y con la
  jerarquía de 5.0 §14 llega después del aumento en pesos: por eso se separa
  más de lo que la separa el `gap` del contenedor.
*/
.mp360-lot__proj-read {
    margin: var(--mp360-space-2) 0 0;
    font-size: 14px;
    font-weight: var(--mp360-weight-medium);
    line-height: 1.5;
}

/*
  Referencia del 22%. Desde 5.0 §16 vive dentro de "¿Cómo se calcula?", cerrando
  la lista de supuestos, y por eso lleva margen positivo: el negativo anterior
  compensaba el `gap` del resultado, un contenedor en el que ya no está.

  El punto de color acompaña a la palabra "por debajo" / "por encima": nunca es
  el único portador del dato, y por eso no funciona como semáforo.
*/
.mp360-lot__proj-refnote {
    margin: var(--mp360-space-3) 0 0;
    display: flex;
    align-items: baseline;
    gap: var(--mp360-space-2);
    font-size: 12px;
    line-height: 1.45;
    opacity: 0.62;
}

.mp360-lot__proj-refnote::before {
    content: "";
    flex: 0 0 auto;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    opacity: 0.55;
}

.mp360-lot__proj-refnote[data-within="true"]::before { background: var(--mp360-accent); opacity: 1; }

/*
  Segundo nivel (4.1 §10). Quien sólo quiere una orientación tiene que poder
  proyectar, entender y cerrar sin abrir nada: los dos enlaces se separan del
  resultado y bajan un escalón de tamaño y de peso para que se lean como "hay
  más si querés" y no como parte de la respuesta.
*/
.mp360-lot__proj-result > .mp360-lot__disclosures { margin-top: var(--mp360-space-4); }

.mp360-lot__proj-result .mp360-lot__link { font-size: 12px; font-weight: var(--mp360-weight-medium); }

/*
  Disclaimer (4.1 §11). Pegado al resultado se leía como una métrica más. Con
  aire propio queda claro que es una advertencia sobre todo lo anterior.
*/
.mp360-lot__proj-note {
    margin: var(--mp360-space-2) 0 0;
    font-size: 11px;
    line-height: 1.4;
    opacity: 0.5;
}

/* --------------------------------------------------------------------------
   Disclosures — mismo patrón que la leyenda

   El alto se anima en píxeles medidos por JS y se suelta a `auto` al terminar;
   `hidden` sólo en reposo. Easing simple en la dimensión —la curva con
   overshoot haría rebotar el layout— y el carácter lo pone el transform del
   contenido, igual que en §7c.
   -------------------------------------------------------------------------- */

.mp360-lot__disclosures {
    display: flex;
    flex-direction: column;
    gap: var(--mp360-space-3);
    margin-top: var(--mp360-space-1);
}

.mp360-lot__disclosure { display: flex; flex-direction: column; }

.mp360-lot__disclosure-box {
    overflow: hidden;
    height: 0;
    transition: height var(--mp360-dur-disclosure-out) var(--mp360-ease);
}

.mp360-lot__disclosure-box.is-open { transition-duration: var(--mp360-dur-disclosure); }

/* `hidden` sólo en reposo: durante la salida cortaría la transición. */
.mp360-lot__disclosure-box[hidden] { display: none; }

.mp360-lot__disclosure-body {
    padding-top: var(--mp360-space-3);
    opacity: 0;
    transform: translateY(-6px);
    transition: opacity var(--mp360-dur-disclosure-out) var(--mp360-ease),
                transform var(--mp360-dur-disclosure-out) var(--ease-mp360-back);
}

.mp360-lot__disclosure-box.is-open .mp360-lot__disclosure-body {
    opacity: 1;
    transform: none;
    transition-duration: var(--mp360-dur-disclosure);
}

/* --------------------------------------------------------------------------
   Evolución mes a mes

   Tabla real —los datos lo son— con peso visual mínimo: sin bordes de celda,
   sin franjas, con cifras tabulares para poder escanear la columna en
   vertical. Reemplaza al gráfico de dos líneas, que obligaba a deducir qué
   representaba cada trazo.
   -------------------------------------------------------------------------- */

.mp360-lot__months {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}

.mp360-lot__months-cap {
    caption-side: top;
    text-align: left;
    padding-bottom: var(--mp360-space-2);
    font-size: 11px;
    font-weight: var(--mp360-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.09em;
    opacity: 0.55;
}

.mp360-lot__months th,
.mp360-lot__months td {
    padding: 6px 0;
    text-align: left;
    font-weight: var(--mp360-weight-regular);
}

.mp360-lot__months thead th {
    font-size: 10px;
    font-weight: var(--mp360-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    opacity: 0.45;
    border-bottom: 1px solid rgba(10, 52, 37, 0.12);
    padding-bottom: var(--mp360-space-2);
}

.mp360-lot__months tbody tr + tr th,
.mp360-lot__months tbody tr + tr td { border-top: 1px solid rgba(10, 52, 37, 0.06); }

.mp360-lot__month-h { opacity: 0.62; white-space: nowrap; }

.mp360-lot__num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.mp360-lot__months tbody .mp360-lot__num { font-weight: var(--mp360-weight-medium); }
.mp360-lot__num--soft { opacity: 0.62; font-weight: var(--mp360-weight-regular) !important; }

/* --- supuestos --- */

.mp360-lot__assumptions-box { display: flex; flex-direction: column; gap: var(--mp360-space-2); }

.mp360-lot__assumptions-title {
    margin: 0;
    font-size: 11px;
    font-weight: var(--mp360-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.09em;
    opacity: 0.55;
}

.mp360-lot__assumptions { margin: 0; display: flex; flex-direction: column; gap: var(--mp360-space-1); }

.mp360-lot__assumption {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--mp360-space-3);
    font-size: 12px;
}

.mp360-lot__assumption dt { margin: 0; opacity: 0.6; }
.mp360-lot__assumption dd { margin: 0; font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------------------------
   Pie comercial persistente

   Hermano del contenedor scrolleable, no hijo: no hace falta reservar padding
   inferior ni preocuparse por contenido escondido detrás, porque nada pasa por
   debajo. Fondo sólido de la ficha y un filete superior muy sutil; ningún
   efecto nuevo.
   -------------------------------------------------------------------------- */

.mp360-lot__footer {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    gap: var(--mp360-space-2);
    padding: var(--mp360-space-3) var(--mp360-space-6) var(--mp360-space-4);
    background: var(--mp360-surface);
    border-top: 1px solid rgba(10, 52, 37, 0.12);
}

.mp360-lot__cta-context { margin: 0; font-size: 12px; opacity: 0.6; }

.mp360-lot__footer .mp360-cta { width: 100%; justify-content: center; }

/* --------------------------------------------------------------------------
   Responsive de la ficha

   Van DESPUÉS de las reglas base a propósito: comparten especificidad con
   ellas, así que declaradas antes perderían por orden de cascada aunque el
   media query coincida. Los ajustes del contenedor —posición y ancho de la
   superficie— siguen arriba, junto al resto de las reglas de superficie.
   -------------------------------------------------------------------------- */

@media (max-width: 640px) {
    /*
      El safe area va en el PIE, que es lo último de la columna. El contenido
      scrolleable no necesita reserva: el pie no lo cubre, va debajo.
    */
    .mp360-lot__footer {
        padding-bottom: max(var(--mp360-space-4), calc(var(--mp360-safe-bottom) + var(--mp360-space-2)));
    }

    /*
      Con 390px de ancho las dos columnas de la comparación dejarían las cifras
      demasiado justas. Se apilan, y el filete pasa de vertical a horizontal
      para que se sigan leyendo como una comparación y no como dos datos.
    */
    .mp360-lot__proj-grid { grid-template-columns: 1fr; gap: var(--mp360-space-3); }

    .mp360-lot__proj-col + .mp360-lot__proj-col {
        padding-left: 0;
        padding-top: var(--mp360-space-3);
        border-left: 0;
        border-top: 1px solid rgba(10, 52, 37, 0.12);
    }
}

/*
  Móvil apaisado: quedan ~320px de alto útil. Cabecera y pie no pueden
  llevarse la mitad, así que se compactan para que el área de contenido siga
  siendo un área de contenido. El CTA conserva su superficie táctil.
*/
@media (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .mp360-lot__head { padding: var(--mp360-space-3) var(--mp360-space-4) var(--mp360-space-2); }
    .mp360-lot__title { font-size: 18px; padding-right: 44px; }
    .mp360-lot__head-meta { margin-top: var(--mp360-space-1); }
    .mp360-lot__head .mp360-surface__close { top: var(--mp360-space-2); right: var(--mp360-space-2); }
    .mp360-lot__scroll { padding: var(--mp360-space-3) var(--mp360-space-4); gap: var(--mp360-space-6); }
    .mp360-lot__lead-amount { font-size: 27px; }
    .mp360-lot__block--plan { padding: var(--mp360-space-3); }

    /*
      El pie pasa a una sola línea: microcontexto y CTA lado a lado. Apilados se
      llevaban 88 de los 322px de la ficha; en fila bajan a ~64 y esos 25px
      vuelven al contenido, que es el recurso escaso acá.
    */
    .mp360-lot__footer {
        flex-direction: row;
        align-items: center;
        gap: var(--mp360-space-3);
        /*
          El padding-bottom conserva el safe-bottom: el shorthand de la versión
          vertical (@640) no llega hasta acá y sin esto el CTA queda debajo de
          la barra de gestos en un teléfono con notch acostado.
        */
        padding: var(--mp360-space-2) var(--mp360-space-4)
                 max(var(--mp360-space-2), var(--mp360-safe-bottom));
    }

    .mp360-lot__cta-context { flex: 1 1 auto; min-width: 0; }
    .mp360-lot__footer .mp360-cta { flex: 0 0 auto; width: auto; }
}


/* ==========================================================================
   15. Funciones comerciales y de conversión (Fase 4)

   Avances de obra, proyector general de cuota, captura de lead y solicitud de
   visita. Ninguna introduce tokens, curvas ni tipografías propias: reutilizan
   la caja de superficie, el motion y los componentes ya aprobados.
   ========================================================================== */

/* --------------------------------------------------------------------------
   15a. WhatsApp icon-only en la navbar

   El canal deja de ocupar un CTA con texto largo y pasa a icono. Conserva el
   destino, el handler y la identificación visual de WhatsApp; el texto vive
   en `aria-label` y `title`, así que no se pierde para nadie.
   -------------------------------------------------------------------------- */

.mp360-iconbtn--wa .mp360-iconbtn__glyph {
    display: block;
    width: 20px;
    height: 20px;
    background: var(--mp360-primary);
    -webkit-mask: var(--mp360-wa-icon) center / contain no-repeat;
            mask: var(--mp360-wa-icon) center / contain no-repeat;
}

/* --------------------------------------------------------------------------
   15b. Cajas de las superficies nuevas
   -------------------------------------------------------------------------- */

.mp360-surface__body[data-type="progress"] { width: min(980px, 100%); }
.mp360-surface__body[data-type="projection"] { width: min(560px, 100%); }
.mp360-surface__body[data-type="visit"],
.mp360-surface__body[data-type="lead"] { width: min(460px, 100%); }

/* --------------------------------------------------------------------------
   15c. Avances de obra

   La unidad de navegación es el PERÍODO, no la foto: el selector temporal está
   arriba y siempre visible, y el medio ocupa el resto. No es una galería con
   otro nombre.
   -------------------------------------------------------------------------- */

.mp360-progress { display: flex; flex-direction: column; min-height: 0; color: var(--mp360-text); }

/* Misma cabecera en grid que §15, por el mismo motivo. */
.mp360-progress__head {
    flex: 0 0 auto;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--mp360-space-4);
    align-items: start;
    padding: var(--mp360-space-6) var(--mp360-space-6) var(--mp360-space-4);
    border-bottom: 1px solid rgba(10, 52, 37, 0.1);
}

/*
  "Última actualización" antes del título: dice de entrada qué es esto, que es
  lo que hace que la función se lea terminada aunque hoy tenga una sola
  publicación.
*/
.mp360-progress__eyebrow {
    grid-column: 1;
    grid-row: 1;
    margin: 0 0 var(--mp360-space-1);
    font-size: 11px;
    font-weight: var(--mp360-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.09em;
    opacity: 0.55;
}

.mp360-progress__title {
    grid-column: 1;
    grid-row: 2;
    margin: 0;
    font-size: 22px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1.15;
    letter-spacing: -0.015em;
}

.mp360-progress__intro {
    grid-column: 1;
    grid-row: 3;
    margin: var(--mp360-space-2) 0 0;
    font-size: 13px;
    opacity: 0.7;
}

/*
  `span 3` explícito, no `1 / -1`: sin `grid-template-rows` declarado el grid no
  tiene líneas explícitas, así que `-1` no significa "hasta el final" y el tramo
  queda a merced de cómo se generen las filas implícitas.
*/
.mp360-progress__head .mp360-surface__close {
    position: static;
    grid-column: 2;
    grid-row: 1 / span 3;
    align-self: start;
}

.mp360-progress__title,
.mp360-progress__intro { min-width: 0; overflow-wrap: break-word; }

.mp360-progress__body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--mp360-space-4) var(--mp360-space-6) var(--mp360-space-6);
    display: flex;
    flex-direction: column;
    gap: var(--mp360-space-4);
}

/*
  Estado vacío. No es un placeholder de maqueta: es lo que se muestra mientras
  no exista material de obra verificable, en vez de inventar períodos.
*/
.mp360-progress__empty {
    margin: 0;
    padding: var(--mp360-space-8) var(--mp360-space-4);
    text-align: center;
    font-size: 14px;
    line-height: 1.5;
    opacity: 0.66;
}

/* Selector temporal: se scrollea en horizontal cuando hay muchos períodos. */
.mp360-progress__periods {
    display: flex;
    gap: var(--mp360-space-2);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: thin;
    padding-bottom: var(--mp360-space-1);
}

.mp360-progress__period-btn {
    flex: 0 0 auto;
    padding: var(--mp360-space-2) var(--mp360-space-3);
    border: 1px solid rgba(10, 52, 37, 0.2);
    border-radius: var(--mp360-radius);
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 13px;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease),
                border-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-progress__period-btn:hover { background: rgba(10, 52, 37, 0.06); }

.mp360-progress__period-btn.is-active {
    background: var(--mp360-primary);
    border-color: var(--mp360-primary);
    color: var(--mp360-on-primary);
}

.mp360-progress__viewer { display: flex; flex-direction: column; gap: var(--mp360-space-3); }

.mp360-progress__media {
    border-radius: var(--mp360-radius);
    overflow: hidden;
    background: rgba(10, 52, 37, 0.06);
}

.mp360-progress__img,
.mp360-progress__video {
    display: block;
    width: 100%;
    height: auto;
    max-height: 58vh;
    object-fit: cover;
}

.mp360-progress__period {
    margin: 0;
    font-size: 16px;
    font-weight: var(--mp360-weight-semibold);
    letter-spacing: -0.005em;
}

.mp360-progress__desc { margin: var(--mp360-space-1) 0 0; font-size: 13px; line-height: 1.45; opacity: 0.72; }

/* --------------------------------------------------------------------------
   15d. Proyectá tu cuota — superficie general

   Tres pasos que se revelan a medida que se completan: etapa, referencia,
   ingreso. La proyección en sí es la MISMA vista de la ficha, así que hereda
   todas sus clases `mp360-lot__proj-*`.
   -------------------------------------------------------------------------- */

.mp360-projgen { display: flex; flex-direction: column; min-height: 0; color: var(--mp360-text); }

/*
  Cabecera en grid con una columna reservada al cierre (4.1 §2).

  Antes el botón iba `position: absolute` y el hueco lo simulaba un
  `padding-right: 52px` puesto SÓLO en el título: el subtítulo, que no lo
  llevaba, pasaba por debajo de la X. Un padding no reserva espacio para nadie
  más que para sí mismo. Con una columna real el hueco existe para todo lo que
  viva en la columna de contenido, presente y futuro, y no hay que acordarse de
  replicar el número mágico en cada elemento nuevo.
*/
.mp360-projgen__head {
    flex: 0 0 auto;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--mp360-space-4);
    align-items: start;
    padding: var(--mp360-space-6) var(--mp360-space-6) var(--mp360-space-4);
    border-bottom: 1px solid rgba(10, 52, 37, 0.1);
}

.mp360-projgen__title {
    grid-column: 1;
    grid-row: 1;
    margin: 0;
    font-size: 22px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1.15;
    letter-spacing: -0.015em;
}

.mp360-projgen__intro {
    grid-column: 1;
    grid-row: 2;
    margin: var(--mp360-space-2) 0 0;
    font-size: 13px;
    line-height: 1.45;
    opacity: 0.7;
}

/* Ocupa las dos filas para que la columna no colapse si el subtítulo crece. */
.mp360-projgen__head .mp360-surface__close {
    position: static;
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: start;
}

.mp360-projgen__scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--mp360-space-6);
    display: flex;
    flex-direction: column;
    gap: var(--mp360-space-6);
}

/*
  Segunda idea educativa, arriba del flujo (4.1 §3). Encabeza la columna con
  menos peso que un paso pero más que una nota: es lo que hay que haber
  entendido antes de tocar "Tipuana 1".
*/
.mp360-projgen__lead {
    margin: 0;
    font-size: 13px;
    line-height: 1.5;
    opacity: 0.75;
}

.mp360-projgen__step { display: flex; flex-direction: column; gap: var(--mp360-space-3); }

.mp360-projgen__step-title {
    margin: 0;
    font-size: 11px;
    font-weight: var(--mp360-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.09em;
    opacity: 0.55;
}

.mp360-projgen__chips { display: flex; flex-wrap: wrap; gap: var(--mp360-space-2); }

.mp360-projgen__chip {
    /* Mismo target que su hermana `__band` (44px) y que el chip de etapa de
       Conocer valores: los tres eligen una opción y no hay razón para que uno
       mida 34px. Medido en runtime antes de igualarlo. */
    min-height: 44px;
    padding: var(--mp360-space-2) var(--mp360-space-4);
    border: 1px solid rgba(10, 52, 37, 0.2);
    border-radius: var(--mp360-radius);
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 14px;
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease),
                border-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-projgen__chip:hover { background: rgba(10, 52, 37, 0.06); }

.mp360-projgen__chip[aria-pressed="true"] {
    background: var(--mp360-primary);
    border-color: var(--mp360-primary);
    color: var(--mp360-on-primary);
}

.mp360-projgen__bands { display: flex; flex-direction: column; gap: var(--mp360-space-2); }

/*
  Cada referencia lleva su color: es el mismo lenguaje del marcador del lote y
  del tooltip, así que la asociación color → precio se sostiene también acá.
*/
.mp360-projgen__band {
    display: flex;
    align-items: center;
    gap: var(--mp360-space-3);
    width: 100%;
    padding: var(--mp360-space-3);
    border: 1px solid rgba(10, 52, 37, 0.16);
    border-radius: var(--mp360-radius);
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease),
                border-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-projgen__band:hover { background: rgba(10, 52, 37, 0.05); border-color: rgba(10, 52, 37, 0.3); }

.mp360-projgen__band[aria-pressed="true"] {
    border-color: var(--mp360-primary);
    background: rgba(10, 52, 37, 0.06);
}

.mp360-projgen__swatch {
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    border-radius: var(--mp360-radius);
    background: var(--mp360-band, transparent);
    /* Sin el anillo, las bandas claras desaparecen sobre la superficie blanca. */
    box-shadow: inset 0 0 0 1px rgba(10, 52, 37, 0.35);
}

.mp360-projgen__band-text { font-size: 15px; font-weight: var(--mp360-weight-medium); }

.mp360-projgen__empty { margin: 0; font-size: 13px; line-height: 1.45; opacity: 0.66; }

/* --------------------------------------------------------------------------
   15e. Formularios comerciales — lead y visita

   Comparten caja, campos y pie de envío. Fricción mínima: la de lead son tres
   campos y una salida clara; la de visita agrega fecha y franja.
   -------------------------------------------------------------------------- */

.mp360-form { display: flex; flex-direction: column; min-height: 0; color: var(--mp360-text); }

/* Misma cabecera en grid que §15 del proyector, por el mismo motivo. */
.mp360-form__head {
    flex: 0 0 auto;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--mp360-space-4);
    align-items: start;
    padding: var(--mp360-space-6) var(--mp360-space-6) var(--mp360-space-4);
    border-bottom: 1px solid rgba(10, 52, 37, 0.1);
}

.mp360-form__title {
    grid-column: 1;
    grid-row: 1;
    margin: 0;
    font-size: 20px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1.2;
    letter-spacing: -0.01em;
}

.mp360-form__intro {
    grid-column: 1;
    grid-row: 2;
    margin: var(--mp360-space-2) 0 0;
    font-size: 13px;
    line-height: 1.45;
    opacity: 0.72;
}

.mp360-form__head .mp360-surface__close {
    position: static;
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: start;
}

.mp360-form__body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--mp360-space-6);
    display: flex;
    flex-direction: column;
    gap: var(--mp360-space-4);
}

.mp360-form__fields { display: flex; flex-direction: column; gap: var(--mp360-space-4); }

.mp360-form__field { display: flex; flex-direction: column; gap: var(--mp360-space-2); border: 0; padding: 0; margin: 0; }

.mp360-form__label { font-size: 13px; font-weight: var(--mp360-weight-medium); opacity: 0.8; padding: 0; }

/*
  El ritmo label→control lo da el `gap` del campo, y con "Horario preferido"
  no funcionaba: ese rótulo es un <legend> dentro de un <fieldset>, y el legend
  se renderiza FUERA del flujo flex del fieldset, así que ningún `gap` lo
  alcanza. Medido: 8px en los cuatro <label> y 0px en el <legend>, que es
  exactamente el pegoteo que se veía contra Mañana/Tarde.

  Se conserva el fieldset —es la semántica correcta para un grupo de opciones—
  y se le devuelve el ritmo con un margen explícito del mismo token.
*/
.mp360-form__field--slots > .mp360-form__label { display: block; margin-bottom: var(--mp360-space-2); }

.mp360-form__input {
    width: 100%;
    min-height: 44px;
    padding: var(--mp360-space-3);
    border: 1px solid rgba(10, 52, 37, 0.2);
    border-radius: var(--mp360-radius);
    background: var(--mp360-surface);
    color: inherit;
    font: inherit;
    font-size: 15px;
}

.mp360-form__input:focus-visible { outline: 2px solid var(--mp360-accent); outline-offset: 1px; }

.mp360-form__input[aria-invalid="true"] { border-color: #A6301A; }

.mp360-form__error { margin: 0; font-size: 12px; color: #A6301A; }

/* Franjas horarias: intención, no disponibilidad real. */
.mp360-form__slots { display: flex; gap: var(--mp360-space-2); flex-wrap: wrap; }

.mp360-form__slot {
    flex: 1 1 auto;
    min-height: 44px;
    padding: var(--mp360-space-2) var(--mp360-space-4);
    border: 1px solid rgba(10, 52, 37, 0.2);
    border-radius: var(--mp360-radius);
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 14px;
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease),
                border-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-form__slot[aria-pressed="true"] {
    background: var(--mp360-primary);
    border-color: var(--mp360-primary);
    color: var(--mp360-on-primary);
}

.mp360-form__hint { margin: 0; font-size: 12px; line-height: 1.4; opacity: 0.6; }

.mp360-form__submit { display: flex; flex-direction: column; gap: var(--mp360-space-2); }

/*
  El CTA del formulario ES el CTA del sistema: lleva también `.mp360-cta` y
  `.mp360-cta--accent`, así que el color, el fondo animado, el recorte de los
  caracteres y los estados de hover / focus-visible / active vienen de §4b sin
  duplicar nada. Acá sólo queda lo que cambia por vivir en un formulario: ancho
  completo y una superficie táctil un poco mayor.

  Por eso desaparecieron `background`, `color` y el hover por `filter`: pintar
  el fondo en el propio botón tapaba `.mp360-cta__bg`, que es justamente el
  elemento que se anima.
*/
.mp360-form__cta {
    width: 100%;
    min-height: 48px;
    padding: 0 var(--mp360-space-4);
    font-size: 15px;
    cursor: pointer;
}

.mp360-form__cta:disabled { opacity: 0.6; cursor: default; }

/*
  El estado del envío. `pending` es el caso real de hoy —no hay transporte
  configurado— y se dice con palabras, no con un falso "enviado".
*/
.mp360-form__status {
    margin: 0;
    padding: var(--mp360-space-3);
    border-radius: var(--mp360-radius);
    font-size: 13px;
    line-height: 1.45;
}

.mp360-form__status[data-kind="ok"] { background: rgba(61, 101, 0, 0.12); color: var(--mp360-primary); }
.mp360-form__status[data-kind="pending"] { background: rgba(10, 52, 37, 0.07); color: var(--mp360-primary); }
.mp360-form__status[data-kind="error"] { background: rgba(166, 48, 26, 0.1); color: #A6301A; }

.mp360-form__dismiss {
    align-self: center;
    padding: var(--mp360-space-2);
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    font-size: 13px;
    opacity: 0.66;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}

/* --------------------------------------------------------------------------
   15f. Responsive

   Después de las reglas base, por la misma razón que en la ficha: comparten
   especificidad y declaradas antes perderían por orden de cascada.
   -------------------------------------------------------------------------- */

@media (max-width: 640px) {
    .mp360-surface[data-surface="lead"],
    .mp360-surface[data-surface="visit"] { align-items: flex-end; padding: 0; }

    .mp360-surface__body[data-type="lead"],
    .mp360-surface__body[data-type="visit"] {
        width: 100%;
        max-height: min(88vh, 100%);
        border-radius: var(--mp360-radius) var(--mp360-radius) 0 0;
    }

    /* El safe area va en el cuerpo scrolleable, que es lo último de la caja. */
    .mp360-form__body {
        padding-bottom: max(var(--mp360-space-6), calc(var(--mp360-safe-bottom) + var(--mp360-space-4)));
    }

    .mp360-progress__head,
    .mp360-projgen__head,
    .mp360-form__head { padding: var(--mp360-space-4) var(--mp360-space-4) var(--mp360-space-3); }

    .mp360-progress__body,
    .mp360-projgen__scroll { padding: var(--mp360-space-3) var(--mp360-space-4) var(--mp360-space-6); }

    .mp360-progress__title,
    .mp360-projgen__title { font-size: 19px; }

    .mp360-progress__img,
    .mp360-progress__video { max-height: 42vh; }
}

/*
  Apaisado: el alto es el recurso escaso. Se compactan cabeceras y se recorta
  el medio para que el selector temporal y el contenido convivan.
*/
@media (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .mp360-progress__head,
    .mp360-projgen__head,
    .mp360-form__head { padding: var(--mp360-space-3) var(--mp360-space-4) var(--mp360-space-2); }

    .mp360-progress__title,
    .mp360-projgen__title,
    .mp360-form__title { font-size: 18px; }

    /*
      Mismo caso que el pie de la ficha: el shorthand pisa el padding-bottom con
      safe-bottom que declara la versión vertical (@640) y en apaisado el último
      campo o el submit quedan bajo la barra de gestos.
    */
    .mp360-progress__body,
    .mp360-projgen__scroll,
    .mp360-form__body {
        padding: var(--mp360-space-3) var(--mp360-space-4)
                 max(var(--mp360-space-3), var(--mp360-safe-bottom));
        gap: var(--mp360-space-3);
    }

    .mp360-progress__img,
    .mp360-progress__video { max-height: 40vh; }

    .mp360-form__fields { gap: var(--mp360-space-3); }
}


@media (prefers-reduced-motion: reduce) {
    /*
      El easing espacial pierde su anticipación y su overshoot en un solo
      punto: cualquier consumidor del token deja de rebotar, incluso fuera de
      .mp360-root. La curva es personalidad, no información — nada de lo que
      hay que entender u operar depende de ella.
    */
    :root { --ease-mp360-back: var(--mp360-ease); }

    .mp360-root *,
    .mp360-root *::before,
    .mp360-root *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        /* El estado final se conserva; sólo se quita el recorrido. */
        transition-timing-function: linear !important;
        scroll-behavior: auto !important;
    }

    /*
      Excepción deliberada: el velo del micro-onboarding conserva un fundido
      simple. Reducir movimiento no es lo mismo que cortar en seco, y acá el
      fundido ES la señal —sin él la pantalla se oscurece de golpe, que es más
      agresivo que la animación que se quería evitar. El énfasis espacial de la
      card sí desaparece, que es lo que la preferencia pide.
    */
    .mp360-spotlight { transition-duration: 300ms !important; }
    .mp360-spotlight.is-on { transition-duration: 260ms !important; }
    .mp360-legend.is-spotlit { animation: none !important; }
}


/* --------------------------------------------------------------------------
   16. NAVEGACIÓN INICIAL MOBILE (4.1 · Parte C)

   Sólo móvil vertical. La vista inicial es una aérea a pantalla completa que
   no pertenece a ningún grupo del selector, así que abajo no hay ni selector
   ni leyenda: el espacio está libre y es el que queda bajo el pulgar.

   Se apoya en el mismo lenguaje que la leyenda —superficie clara, radio y
   sombra del sistema, z-index 8 por debajo de navbar (10), drawer (9) y
   superficies (20)—. Es navegación, no una acción comercial: sin Character
   Stagger, sin velo, sin spotlight y sin pulso.
   -------------------------------------------------------------------------- */

.mp360-starter {
    /* Fuera de móvil vertical no existe: el problema que resuelve es de ahí. */
    display: none;
}

.mp360-starter[hidden] { display: none; }

.mp360-starter__eyebrow {
    margin: 0;
    font-size: 11px;
    font-weight: var(--mp360-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.09em;
    opacity: 0.55;
}

.mp360-starter__row { display: flex; gap: var(--mp360-space-2); }

.mp360-starter__stage {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 1px;
    min-height: 52px;
    padding: var(--mp360-space-2) var(--mp360-space-3);
    border: 1px solid rgba(10, 52, 37, 0.18);
    border-radius: var(--mp360-radius);
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease),
                border-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-starter__stage:active { background: rgba(10, 52, 37, 0.06); border-color: rgba(10, 52, 37, 0.32); }
.mp360-starter__stage:focus-visible { outline: 2px solid var(--mp360-accent); outline-offset: 2px; }

.mp360-starter__stage-name { font-size: 15px; font-weight: var(--mp360-weight-semibold); }
.mp360-starter__stage-hint { font-size: 12px; opacity: 0.62; }

/* Tercera opción, deliberadamente más liviana que las dos de lotes. */
.mp360-starter__views {
    align-self: flex-start;
    /* Es un enlace por peso visual, pero un control de navegación por función:
       conserva los 44px de superficie táctil de DESIGN.md §7. */
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--mp360-accent);
    font: inherit;
    font-size: 13px;
    font-weight: var(--mp360-weight-medium);
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}

.mp360-starter__views:focus-visible { outline: 2px solid var(--mp360-accent); outline-offset: 2px; }

@media (max-width: 767px) and (orientation: portrait) {
    .mp360-starter {
        position: absolute;
        left: max(var(--mp360-space-4), var(--mp360-safe-left));
        right: max(var(--mp360-space-4), var(--mp360-safe-right));
        bottom: calc(var(--mp360-space-4) + var(--mp360-safe-bottom));
        z-index: 8;
        display: flex;
        flex-direction: column;
        gap: var(--mp360-space-2);
        padding: var(--mp360-space-3) var(--mp360-space-4);
        border-radius: var(--mp360-radius);
        background: var(--mp360-surface);
        box-shadow: 0 2px 10px rgba(10, 52, 37, 0.22);
        color: var(--mp360-text);
        /* Entrada breve al terminar la bienvenida. Nada que se repita. */
        animation: mp360-starter-in var(--mp360-dur-disclosure) var(--mp360-ease) both;
    }

    /* `hidden` gana siempre: es el estado que decide el panorama. */
    .mp360-starter[hidden] { display: none; }

    /*
      Con una superficie abierta no compite ni queda alcanzable por teclado o
      lector de pantalla. La condición se observa donde ocurre —el DOM— en vez
      de duplicarla como estado en JS.
    */
    .mp360-root:has(.mp360-surface.is-open) .mp360-starter { display: none; }
}

@keyframes mp360-starter-in {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* --------------------------------------------------------------------------
   20b. Navegación inicial desktop

   Ocupa exactamente el hueco de la leyenda —inferior izquierda, 320px—, que
   en el panorama inicial está vacío porque ahí no hay lotes que referenciar.
   No es una posición nueva: es la misma casilla del layout canónico usada por
   el único componente que puede estar ahí en ese momento.

   Deliberadamente no es una card grande, no se centra sobre el panorama y no
   arma velo: compite con el recorrido lo mínimo posible y desaparece en
   cuanto el usuario se va de la vista inicial.
   -------------------------------------------------------------------------- */

.mp360-dstarter {
    /* Sólo desktop: el problema de descubribilidad de mobile ya lo resuelve
       `.mp360-starter`, con otro contenido y otra jerarquía. */
    display: none;
}

.mp360-dstarter[hidden] { display: none; }

/*
  Dónde aparece. Ancho suficiente para que la card de 320px no invada el
  panorama, y alto suficiente para que no se apile contra la barra: eso deja
  fuera el apaisado de teléfono, donde quedan ~330px de alto y el starter
  mobile ya decidió no competir por esa franja. Tablet vertical sí entra: es el
  viewport donde el starter mobile no aplica y hasta ahora no había ninguno.
*/
@media (min-width: 768px) and (min-height: 600px) {
    .mp360-dstarter {
        position: absolute;
        left: var(--mp360-space-6);
        bottom: calc(var(--mp360-space-8) + var(--mp360-safe-bottom));
        /* Misma capa que leyenda y minimapa: por debajo de navbar y superficies. */
        z-index: 8;
        display: flex;
        flex-direction: column;
        gap: var(--mp360-space-2);
        width: min(320px, calc(100vw - 2 * var(--mp360-space-6)));
        padding: var(--mp360-space-4);
        border-radius: var(--mp360-radius);
        background: var(--mp360-surface);
        box-shadow: 0 2px 10px rgba(10, 52, 37, 0.22);
        color: var(--mp360-text);
        /* Misma entrada breve que el starter mobile; no se repite. */
        animation: mp360-starter-in var(--mp360-dur-disclosure) var(--mp360-ease) both;
    }

    .mp360-dstarter[hidden] { display: none; }

    /* Con una superficie abierta no compite ni queda alcanzable por teclado. */
    .mp360-root:has(.mp360-surface.is-open) .mp360-dstarter { display: none; }
}

.mp360-dstarter__eyebrow {
    margin: 0;
    font-size: 11px;
    font-weight: var(--mp360-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.09em;
    opacity: 0.55;
}

.mp360-dstarter__text {
    margin: 0;
    font-size: 13.5px;
    line-height: 1.45;
    opacity: 0.78;
}

/*
  CTA de navegación, no comercial: superficie clara y peso medio, igual que
  "Volver al inicio". El Character Stagger sí se hereda —es la mecánica de
  botón del sistema— pero no la jerarquía del CTA principal.
*/
.mp360-dstarter__cta {
    align-self: flex-start;
    margin-top: var(--mp360-space-1);
    display: inline-flex;
    align-items: center;
    min-height: 40px;
    padding: 0 var(--mp360-space-4);
    border: 1px solid rgba(10, 52, 37, 0.22);
    border-radius: var(--mp360-radius);
    background: none;
    color: var(--mp360-primary);
    font-family: inherit;
    font-size: 14px;
    font-weight: var(--mp360-weight-semibold);
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease),
                border-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-dstarter__cta:hover { background: rgba(10, 52, 37, 0.06); border-color: rgba(10, 52, 37, 0.34); }
.mp360-dstarter__cta:focus-visible { outline: 2px solid var(--mp360-accent); outline-offset: 2px; }


/* --------------------------------------------------------------------------
   17. POI TOOLTIP (Fase 5)

   Reemplaza dos piezas legacy: el bitmap del skin que aparecía fijo en la
   esquina superior derecha y el tooltip nativo del player.

   Comparte con el tooltip de lotes la mecánica —posición absoluta escrita por
   TipAnchor, `pointer-events: none` para no interponerse en el drag del
   panorama, misma transición de opacidad— y se diferencia en lo único que debe
   diferenciarse: un POI no es una unidad comercial, así que no lleva color de
   banda. Superficie clara del sistema, tinta de marca.

   No lleva imagen. El skin usaba una porque su contenido estaba horneado en un
   bitmap; acá el contenido es texto y la tipografía es Instrument Sans.
   -------------------------------------------------------------------------- */

.mp360-poitip {
    position: absolute;
    top: 0;
    left: 0;
    /* Por encima del minimapa (8) y por debajo de navbar (10). */
    z-index: 9;
    max-width: 240px;
    padding: var(--mp360-space-2) var(--mp360-space-3);
    border-radius: var(--mp360-radius);
    background: var(--mp360-surface);
    color: var(--mp360-text);
    /* Sombra contenida: define el borde sobre el panorama sin pesar. */
    box-shadow: 0 6px 18px rgba(10, 52, 37, 0.22),
                inset 0 0 0 1px rgba(10, 52, 37, 0.10);
    pointer-events: none;
    opacity: 0;
    transform-origin: top left;
    transition: opacity var(--mp360-dur-fast) var(--mp360-ease);
    will-change: transform;
}

.mp360-poitip.is-visible { opacity: 1; }

.mp360-poitip__title {
    margin: 0;
    font-size: 13px;
    font-weight: var(--mp360-weight-semibold);
    letter-spacing: 0.01em;
    line-height: 1.25;
}

/* Microcopy opcional: describe la acción que el hotspot YA tiene. Cuando el
   POI no tiene click, este nodo va `hidden` y no se dibuja nada. */
.mp360-poitip__note {
    margin: 2px 0 0;
    font-size: 12px;
    line-height: 1.35;
    opacity: 0.66;
}

.mp360-poitip__note[hidden] { display: none; }

/* Con una superficie abierta el POI no compite: Poi.show() ya no lo muestra,
   y esto cubre el caso de que se abra una mientras está a la vista. */
.mp360-root:has(.mp360-surface.is-open) .mp360-poitip { opacity: 0; }


/* --------------------------------------------------------------------------
   18. CONOCER VALORES (Fase 5)

   Misma gramática que el proyector general —cabecera en grid con columna de
   cierre, pasos rotulados, chips de etapa— porque son dos herramientas de la
   misma familia y conviene que se reconozcan entre sí. Lo que cambia es el
   contenido: acá el protagonista es el plan, no la simulación.
   -------------------------------------------------------------------------- */

.mp360-values {
    display: flex;
    flex-direction: column;
    max-height: 100%;
    min-height: 0;
}

.mp360-values__head {
    flex: 0 0 auto;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--mp360-space-4);
    align-items: start;
    padding: var(--mp360-space-6) var(--mp360-space-6) var(--mp360-space-4);
    border-bottom: 1px solid rgba(10, 52, 37, 0.1);
}

.mp360-values__title {
    grid-column: 1;
    grid-row: 1;
    margin: 0;
    font-size: 22px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1.15;
    letter-spacing: -0.015em;
}

.mp360-values__intro {
    grid-column: 1;
    grid-row: 2;
    margin: var(--mp360-space-2) 0 0;
    font-size: 13px;
    line-height: 1.45;
    opacity: 0.7;
}

.mp360-values__head .mp360-surface__close {
    position: static;
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: start;
}

.mp360-values__scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--mp360-space-6);
    display: flex;
    flex-direction: column;
    gap: var(--mp360-space-6);
}

.mp360-values__step { display: flex; flex-direction: column; gap: var(--mp360-space-3); }

.mp360-values__step-title {
    margin: 0;
    font-size: 11px;
    font-weight: var(--mp360-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.09em;
    opacity: 0.55;
}

.mp360-values__chips { display: flex; flex-wrap: wrap; gap: var(--mp360-space-2); }

.mp360-values__chip {
    min-height: 44px;
    padding: var(--mp360-space-2) var(--mp360-space-4);
    border: 1px solid rgba(10, 52, 37, 0.2);
    border-radius: var(--mp360-radius);
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 15px;
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease),
                border-color var(--mp360-dur-fast) var(--mp360-ease),
                color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-values__chip[aria-pressed="true"] {
    background: var(--mp360-primary);
    border-color: var(--mp360-primary);
    color: var(--mp360-on-primary);
}

.mp360-values__chip:focus-visible { outline: 2px solid var(--mp360-accent); outline-offset: 2px; }

.mp360-values__plans { display: flex; flex-direction: column; gap: var(--mp360-space-3); }

/*
  Una tarjeta por plan, no una card enorme: cuota arriba con el swatch, las tres
  cifras secundarias en una fila de datos y el stock como una línea. Sin borde
  de color ni relleno tintado — el swatch ya identifica el plan.
*/
.mp360-values__plan {
    display: flex;
    flex-direction: column;
    gap: var(--mp360-space-3);
    padding: var(--mp360-space-4);
    border: 1px solid rgba(10, 52, 37, 0.14);
    border-radius: var(--mp360-radius);
}

.mp360-values__plan-head { display: flex; align-items: center; gap: var(--mp360-space-3); }

.mp360-values__swatch {
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    border-radius: 4px;
    background: var(--mp360-band, transparent);
    box-shadow: inset 0 0 0 1px rgba(10, 52, 37, 0.28);
}

.mp360-values__cuota {
    margin: 0;
    font-size: 17px;
    font-weight: var(--mp360-weight-semibold);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
}

.mp360-values__figs {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--mp360-space-3);
    margin: 0;
}

.mp360-values__fig { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.mp360-values__fig dt { font-size: 11px; opacity: 0.6; }
.mp360-values__fig dd {
    margin: 0;
    font-size: 14px;
    font-variant-numeric: tabular-nums;
    font-weight: var(--mp360-weight-medium);
}

.mp360-values__stock { margin: 0; font-size: 13px; opacity: 0.75; }

.mp360-values__actions { display: flex; flex-direction: column; gap: var(--mp360-space-3); }

.mp360-values__lots {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.mp360-values__lot {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--mp360-space-3);
    width: 100%;
    min-height: 40px;
    padding: var(--mp360-space-2);
    border: 0;
    border-radius: var(--mp360-radius);
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-values__lot:hover { background: rgba(10, 52, 37, 0.05); }
.mp360-values__lot:focus-visible { outline: 2px solid var(--mp360-accent); outline-offset: -2px; }

.mp360-values__lot-id { font-size: 14px; font-weight: var(--mp360-weight-medium); }
.mp360-values__lot-m2 { font-size: 12px; opacity: 0.68; font-variant-numeric: tabular-nums; }

.mp360-values__tour {
    align-self: flex-start;
    min-height: 44px;
    padding: 0 var(--mp360-space-4);
    border: 1px solid var(--mp360-primary);
    border-radius: var(--mp360-radius);
    background: transparent;
    color: var(--mp360-primary);
    font: inherit;
    font-size: 14px;
    font-weight: var(--mp360-weight-medium);
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease),
                color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-values__tour:hover { background: var(--mp360-primary); color: var(--mp360-on-primary); }
.mp360-values__tour:focus-visible { outline: 2px solid var(--mp360-accent); outline-offset: 2px; }

.mp360-values__empty { margin: 0; font-size: 13px; line-height: 1.5; opacity: 0.7; }

/*
  El stock se agotó entre la apertura y el click. Va debajo del CTA —que queda
  deshabilitado— y no como un error de formulario: no hizo nada mal.
*/
.mp360-values__gone {
    margin: var(--mp360-space-3) 0 0;
    font-size: 12.5px;
    line-height: 1.45;
    color: var(--mp360-primary);
    opacity: 0.82;
}

/* --------------------------------------------------------------------------
   18a-bis. Lotes y Etapas

   Superficie de orientación, no de contenido: dos tarjetas y nada más. Todo
   lo que hay dentro es dato real —el nombre de la etapa y su stock de ahora—;
   no hay copy comercial que las diferencie porque no existe un dato que lo
   respalde.

   Reutiliza la métrica del encabezado de "Conocer valores": mismo grid con la
   X en la segunda columna, mismo peso de título e intro. No es una superficie
   con reglas propias.
   -------------------------------------------------------------------------- */

.mp360-stages {
    display: flex;
    flex-direction: column;
    max-height: 100%;
    min-height: 0;
}

.mp360-stages__head {
    flex: 0 0 auto;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--mp360-space-4);
    align-items: start;
    padding: var(--mp360-space-6) var(--mp360-space-6) var(--mp360-space-4);
    border-bottom: 1px solid rgba(10, 52, 37, 0.1);
}

/*
  El bloque textual ocupa su columna y nunca la de la X. La pista ya es
  `minmax(0, 1fr)`, pero eso gobierna la pista, no el contenido: sin
  `min-width: 0` en los hijos una palabra larga impone su ancho mínimo y empuja
  el grid. Es el modo silencioso en que un header así se rompe.
*/
.mp360-stages__title,
.mp360-stages__intro {
    min-width: 0;
    overflow-wrap: break-word;
}

.mp360-stages__title {
    grid-column: 1;
    grid-row: 1;
    margin: 0;
    font-size: 22px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1.15;
    letter-spacing: -0.015em;
}

.mp360-stages__intro {
    grid-column: 1;
    grid-row: 2;
    margin: var(--mp360-space-2) 0 0;
    font-size: 13px;
    line-height: 1.45;
    opacity: 0.7;
}

.mp360-stages__head .mp360-surface__close {
    position: static;
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: start;
}

.mp360-stages__list {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--mp360-space-4);
    padding: var(--mp360-space-6);
}

.mp360-stages__card {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--mp360-space-2);
    padding: var(--mp360-space-4);
    border: 1px solid rgba(10, 52, 37, 0.14);
    border-radius: var(--mp360-radius);
}

/* Sin stock la tarjeta sigue estando —la etapa existe— pero no invita. */
.mp360-stages__card[data-empty="true"] { opacity: 0.72; }

.mp360-stages__name {
    margin: 0;
    font-size: 17px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1.2;
}

.mp360-stages__stock {
    margin: 0;
    font-size: 13px;
    line-height: 1.4;
    opacity: 0.72;
    font-variant-numeric: tabular-nums;
}

/* Mismo control que "Ver lotes de este plan": es la misma clase de acción. */
.mp360-stages__cta {
    margin-top: auto;
    align-self: stretch;
    min-height: 44px;
    padding: 0 var(--mp360-space-4);
    border: 1px solid var(--mp360-primary);
    border-radius: var(--mp360-radius);
    background: transparent;
    color: var(--mp360-primary);
    font: inherit;
    font-size: 14px;
    font-weight: var(--mp360-weight-medium);
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease),
                color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-stages__cta:hover:not(:disabled) { background: var(--mp360-primary); color: var(--mp360-on-primary); }
.mp360-stages__cta:focus-visible { outline: 2px solid var(--mp360-accent); outline-offset: 2px; }
.mp360-stages__cta:disabled { opacity: 0.45; cursor: default; }

/* La superficie no necesita el ancho de una de contenido. */
.mp360-surface__body[data-type="stages"] { width: min(520px, 100%); }

/* --------------------------------------------------------------------------
   18b. Navegador contextual de plan

   Vive sobre el panorama, bajo la navbar. Esa banda está libre en los cuatro
   viewports: el botón de inicio va arriba a la izquierda, el minimapa arriba a
   la derecha, y el selector, la leyenda y el starter viven abajo.

   Es un modo temporal, así que se comporta como tal: entra desde arriba, no
   bloquea el panorama y se sale con la X o con Esc.
   -------------------------------------------------------------------------- */

/*
  Lateral izquierdo, apilado bajo "Volver al inicio". Antes vivía centrado
  arriba y ocupaba la posición más protagonista de la pantalla para lo que es un
  modo temporal; acá se lee como una extensión de los controles de navegación
  que ya viven en esa columna, y deja el centro del panorama libre.

  No va bajo el minimapa a propósito: esa esquina concentra el minimapa, el
  marcador activo y los rótulos de zona del propio export, y es donde más
  colisiones aparecen.

  La posición reutiliza la expresión del home —navbar de 72px más un paso— y le
  suma su alto. Si el home se mueve, esta línea se mueve con él.
*/
.mp360-planav {
    position: absolute;
    left: max(var(--mp360-space-6), var(--mp360-safe-left));
    top: calc(var(--mp360-safe-top) + 72px + var(--mp360-space-6)
              + 44px + var(--mp360-space-3));
    z-index: 8;
    display: flex;
    flex-direction: column;
    gap: var(--mp360-space-2);
    width: min(268px, calc(100vw - 2 * var(--mp360-space-6)));
    padding: var(--mp360-space-3);
    border-radius: var(--mp360-radius);
    background: var(--mp360-surface);
    /* Más liviana que una superficie: acompaña, no se impone. */
    box-shadow: 0 2px 10px rgba(10, 52, 37, 0.22);
    color: var(--mp360-text);
    opacity: 0;
    transform: translateY(-6px);
    transition: opacity var(--mp360-dur-fast) var(--mp360-ease),
                transform var(--mp360-dur-base) var(--ease-mp360-back);
}

.mp360-planav.is-open { opacity: 1; transform: translateY(0); }
.mp360-planav[hidden] { display: none; }

/* Con una superficie abierta se aparta, pero la exploración no se pierde. */
.mp360-root:has(.mp360-surface.is-open) .mp360-planav { opacity: 0; pointer-events: none; }

.mp360-planav__head { display: flex; align-items: flex-start; gap: var(--mp360-space-3); }

.mp360-planav__swatch {
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    margin-top: 2px;
    border-radius: 4px;
    background: var(--mp360-band, transparent);
    box-shadow: inset 0 0 0 1px rgba(10, 52, 37, 0.28);
}

.mp360-planav__texts { flex: 1 1 auto; min-width: 0; }

.mp360-planav__cuota {
    margin: 0;
    font-size: 13px;
    font-weight: var(--mp360-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.mp360-planav__hint { margin: 1px 0 0; font-size: 11px; line-height: 1.35; opacity: 0.62; }

.mp360-planav__close {
    position: relative;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    margin: -4px -6px 0 0;
    border: 0;
    border-radius: var(--mp360-radius);
    background: none;
    color: inherit;
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-planav__close:hover { background: rgba(10, 52, 37, 0.07); }
.mp360-planav__close:focus-visible { outline: 2px solid var(--mp360-accent); outline-offset: 1px; }

/*
  Único caso con tamaño propio: el navegador es un control compacto sobre el
  panorama y su X siempre fue más chica que la de las superficies. Se conserva
  esa proporción —16px de caja dan 9,3px de tinta, lo mismo que las diagonales
  de 13px que tenía— cambiando sólo el valor, no el recurso.
*/
.mp360-planav__close { --mp360-close-size: 16px; }

.mp360-planav__steps {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--mp360-space-3);
}

.mp360-planav__count { margin: 0; flex: 1 1 auto; font-size: 11px; opacity: 0.7; text-align: center; }

.mp360-planav__arrow {
    position: relative;
    flex: 0 0 auto;
    width: 36px;
    height: 36px;
    border: 1px solid rgba(10, 52, 37, 0.2);
    border-radius: var(--mp360-radius);
    background: transparent;
    color: inherit;
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease),
                border-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-planav__arrow:hover { background: rgba(10, 52, 37, 0.06); }
.mp360-planav__arrow:focus-visible { outline: 2px solid var(--mp360-accent); outline-offset: 2px; }
.mp360-planav__arrow[hidden] { display: none; }

.mp360-planav__arrow::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 8px;
    height: 8px;
    border-left: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: translate(-40%, -50%) rotate(45deg);
}

.mp360-planav__arrow--next::before { transform: translate(-60%, -50%) rotate(-135deg); }

@media (max-width: 640px) {
    .mp360-values__head { padding: var(--mp360-space-4) var(--mp360-space-4) var(--mp360-space-3); }
    .mp360-values__title { font-size: 19px; }
    .mp360-values__scroll { padding: var(--mp360-space-3) var(--mp360-space-4) var(--mp360-space-6); }

    /* Tres cifras en 390px quedan ilegibles: pasan a dos filas. */
    .mp360-values__figs { grid-template-columns: repeat(2, minmax(0, 1fr)); }

    .mp360-values__tour { align-self: stretch; text-align: center; }

    /*
      Dos tarjetas lado a lado no entran: se apilan y cada una respira.

      El padding usa `--mp360-space-4`, no un token inventado: la escala es
      4·8·12·16·24·32·48 y NO tiene un paso 5. Un `var()` inexistente dentro de
      un shorthand no cae al valor de la regla base —queda inválido a la hora de
      computar y el navegador aplica el valor inicial—, así que el header
      terminaba con `padding: 0` y el título, la bajada y la X de 44px quedaban
      pegados a los bordes. Detectado en iPhone real.
    */
    .mp360-stages__head { padding: var(--mp360-space-4) var(--mp360-space-4) var(--mp360-space-3); }
    .mp360-stages__title { font-size: 19px; }
    .mp360-stages__list {
        grid-template-columns: minmax(0, 1fr);
        gap: var(--mp360-space-3);
        padding: var(--mp360-space-4);
    }

    /*
      A ancho completo el navegador se montaba sobre "Volver al inicio":
      medido en 390×844, home ocupaba 12–138 × 76–116 y el navegador
      12–378 × 88–195. En desktop no pasa porque el navegador va centrado y el
      home vive en el extremo izquierdo.

      Se apila debajo del home reutilizando SU misma expresión —navbar de 60px
      más un paso— y sumando su alto compacto. Si el home cambia de altura o de
      posición en este breakpoint, esta línea tiene que moverse con él.
    */
    .mp360-planav {
        left: max(var(--mp360-space-3), var(--mp360-safe-left));
        right: max(var(--mp360-space-3), var(--mp360-safe-right));
        /* Home compacto: navbar de 60px, alto 40px. */
        top: calc(var(--mp360-safe-top) + 60px + var(--mp360-space-4)
                  + 40px + var(--mp360-space-3));
        width: auto;
    }
}

@media (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .mp360-values__head { padding: var(--mp360-space-3) var(--mp360-space-4) var(--mp360-space-2); }
    .mp360-values__title { font-size: 18px; }
    /*
      Apaisado: la altura es el recurso escaso, así que vuelven las dos
      columnas —hay ancho de sobra— y se comprime el encabezado.
    */
    .mp360-stages__head { padding: var(--mp360-space-3) var(--mp360-space-4) var(--mp360-space-2); }
    .mp360-stages__title { font-size: 18px; }
    .mp360-stages__list {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--mp360-space-3);
        padding: var(--mp360-space-3) var(--mp360-space-4);
    }
    .mp360-values__scroll { padding: var(--mp360-space-3) var(--mp360-space-4); gap: var(--mp360-space-3); }
    /*
      Apaisado: navbar de 52px y home de 36px, con el aire mínimo.

      `right` y `width` se re-declaran a propósito. El bloque de `max-width:
      767px` —que un teléfono acostado de 667 o 740 también cumple— estira la
      tarjeta de borde a borde, y una banda del ancho completo cruzando el
      panorama es exactamente lo que un modo temporal no debe hacer cuando el
      alto ya es escaso. Vuelve a ser la card angosta de la columna izquierda,
      igual que a 812 o 844, donde ese bloque no llega a aplicarse.

      En apaisado el notch va al COSTADO: el inset lateral no es decorativo.
    */
    .mp360-planav {
        left: max(var(--mp360-space-3), var(--mp360-safe-left));
        right: auto;
        width: min(268px, calc(100vw - 2 * var(--mp360-space-3)
                                     - var(--mp360-safe-left) - var(--mp360-safe-right)));
        top: calc(var(--mp360-safe-top) + 52px + var(--mp360-space-3)
                  + 36px + var(--mp360-space-2));
    }
}

/* --------------------------------------------------------------------------
   19. Filtros de lote (Fase 7)

   Un componente, dos presentaciones: popover anclado a la disponibilidad en
   escritorio, hoja inferior en móvil. Lo decide este archivo, no el JS, igual
   que la leyenda ya hace con su fila compacta.
   -------------------------------------------------------------------------- */

/* --- disparador dentro de la disponibilidad --- */

.mp360-legend__actions {
    display: flex;
    align-items: center;
    gap: var(--mp360-space-3);
    margin-top: var(--mp360-space-2);
}

/* El disclosure deja de ocupar el ancho entero: ahora lo comparte. */
.mp360-legend__actions .mp360-legend__toggle {
    flex: 1 1 auto;
    min-width: 0;
    margin-top: 0;
}

/*
  Apaisado: la fila de acciones deja de ser una fila y pasa a ser la segunda
  columna de la fila compacta, así que su separación superior sobra.

  Va ACÁ y no junto al resto de la composición apaisada, unos miles de líneas
  más arriba, por la cascada: `.mp360-legend__actions` de la regla base tiene
  la misma especificidad y se declara después, así que ganaba. Medído: la fila
  quedaba en 48px en vez de 40 y la card en 64 en vez de 56.
*/
@media (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .mp360-legend__actions { margin-top: 0; }
}

.mp360-legend__filter {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 34px;
    padding: 0 var(--mp360-space-3);
    border: 1px solid rgba(10, 52, 37, 0.22);
    border-radius: var(--mp360-radius);
    background: none;
    cursor: pointer;
    font-family: inherit;
    font-size: 13px;
    font-weight: var(--mp360-weight-medium);
    color: var(--mp360-primary);
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease),
                border-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-legend__filter:hover { background: rgba(10, 52, 37, 0.07); border-color: rgba(10, 52, 37, 0.4); }
.mp360-legend__filter:active { background: rgba(10, 52, 37, 0.12); }

/*
  Con filtros activos el botón deja de ser una acción disponible y pasa a ser
  un estado: es lo único que le avisa al usuario que no está viendo el
  recorrido completo.
*/
.mp360-legend__filter.has-filters {
    border-color: var(--mp360-accent);
    color: var(--mp360-accent);
}

.mp360-legend__filter-ico {
    width: 16px;
    height: 16px;
    background: currentColor;
    -webkit-mask: var(--mp360-ico-filter) center / contain no-repeat;
            mask: var(--mp360-ico-filter) center / contain no-repeat;
}

.mp360-legend__filter-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 9px;
    background: var(--mp360-accent);
    color: var(--mp360-on-accent);
    font-size: 11px;
    font-weight: var(--mp360-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.mp360-legend__filter-badge[hidden] { display: none; }

/* --- panel --- */

/*
  El velo no oscurece en escritorio: sólo captura el click de afuera. El panel
  es una extensión de un control, no una superficie que toma la pantalla.
*/
.mp360-lotfilter__scrim {
    position: absolute;
    inset: 0;
    z-index: 11;
    background: transparent;
}

.mp360-lotfilter__scrim[hidden] { display: none; }

.mp360-lotfilter {
    position: absolute;
    z-index: 12;
    display: flex;
    flex-direction: column;
    width: 300px;
    max-height: calc(100vh - 24px);
    border-radius: var(--mp360-radius);
    background: var(--mp360-surface);
    box-shadow: 0 14px 40px rgba(0, 0, 0, 0.26);
    color: var(--mp360-text);
    overflow: hidden;
    opacity: 0;
    transform: translateY(6px) scale(0.985);
    transition: opacity var(--mp360-dur-fast) var(--mp360-ease),
                transform var(--mp360-dur-base) var(--ease-mp360-back);
}

.mp360-lotfilter.is-open { opacity: 1; transform: none; }
.mp360-lotfilter[hidden] { display: none; }

.mp360-lotfilter__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--mp360-space-2);
    flex: 0 0 auto;
    padding: var(--mp360-space-3) var(--mp360-space-3) var(--mp360-space-3) var(--mp360-space-4);
    border-bottom: 1px solid rgba(10, 52, 37, 0.12);
}

.mp360-lotfilter__title {
    margin: 0;
    font-size: 15px;
    font-weight: var(--mp360-weight-semibold);
    color: var(--mp360-primary);
}

.mp360-lotfilter__close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    flex: 0 0 auto;
    border: 0;
    border-radius: var(--mp360-radius);
    background: none;
    color: var(--mp360-primary);
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-lotfilter__close:hover { background: rgba(10, 52, 37, 0.08); }

.mp360-lotfilter__body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: var(--mp360-space-3) var(--mp360-space-4) var(--mp360-space-4);
}

.mp360-lotfilter__section + .mp360-lotfilter__section { margin-top: var(--mp360-space-4); }

.mp360-lotfilter__legend {
    margin: 0 0 var(--mp360-space-2);
    font-size: 11px;
    font-weight: var(--mp360-weight-medium);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--mp360-primary);
    opacity: 0.55;
}

/* --- interruptor de estado --- */

.mp360-lotfilter__switch {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--mp360-space-3);
    width: 100%;
    min-height: 44px;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
    font-family: inherit;
    text-align: left;
    color: var(--mp360-text);
}

.mp360-lotfilter__switch-texts { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.mp360-lotfilter__switch-label { font-size: 14px; font-weight: var(--mp360-weight-medium); }
.mp360-lotfilter__switch-note { font-size: 12px; opacity: 0.6; }

.mp360-lotfilter__track {
    position: relative;
    flex: 0 0 auto;
    width: 38px;
    height: 22px;
    border-radius: 11px;
    background: rgba(10, 52, 37, 0.22);
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-lotfilter__track::after {
    content: "";
    position: absolute;
    top: 3px;
    left: 3px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--mp360-surface);
    transition: transform var(--mp360-dur-base) var(--ease-mp360-back);
}

.mp360-lotfilter__switch.is-on .mp360-lotfilter__track { background: var(--mp360-accent); }
.mp360-lotfilter__switch.is-on .mp360-lotfilter__track::after { transform: translateX(16px); }

/* --- filas de plan --- */

.mp360-lotfilter__plans { display: flex; flex-direction: column; gap: 2px; }

/*
  La fila entera es el objetivo: no hay que acertarle al swatch. 44px de alto
  real, como el resto de los controles táctiles del sistema.
*/
.mp360-lotfilter__plan {
    display: flex;
    align-items: center;
    gap: var(--mp360-space-2);
    width: 100%;
    min-height: 44px;
    padding: 0 var(--mp360-space-2);
    border: 1px solid transparent;
    border-radius: var(--mp360-radius);
    background: none;
    cursor: pointer;
    font-family: inherit;
    text-align: left;
    color: var(--mp360-text);
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease),
                border-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-lotfilter__plan:hover { background: rgba(10, 52, 37, 0.06); }

/*
  Seleccionado se lee por TRES señales: el check, el borde y el fondo. El color
  del swatch identifica el plan, nunca el estado — si la selección dependiera
  del color, seis filas de colores distintos serían indistinguibles.
*/
.mp360-lotfilter__plan.is-on {
    border-color: var(--mp360-accent);
    background: rgba(61, 101, 0, 0.08);
}

.mp360-lotfilter__check {
    position: relative;
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    border: 1.5px solid rgba(10, 52, 37, 0.35);
    border-radius: 5px;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease),
                border-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-lotfilter__plan.is-on .mp360-lotfilter__check {
    background: var(--mp360-accent);
    border-color: var(--mp360-accent);
}

.mp360-lotfilter__check::after {
    content: "";
    position: absolute;
    left: 5px;
    top: 1px;
    width: 5px;
    height: 9px;
    border-right: 2px solid var(--mp360-on-accent);
    border-bottom: 2px solid var(--mp360-on-accent);
    transform: rotate(45deg) scale(0.6);
    opacity: 0;
    transition: opacity var(--mp360-dur-fast) var(--mp360-ease),
                transform var(--mp360-dur-micro) var(--ease-mp360-back);
}

.mp360-lotfilter__plan.is-on .mp360-lotfilter__check::after { opacity: 1; transform: rotate(45deg) scale(1); }

.mp360-lotfilter__swatch {
    flex: 0 0 auto;
    width: 14px;
    height: 14px;
    border-radius: 4px;
    background: var(--mp360-band, #FFFFFF);
    box-shadow: inset 0 0 0 1px rgba(10, 52, 37, 0.25);
}

/* Sin plan asignado: el mismo blanco con el que ya se lo representa. */
.mp360-lotfilter__swatch--none { background: #FFFFFF; }

.mp360-lotfilter__plan-label {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 14px;
    font-variant-numeric: tabular-nums;
}

/* "Consultar condiciones" no es una séptima banda: se separa. */
.mp360-lotfilter__sep {
    height: 1px;
    margin: var(--mp360-space-2);
    background: rgba(10, 52, 37, 0.12);
}

.mp360-lotfilter__empty {
    margin: var(--mp360-space-3) 0 0;
    padding: var(--mp360-space-2) var(--mp360-space-3);
    border-radius: var(--mp360-radius);
    background: rgba(10, 52, 37, 0.06);
    font-size: 13px;
    line-height: 1.4;
}

.mp360-lotfilter__empty[hidden] { display: none; }

/* --- pie --- */

.mp360-lotfilter__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--mp360-space-3);
    flex: 0 0 auto;
    padding: var(--mp360-space-3) var(--mp360-space-4);
    border-top: 1px solid rgba(10, 52, 37, 0.12);
}

.mp360-lotfilter__clear {
    padding: 0;
    min-height: 36px;
    border: 0;
    background: none;
    cursor: pointer;
    font-family: inherit;
    font-size: 13px;
    font-weight: var(--mp360-weight-medium);
    color: var(--mp360-accent);
}

.mp360-lotfilter__done {
    min-height: 36px;
    padding: 0 var(--mp360-space-4);
    border: 0;
    border-radius: var(--mp360-radius);
    background: var(--mp360-primary);
    color: var(--mp360-on-primary);
    cursor: pointer;
    font-family: inherit;
    font-size: 13px;
    font-weight: var(--mp360-weight-semibold);
}

/* --- móvil: hoja inferior --- */

/*
  Sin disclosure de valores —lo reemplaza la fila compacta—, la fila de
  acciones queda sólo con el filtro y ocupa el ancho. Es de clase dispositivo,
  no de orientación: vale en vertical y en apaisado.
*/
@media (max-width: 767px),
       (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .mp360-legend__filter {
        flex: 1 1 auto;
        justify-content: center;
        min-height: 40px;
    }
}

/*
  HOJA INFERIOR: sólo en VERTICAL.

  Iba en `max-width: 767px` a secas y eso partía a los teléfonos acostados en
  dos: a 667x375 se aplicaban la hoja (left/right/bottom 0) Y la columna de
  280px del bloque de apaisado, dos presentaciones peleando por el mismo nodo;
  a 812x375 no se aplicaba ninguna de las dos y quedaba la de escritorio.

  En apaisado la presentación aprobada es la columna lateral (§28 del perfil):
  un panel de 200px con seis planes dentro no es un panel. La hoja es la
  respuesta de vertical y se queda en vertical.
*/
@media (max-width: 767px) and (orientation: portrait) {
    .mp360-lotfilter__scrim { background: rgba(10, 20, 16, 0.32); }

    .mp360-lotfilter {
        left: 0;
        right: 0;
        bottom: 0;
        top: auto;
        width: auto;
        max-height: min(76dvh, 560px);
        border-radius: 16px 16px 0 0;
        padding-bottom: var(--mp360-safe-bottom);
        transform: translateY(16px);
    }

    .mp360-lotfilter.is-open { transform: none; }

    .mp360-lotfilter__title { font-size: 16px; }
    .mp360-lotfilter__done { flex: 1 1 auto; text-align: center; }
    .mp360-lotfilter__clear { flex: 0 0 auto; }
}

/*
  Apaisado: la altura es el recurso escaso. La hoja no puede comerse el
  viewport ni dejar el CTA fuera de pantalla.
*/
@media (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    /*
      Columna angosta: a 844px de ancho la franja central del selector empieza
      en ~300px, y 280 deja el panel enteramente fuera de su camino.
    */
    .mp360-lotfilter { width: 280px; }
    .mp360-lotfilter__body { padding: var(--mp360-space-2) var(--mp360-space-4) var(--mp360-space-3); }
    .mp360-lotfilter__head,
    .mp360-lotfilter__foot { padding-top: var(--mp360-space-2); padding-bottom: var(--mp360-space-2); }
    .mp360-lotfilter__switch { min-height: 40px; }
    .mp360-lotfilter__plan { min-height: 40px; }

    /*
      El panel se ancla contra el borde inferior, así que necesita el mismo
      resguardo que la versión de hoja vertical. Sin esto, "Aplicar" queda bajo
      la barra de gestos con el teléfono acostado.
    */
    .mp360-lotfilter__foot { padding-bottom: max(var(--mp360-space-2), var(--mp360-safe-bottom)); }
}

/* --------------------------------------------------------------------------
   19b. Aviso de cambio de etapa

   Un solo nodo, transitorio, apoyado sobre la disponibilidad —que es de lo que
   habla—. No es un modal: sin velo, sin centro de pantalla y sin capturar el
   puntero salvo en su X.
   -------------------------------------------------------------------------- */

.mp360-notice {
    position: absolute;
    z-index: 11;
    display: flex;
    align-items: flex-start;
    gap: var(--mp360-space-2);
    width: min(320px, calc(100vw - 2 * var(--mp360-space-4)));
    padding: var(--mp360-space-3);
    border-radius: var(--mp360-radius);
    background: var(--mp360-surface);
    /* Sombra de control, no de superficie: acompaña, no se impone. */
    box-shadow: 0 4px 16px rgba(10, 52, 37, 0.24);
    color: var(--mp360-text);
    /* No bloquea el recorrido: sólo la X recibe el puntero. */
    pointer-events: none;
    opacity: 0;
    transform: translateY(8px);
    transition: opacity var(--mp360-dur-fast) var(--mp360-ease),
                transform var(--mp360-dur-base) var(--ease-mp360-back);
}

.mp360-notice.is-open { opacity: 1; transform: none; }
.mp360-notice[hidden] { display: none; }

.mp360-notice__ico {
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    margin-top: 1px;
    background: var(--mp360-accent);
    -webkit-mask: var(--mp360-ico-info) center / contain no-repeat;
            mask: var(--mp360-ico-info) center / contain no-repeat;
}

.mp360-notice__texts { flex: 1 1 auto; min-width: 0; }

.mp360-notice__title {
    margin: 0;
    font-size: 14px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1.25;
    color: var(--mp360-primary);
}

.mp360-notice__body {
    margin: 2px 0 0;
    font-size: 12.5px;
    line-height: 1.4;
    opacity: 0.75;
}

.mp360-notice__close {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    margin: -4px -4px 0 0;
    border: 0;
    border-radius: var(--mp360-radius);
    background: none;
    color: var(--mp360-primary);
    cursor: pointer;
    /* La única parte interactiva del aviso. */
    pointer-events: auto;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-notice__close:hover { background: rgba(10, 52, 37, 0.08); }

/* Con una superficie abierta el aviso no compite: se atenúa, como el resto. */
.mp360-root:has(.mp360-surface.is-open) .mp360-notice { opacity: 0; }

@media (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .mp360-notice { width: min(280px, calc(100vw - 2 * var(--mp360-space-4))); padding: var(--mp360-space-2); }
    .mp360-notice__body { font-size: 12px; }
}

/* --------------------------------------------------------------------------
   21. CursorSystem — cursor Nucleo y micro-lens

   Dos elementos hermanos en `body`, nunca anidados: el cursor lleva un
   `drop-shadow` y la lens un `backdrop-filter`, y un filtro en el ancestro
   aislaría el backdrop del descendiente — la lens dejaría de ver el recorrido.

   Cada uno separa el SEGUIMIENTO de la EXPRESIÓN en dos capas:

     el contenedor  traslada, sin transición: el cursor no puede ir detrás
                    del mouse. La precisión es la función; el resto es adorno.
     el hijo        escala y se atenúa, con transición: es lo único que
                    interpola.

   Si estuvieran en el mismo `transform`, una transición sobre la escala
   arrastraría también la traslación y el cursor flotaría.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   COLOR DEL CURSOR — se adapta al plano que tiene debajo

   Un cursor blanco sobre una superficie blanca no existe, y MP360 está lleno de
   superficies blancas. Sobre ellas pasa a verde oscuro de marca; sobre el
   recorrido y sobre las islas oscuras vuelve al blanco.

   Es un cambio de COLOR, no de cursor: la misma geometría Nucleo, las mismas
   microtransformaciones, la misma sombra. Los dos paths heredan `currentColor`,
   así que alcanza con transicionar esta propiedad. 220ms del Motion System —el
   mismo tempo de los paneles— para que se lea como una adaptación al material y
   no como un parpadeo.
   -------------------------------------------------------------------------- */

.mp360-cursor {
    color: #fff;
    transition: color var(--mp360-dur-panel) var(--mp360-ease);
}

.mp360-cursor[data-tone="light"] { color: var(--mp360-primary); }

.mp360-cursor,
.mp360-cursor-lens {
    position: fixed;
    top: 0;
    left: 0;
    width: 0;
    height: 0;
    /* Por encima de todo lo de MP360 —superficies incluidas— sin participar
       de su sistema de capas: no compite con nada porque no recibe eventos. */
    z-index: 2147483000;
    /* CRÍTICO: nunca captura hover, click, drag ni altera el hit testing. */
    pointer-events: none;
    opacity: 0;
    /* La capa se promueve una vez; después sólo se reescribe el transform. */
    will-change: transform;
}

/* El nativo se apaga recién cuando el sistema ya está siguiendo al puntero. */
html.mp360-cursor-visible .mp360-cursor,
html.mp360-cursor-visible .mp360-cursor-lens { opacity: 1; }

html.mp360-cursor-visible,
html.mp360-cursor-visible * { cursor: none !important; }

/*
  Donde la forma nativa informa algo que no debemos sustituir, gana ella. Es
  más específico que la regla de arriba, así que no hace falta ordenarlas.
*/
html.mp360-cursor-visible input:not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]),
html.mp360-cursor-visible textarea,
html.mp360-cursor-visible [contenteditable="true"] { cursor: text !important; }

/* Estado `native`: el sistema se retira por completo y devuelve la pantalla. */
html.mp360-cursor-native,
html.mp360-cursor-native * { cursor: auto !important; }
html.mp360-cursor-native .mp360-cursor,
html.mp360-cursor-native .mp360-cursor-lens { opacity: 0; }

/* --- la flecha --- */

.mp360-cursor__arrow {
    position: absolute;
    /*
      La punta del recurso cae en (8.877, 8.877) del viewBox de 32. Se corre la
      caja para que ese punto quede sobre el puntero, y se ancla ahí el origen
      de la escala: así ninguna microtransformación mueve la punta.
    */
    left: calc(-1 * var(--mp360-cursor-hot, 8.877px));
    top: calc(-1 * var(--mp360-cursor-hot, 8.877px));
    width: 32px;
    height: 32px;
    transform-origin: var(--mp360-cursor-hot, 8.877px) var(--mp360-cursor-hot, 8.877px);
    /*
      Misma sombra del recurso Nucleo —dy 1, blur .5, negro al 25%— resuelta
      por el compositor en vez de por un filtro SVG. Es lo único que separa al
      cursor blanco de una superficie blanca; sin ella se pierde.
    */
    filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.25));
    transition: transform var(--mp360-dur-fast) var(--mp360-ease);
}

/*
  Microcompresión táctil, no animación. La escala baja al entrar en algo
  clickeable, baja un poco más al presionar y se sostiene al arrastrar.
*/
.mp360-cursor[data-state="interactive"] .mp360-cursor__arrow { transform: scale(0.95); }
.mp360-cursor[data-state="pressed"]     .mp360-cursor__arrow { transform: scale(0.91); }
.mp360-cursor[data-state="dragging"]    .mp360-cursor__arrow { transform: scale(0.93); }

/* --- la lens --- */

.mp360-cursor-lens__disc {
    position: absolute;
    left: -14px;
    top: -14px;
    width: 28px;
    height: 28px;
    transform-origin: 14px 14px;
    border-radius: 50%;

    /*
      El efecto entero. Sobre blanco o gris no hay saturación que bajar y la
      lens es literalmente invisible; sobre un verde de marca o un lote rosa
      aparece sola. Por eso no hace falta leer un solo píxel.

      Sin borde, sin relleno, sin glow: no hay nada que dibujar, sólo algo que
      atenuar.
    */
    -webkit-backdrop-filter: saturate(0.72) brightness(0.97);
            backdrop-filter: saturate(0.72) brightness(0.97);

    /*
      Un disco de borde duro se leería como un círculo decorativo. La máscara
      radial lo disuelve: hay un núcleo y después nada, sin contorno posible.
    */
    -webkit-mask: radial-gradient(closest-side, #000 30%, rgba(0, 0, 0, 0) 100%);
            mask: radial-gradient(closest-side, #000 30%, rgba(0, 0, 0, 0) 100%);

    /*
      La intensidad se modula con `opacity`, que mezcla el backdrop filtrado
      con el original: un solo valor de filtro y una transición barata. En
      reposo apenas existe; al entrar en algo interactivo termina de aparecer.
    */
    opacity: 0.34;
    transition: opacity var(--mp360-dur-base) var(--mp360-ease),
                transform var(--mp360-dur-base) var(--mp360-ease);
}

.mp360-cursor-lens[data-state="interactive"] .mp360-cursor-lens__disc { opacity: 0.9; }
.mp360-cursor-lens[data-state="pressed"]     .mp360-cursor-lens__disc { opacity: 1; transform: scale(0.88); }
/* Arrastrando el panorama la lens se recoge: acompaña el peso, no compite. */
.mp360-cursor-lens[data-state="dragging"]    .mp360-cursor-lens__disc { opacity: 0.45; transform: scale(0.8); }

/*
  Motion reducido: se conserva la función —el cursor y la lens siguen ahí y
  siguen siendo precisos— y se quitan las interpolaciones secundarias.
*/
@media (prefers-reduced-motion: reduce) {
    .mp360-cursor__arrow,
    .mp360-cursor-lens__disc { transition: none; }
    .mp360-cursor[data-state] .mp360-cursor__arrow { transform: none; }
    .mp360-cursor-lens[data-state] .mp360-cursor-lens__disc { transform: none; }
}

/*
  Sin puntero fino no existe nada de esto. La condición es la capacidad del
  dispositivo, no el ancho: el JS ni siquiera monta los nodos, y esta regla es
  la red por si algo los dejara puestos.
*/
@media not all and (hover: hover) and (pointer: fine) {
    .mp360-cursor,
    .mp360-cursor-lens { display: none !important; }
    html.mp360-cursor-visible,
    html.mp360-cursor-visible * { cursor: auto !important; }
}

/* --------------------------------------------------------------------------
   21b. Avances de obra — última actualización

   MP360 CONTIENE la publicación; no imita Instagram alrededor de ella. Todo lo
   que rodea al embed es el sistema de siempre: la Surface, su cabecera, su X y
   un CTA secundario. Ni un borde, ni un ícono, ni una tipografía prestados.
   -------------------------------------------------------------------------- */

/*
  La superficie termina en el contenido. Sin CTA debajo, no queda ni el hueco ni
  el gap que existían para sostenerlo: la caja del embed se queda con ese alto,
  que además es justo lo que le faltaba para no recortar el pie de la
  publicación.
*/
.mp360-progress__latest {
    display: flex;
    flex-direction: column;
    align-items: center;
}

/*
  La caja del embed. Instagram ajusta su contenido al alto disponible, así que
  fijarla evita el salto de layout al cargar y hace que el estado de espera, el
  embed y el fallback ocupen exactamente el mismo lugar.
*/
.mp360-progress__embed {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--mp360-space-2);
    width: min(360px, 100%);
    height: min(70vh, 660px);
    min-height: 320px;
    padding: var(--mp360-space-4);
    border: 1px solid rgba(10, 52, 37, 0.12);
    border-radius: var(--mp360-radius);
    /* Superficie clara, nunca un rectángulo negro esperando contenido. */
    background: rgba(10, 52, 37, 0.03);
    overflow: hidden;
}

.mp360-progress__frame {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
    /* Aparece cuando cargó, para no mostrar el marco a medio pintar. */
    opacity: 0;
    transition: opacity var(--mp360-dur-base) var(--mp360-ease);
}

.mp360-progress__embed[data-ready="true"] { background: var(--mp360-surface); padding: 0; }
.mp360-progress__embed[data-ready="true"] .mp360-progress__frame { opacity: 1; }

.mp360-progress__embed-wait {
    margin: 0;
    font-size: 13px;
    opacity: 0.65;
    text-align: center;
}

/*
  Fallback: ocupa la caja del embed, no se agrega debajo. El enlace vive acá
  adentro porque es el único caso donde la superficie necesita una salida — si
  el embed no apareció, sin esto la función no lleva a ningún lado.
*/
.mp360-progress__fallback {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--mp360-space-3);
    text-align: center;
}

.mp360-progress__fallback-title {
    margin: 0;
    font-size: 16px;
    font-weight: var(--mp360-weight-semibold);
    color: var(--mp360-primary);
}

.mp360-progress__fallback-body {
    margin: 0;
    max-width: 26ch;
    font-size: 13px;
    line-height: 1.5;
    opacity: 0.72;
    text-align: center;
}

/* Sólo existe dentro del fallback. Con el embed cargado no hay ningún CTA. */
.mp360-progress__cta {
    margin-top: var(--mp360-space-1);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    /* Token real de la escala: no existe un paso 5 (ver §21b del header). */
    padding: 0 var(--mp360-space-4);
    border: 1px solid var(--mp360-primary);
    border-radius: var(--mp360-radius);
    color: var(--mp360-primary);
    font-size: 14px;
    font-weight: var(--mp360-weight-medium);
    text-decoration: none;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease),
                color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-progress__cta:hover { background: var(--mp360-primary); color: var(--mp360-on-primary); }
.mp360-progress__cta:focus-visible { outline: 2px solid var(--mp360-accent); outline-offset: 2px; }

@media (max-width: 767px) {
    .mp360-progress__embed { width: 100%; height: min(66vh, 620px); }
}

/*
  Apaisado de teléfono: el alto es el recurso escaso. La caja se queda en una
  medida usable y el cuerpo de la superficie scrollea, que es preferible a un
  reel de 150px.
*/
@media (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .mp360-progress__embed { height: 300px; min-height: 300px; width: min(190px, 100%); }
    .mp360-progress__latest { gap: var(--mp360-space-3); }
}


/* ==========================================================================
   BLOQUEO TEMPORAL DE APAISADO DE TELÉFONO

   TEMPORAL Y AUTOCONTENIDO. Mientras se termina el rediseño de la capa
   landscape, un teléfono acostado no ve la experiencia. Cuando esa capa
   cierre, se borran juntos: este bloque, la <section class="mp360-rotate"> de
   index.html y RotateGate en mp360.js. No hay nada más enganchado.

   FUENTE ÚNICA DE VERDAD: la media query de más abajo. El JS no decide si esto
   se ve —sólo marca el fondo como inert para que teclado y lectores de
   pantalla no lo alcancen—. Esa separación es lo que hace que volver a
   vertical restaure la experiencia entera sin recargar y sin escribir un solo
   restaurador: la regla deja de aplicar y detrás sigue todo como estaba.

   LA CONDICIÓN ES LA DE §38, sin variantes, y debe coincidir EXACTAMENTE con
   MQ_APAISADO_TACTIL en mp360.js. `pointer: coarse` es la guarda que separa
   teléfono acostado de ventana de escritorio baja: es literalmente lo que hace
   que 1366×450 con mouse no se bloquee.
   ========================================================================== */

.mp360-rotate {
    /* Oculto en todos lados salvo donde la media query lo enciende. */
    display: none;
    position: fixed;
    inset: 0;
    min-height: 100dvh;
    /*
      Por encima de TODO lo de MP360: loading-screen 100, loading-header 90,
      wipe 60, tooltip 30, superficies 20, navbar 10. Queda por debajo del
      cursor (2147483000), que es pointer-events: none y en táctil ni se
      enciende.
    */
    z-index: 200;

    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--mp360-space-6);

    /* En apaisado el notch va a los COSTADOS: el inset lateral no es decorativo. */
    padding: calc(var(--mp360-space-4) + var(--mp360-safe-top))
             max(var(--mp360-space-6), var(--mp360-safe-right))
             calc(var(--mp360-space-4) + var(--mp360-safe-bottom))
             max(var(--mp360-space-6), var(--mp360-safe-left));

    background: var(--mp360-background);
    color: var(--mp360-text);
    text-align: left;
    /* Corta el rubber-band: el bloqueo no rebota. */
    overscroll-behavior: none;

    /*
      Único movimiento de toda la pantalla, y es para no aparecer de golpe al
      girar. Nada gira, nada entra desde ningún lado.
    */
    animation: mp360-rotate-in var(--mp360-dur-base) var(--mp360-ease);
}

@keyframes mp360-rotate-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* El foco lo pone RotateGate para llevar al lector de pantalla acá; no es un
   control, así que no debe dibujar un anillo. */
.mp360-rotate:focus { outline: none; }

/*
  Marca. El PNG es de 443×269 y no hay SVG —mismo recurso que la navbar—, así
  que se limita el alto y se usa contain para no deformarlo.
*/
.mp360-rotate__logo {
    display: block;
    height: 32px;
    width: auto;
    max-width: 110px;
    object-fit: contain;
}

/*
  COMPOSICIÓN HORIZONTAL, no una columna centrada. El viewport es ancho y bajo:
  apilar cuatro cosas en vertical es exactamente el error que esta pantalla
  existe para señalar. El icono va al lado del texto, no encima.
  DESIGN.md §9: transformar el layout antes de comprimir contenido.
*/
.mp360-rotate__body {
    display: flex;
    align-items: center;
    gap: var(--mp360-space-4);
    max-width: 100%;
}

.mp360-rotate__ico {
    flex: 0 0 auto;
    width: 44px;
    height: 44px;
    color: var(--mp360-accent);
}

.mp360-rotate__texts { min-width: 0; }

.mp360-rotate__title {
    margin: 0;
    font-size: 20px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1.2;
    color: var(--mp360-primary);
}

/*
  El mensaje completo está acá: el icono no carga información que no esté
  escrita. La medida en `ch` mantiene la línea legible sin depender del ancho
  del teléfono.
*/
.mp360-rotate__text {
    margin: var(--mp360-space-2) 0 0;
    max-width: 46ch;
    font-size: 15px;
    line-height: 1.45;
    color: var(--mp360-text);
    opacity: 0.78;
}

/* --------------------------------------------------------------------------
   El interruptor. Una regla, una condición, idéntica a la de §38.
   -------------------------------------------------------------------------- */

@media (max-height: 480px) and (orientation: landscape) and (pointer: coarse) {
    .mp360-rotate { display: flex; }

    /*
      Ni scroll vertical ni horizontal del documento mientras dura. Mismo
      mecanismo que ya usa la intro con html.mp360-intro-active; no se inventa
      uno nuevo.
    */
    html,
    body { overflow: clip; }
}

/* Sin excepciones: si el sistema pide menos movimiento, no hay ninguno. */
@media (prefers-reduced-motion: reduce) {
    .mp360-rotate { animation: none; }
}


/* ==========================================================================
   PLANO VECTORIAL (POC, detrás de bandera)

   Interpretación propia de "plano técnico/comercial de Tipuana", no una copia
   de otro proyecto: base clara y neutra, geometría protagonista, todo lo no
   comercial en segundo plano (DESIGN.md §1). Tipografía, radios, verdes y
   curvas son los del sistema; no se introduce ningún token nuevo salvo el
   papel del propio plano, que no existía.

   Se borra junto con el módulo PlanoVector cuando el POC cierre o se apruebe.
   ========================================================================== */

:root {
    /* Papel del plano: un gris cálido muy claro, no blanco puro, para que las
       seis bandas comerciales se recorten sin competir. */
    --mp360-plano-papel: #F4F5F1;
    /* Cara sin identidad todavía: se lee como "no hay dato", nunca como un
       estado comercial. */
    --mp360-plano-neutro: #E3E5DE;
    --mp360-plano-linea: rgba(10, 52, 37, 0.28);
}

.mp360-surface__body[data-type="planovector"] {
    width: min(1600px, 88vw);
    height: min(88dvh, 1000px);
}

.mp360-plano {
    position: relative;
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
    background: var(--mp360-surface);
}

.mp360-plano__head {
    flex: 0 0 auto;
    padding: var(--mp360-space-4) var(--mp360-space-6) var(--mp360-space-3);
}

.mp360-plano__titulo {
    margin: 0;
    font-size: 20px;
    font-weight: var(--mp360-weight-semibold);
    line-height: 1.2;
    color: var(--mp360-primary);
}

/*
  El lienzo es el contenido: toma todo el alto que sobra. `touch-action: none`
  porque el gesto lo maneja el módulo — sin esto el navegador se queda el
  arrastre y el pan no llega nunca.
*/
.mp360-plano__lienzo {
    position: relative;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    background: var(--mp360-plano-papel);
    cursor: grab;
    touch-action: none;
}

.mp360-plano__lienzo.is-dragging { cursor: grabbing; }

.mp360-plano__svg {
    display: block;
    width: 100%;
    height: 100%;
}

/*
  El grosor de línea se divide por la escala para que el trazo se vea IGUAL a
  cualquier zoom. Sin esto, al acercarse los bordes engordan y el plano deja de
  leerse como dibujo técnico.
*/
.mp360-plano__lote {
    stroke: var(--mp360-plano-linea);
    stroke-width: calc(0.35px / var(--k, 1));
    stroke-linejoin: round;
    transition: fill-opacity var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-plano__lote.is-interactivo { cursor: pointer; }

/* Realce discreto: no cambia el color —que ES el dato— sino su densidad. */
@media (hover: hover) {
    .mp360-plano__lote.is-interactivo:hover {
        fill-opacity: 0.72;
        stroke: var(--mp360-primary);
        stroke-width: calc(1.1px / var(--k, 1));
    }
}

/* Contexto: calles internas y espacios. Segundo plano, sin excepción. */
.mp360-plano__area {
    fill: rgba(10, 52, 37, 0.045);
    stroke: none;
}

.mp360-plano__trazos line {
    stroke: rgba(10, 52, 37, 0.16);
    stroke-width: calc(0.3px / var(--k, 1));
}

/* --- controles: los mínimos --- */

.mp360-plano__controles {
    position: absolute;
    right: var(--mp360-space-4);
    bottom: var(--mp360-space-4);
    display: flex;
    gap: var(--mp360-space-2);
}

.mp360-plano__ctrl {
    min-height: 36px;
    padding: 0 var(--mp360-space-3);
    border: 1px solid rgba(10, 52, 37, 0.18);
    border-radius: var(--mp360-radius);
    background: var(--mp360-surface);
    box-shadow: 0 1px 4px rgba(10, 52, 37, 0.14);
    color: var(--mp360-primary);
    font-family: inherit;
    font-size: 13px;
    font-weight: var(--mp360-weight-medium);
    cursor: pointer;
    transition: background-color var(--mp360-dur-fast) var(--mp360-ease);
}

.mp360-plano__ctrl:hover { background: #EDF2E8; }

/* --- leyenda: compacta, en el pie, sin tapar desarrollo --- */

.mp360-plano__pie {
    flex: 0 0 auto;
    padding: var(--mp360-space-3) var(--mp360-space-6);
    border-top: 1px solid rgba(10, 52, 37, 0.1);
}

.mp360-plano__leyenda {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--mp360-space-2) var(--mp360-space-6);
    font-size: 12px;
    color: var(--mp360-text);
}

.mp360-plano__leg { display: inline-flex; align-items: center; gap: var(--mp360-space-2); }
.mp360-plano__sws { display: inline-flex; gap: 2px; }

.mp360-plano__sw {
    display: block;
    width: 13px;
    height: 13px;
    flex: 0 0 auto;
    border-radius: 3px;
    /* Igual que en la leyenda del recorrido: sin el anillo, las bandas claras
       desaparecen contra el papel. */
    box-shadow: inset 0 0 0 1px rgba(10, 52, 37, 0.35);
}

.mp360-plano__sw.is-mini { width: 10px; height: 10px; border-radius: 2px; }

.mp360-plano__error { padding: var(--mp360-space-6); color: var(--mp360-text); }

/* ==========================================================================
   EDITOR DE MAPPING — sólo con ?map-editor=1

   HERRAMIENTA DE DESARROLLO. Deliberadamente distinta del resto de la
   interfaz: superficie oscura y densa, para que nadie la confunda nunca con
   una superficie de producto.
   ========================================================================== */

.mp360-mapedit {
    position: absolute;
    top: var(--mp360-space-4);
    right: var(--mp360-space-4);
    z-index: 5;
    width: 264px;
    padding: var(--mp360-space-4);
    border-radius: var(--mp360-radius);
    background: rgba(10, 52, 37, 0.96);
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.35);
    color: #F4F5F1;
    font-size: 12px;
}

.mp360-mapedit__titulo {
    margin: 0 0 var(--mp360-space-3);
    font-size: 13px;
    font-weight: var(--mp360-weight-semibold);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.mp360-mapedit__campo {
    display: flex;
    align-items: center;
    gap: var(--mp360-space-2);
    margin-bottom: var(--mp360-space-2);
}

.mp360-mapedit__campo label { flex: 0 0 92px; opacity: 0.8; }

.mp360-mapedit__campo input {
    flex: 1 1 auto;
    min-width: 0;
    min-height: 30px;
    padding: 0 8px;
    border: 1px solid rgba(244, 245, 241, 0.3);
    border-radius: 3px;
    background: rgba(0, 0, 0, 0.25);
    color: inherit;
    font: inherit;
}

.mp360-mapedit__acciones {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: var(--mp360-space-3) 0;
}

.mp360-mapedit__btn {
    min-height: 28px;
    padding: 0 10px;
    border: 1px solid rgba(244, 245, 241, 0.3);
    border-radius: 3px;
    background: none;
    color: inherit;
    font: inherit;
    cursor: pointer;
}

.mp360-mapedit__btn:hover { background: rgba(244, 245, 241, 0.12); }
.mp360-mapedit__btn.is-primario { background: var(--mp360-accent); border-color: var(--mp360-accent); }

.mp360-mapedit__progreso { margin: var(--mp360-space-2) 0; line-height: 1.5; }
.mp360-mapedit__fila { margin: 0; font-variant-numeric: tabular-nums; }
.mp360-mapedit__fila b { font-weight: var(--mp360-weight-semibold); opacity: 0.75; }

.mp360-mapedit__aviso { margin: var(--mp360-space-2) 0 0; line-height: 1.4; min-height: 2.4em; }
.mp360-mapedit__aviso[data-tono="ok"] { color: #B7E1A1; }
.mp360-mapedit__aviso[data-tono="warn"] { color: #FFD48A; }
.mp360-mapedit__aviso[data-tono="error"] { color: #FFAFAF; }

.mp360-mapedit__ayuda { margin: var(--mp360-space-3) 0 0; opacity: 0.62; line-height: 1.45; }

/*
  En modo mapping importa QUÉ FALTA, así que lo ya asignado se marca con el
  color de acción y lo pendiente queda neutro. Es lo contrario de producción,
  a propósito.
*/
.mp360-plano__lote.is-asignado {
    stroke: var(--mp360-accent);
    stroke-width: calc(1.2px / var(--k, 1));
}

/* Manzana topologica de la cara que se acaba de tocar: contesta "esto es una
   sola manzana?" sin que el editor tenga que adivinar identidad. */
.mp360-plano__lote.is-bloque {
    fill: #FFF3C4;
    stroke: var(--mp360-accent);
    stroke-width: calc(0.9px / var(--k, 1));
}

.mp360-mapedit__bloque {
    margin: 0 0 var(--mp360-space-2);
    padding-bottom: var(--mp360-space-2);
    border-bottom: 1px solid rgba(244, 245, 241, 0.18);
    font-variant-numeric: tabular-nums;
    opacity: 0.9;
    min-height: 1.2em;
}

/* Cara con manzana identificada por las capturas pero sin numero de lote
   todavia: es exactamente el trabajo que queda por hacer. */
.mp360-plano__lote.is-con-manzana {
    fill: #DCE8F2;
    stroke: rgba(10, 52, 37, 0.35);
}

/* Cara tocada. Vale en runtime y en editor: confirma que el toque llego,
   antes de cualquier otra consecuencia. */
.mp360-plano__lote.is-sel {
    stroke: var(--mp360-primary);
    stroke-width: calc(2.2px / var(--k, 1));
    fill-opacity: 0.85;
}

.mp360-mapedit__cara {
    margin: 0 0 4px;
    font-variant-numeric: tabular-nums;
    opacity: 0.95;
    min-height: 1.2em;
    word-break: break-word;
}

/* --------------------------------------------------------------------------
   ROTULOS DE QA — manzana-lote sobre cada cara. Solo modo dev.

   Tamano CONSTANTE en pantalla: se divide por la escala para que el texto no
   crezca con el zoom. Asi el rotulo se lee igual de cerca que de lejos, y el
   umbral de aparicion lo decide el JS.
   -------------------------------------------------------------------------- */

.mp360-plano__rotulos {
    /* Los rotulos NUNCA le roban el click al poligono que describen. */
    pointer-events: none;
    font-family: var(--mp360-font);
    font-weight: var(--mp360-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.mp360-plano__rotulos text {
    font-size: calc(11px / var(--k, 1));
    fill: var(--mp360-primary);
    /* Halo: el rotulo tiene que leerse sobre cualquier banda comercial, desde
       el amarillo hasta el verde oscuro de vendido. */
    paint-order: stroke;
    stroke: rgba(255, 255, 255, 0.92);
    stroke-width: calc(2.6px / var(--k, 1));
    stroke-linejoin: round;
}

/* Confianza del mapping automatico. Alta se lee normal; el resto salta. */
.mp360-plano__rotulos text[data-conf="media"] { fill: #9A6100; }
.mp360-plano__rotulos text[data-conf="baja"]  { fill: #B3261E; }

/* Sin identificar: se marca, no se disimula. */
.mp360-plano__rotulos text[data-conf="sin"] {
    fill: rgba(10, 52, 37, 0.45);
    font-weight: var(--mp360-weight-regular);
}

.mp360-plano__ctrl.is-off { opacity: 0.5; }
