:root {
  --brand-canopy: #c8c07e;
  --brand-canopy-rgb: 200, 192, 126;
  --brand-ink: #071316;
  --brand-ink-rgb: 7, 19, 22;
  --brand-ink-soft: #0c1d21;
  --brand-ink-soft-rgb: 12, 29, 33;
  --brand-shadow-rgb: 3, 9, 11;
  --brand-sand: #ded7ba;
  --brand-sand-rgb: 222, 215, 186;
  /* Esta página NO carga base.css, así que las variables de la escala global
     hay que declararlas aquí o `height: var(--jt-screen-h)` de .mp-shell queda
     sin valor, el navegador descarta la declaración y el shell se queda sin
     altura: la página entera se descuadra. El Master Plan es una vista de
     pantalla completa con su propio scroll interno, así que no se le aplica
     zoom; el token existe para que .mp-shell resuelva a 100svh limpio. */
  --jt-zoom: 1;
  --jt-screen-h: calc(100svh / var(--jt-zoom));
  /* Mismos tokens que base.css — esta página no la carga (ver fonts.css). */
  --font-display: "Stara", Georgia, serif;
  --font-serif: var(--font-display);
  --font-body: "Manrope", system-ui, sans-serif;
  --font-sans: var(--font-body);
  --hero-text: var(--brand-sand);
  --hero-muted: rgba(var(--brand-sand-rgb), 0.72);
  --page-shadow: 0 24px 60px rgba(0, 0, 0, 0.22);
}

* { box-sizing: border-box; }

/* Scopeado a html.mp-page (solo master-plan.html): esta hoja también se
   carga en landing.html para heredar los estilos de la calculadora, y un
   selector "html, body" sin scope dejaba TODA la landing sin poder hacer
   scroll (overflow:hidden global). master-plan.html es un app-shell de una
   sola pantalla — landing.html no debe heredar ese comportamiento. */

html.mp-page,
html.mp-page body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: var(--brand-ink);
  color: var(--brand-sand);
  font-family: var(--font-body);
}

.mp-shell {
  position: relative;
  height: var(--jt-screen-h);
  display: flex;
  flex-direction: column;
  /* 600ms era largo de más: como el fondo ya está pintado por el estilo
     crítico del head, un fundido corto basta y la entrada deja de leerse
     como un parpadeo. */
  animation: mpFadeIn 260ms ease both;
}

@keyframes mpFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* ── Header ── */

/* master-plan.html no carga base.css, así que aquí no llega su reset y los
   enlaces salían con el subrayado por defecto del navegador — incluidos el
   logo y los tres botones de la barra. */

a {
  color: inherit;
  text-decoration: none;
}

.mp-header {
  position: relative;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1rem 1.5rem;
  background: rgba(7, 19, 22, 0.92);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-bottom: 1px solid rgba(var(--brand-canopy-rgb), 0.16);
  flex-wrap: wrap;
}

.mp-brand {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.mp-brand img {
  width: 2.6rem;
  height: auto;
}

/* Igual que en index.html: se cambia el archivo del logo según el tema, en vez
   de intentar corregir el blanco con mix-blend-mode (que lo dejaba casi
   invisible sobre la barra oscura). */

.logo-light-theme { display: none; }

.logo-dark-theme  { display: inline-block; }

html[data-theme="light"] .logo-light-theme { display: inline-block; }

html[data-theme="light"] .logo-dark-theme  { display: none; }

.mp-brand-text {
  display: flex;
  flex-direction: column;
  font-family: var(--font-serif);
  text-transform: uppercase;
  line-height: 1;
}

.mp-brand-text strong {
  font-size: 1.15rem;
  font-weight: 500;
  color: var(--brand-sand);
}

.mp-brand-text small {
  font-size: 0.62rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--brand-canopy);
}

/* Sello "By TAO" — réplica del de la barra de index.html. */

.mp-brand-tao {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-right: auto;
  padding-left: 0.9rem;
  border-left: 1px solid rgba(var(--brand-sand-rgb), 0.18);
  opacity: 0.9;
  transition: opacity 200ms ease;
}

.mp-brand-tao:hover { opacity: 1; }

.mp-brand-tao-by {
  font-size: 0.55rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(var(--brand-sand-rgb), 0.5);
}

.mp-brand-tao img {
  width: 3.6rem;
  height: auto;
}

.mp-poi-filter {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.mp-poi-pill {
  padding: 0.45rem 0.95rem;
  border-radius: 999px;
  border: 1px solid rgba(var(--brand-sand-rgb), 0.18);
  background: rgba(var(--brand-ink-soft-rgb), 0.6);
  color: rgba(var(--brand-sand-rgb), 0.75);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  cursor: pointer;
  transition: background-color 200ms ease, border-color 200ms ease, color 200ms ease;
}

.mp-poi-pill.is-active,
.mp-poi-pill:hover {
  background: var(--brand-canopy);
  border-color: var(--brand-canopy);
  color: var(--brand-ink);
}

.mp-header-actions {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.mp-header-links {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

/* ── Botones de la barra ──────────────────────────────────────────────────────
   Una sola base para los tres (descargar plano · cómo llegar · aparta tu lote)
   con dos variantes: --ghost para los secundarios y --accent para la acción
   principal. Antes solo existía .mp-directions-btn con el estilo de acento, así
   que cualquier botón nuevo competía visualmente con él. */

.mp-header-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 1.1rem;
  border-radius: 999px;
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  border: 1px solid transparent;
  transition: transform 200ms ease, box-shadow 200ms ease,
              background-color 200ms ease, border-color 200ms ease, color 200ms ease;
}

.mp-header-btn i {
  font-size: 0.9em;
}

.mp-header-btn--accent {
  background: linear-gradient(135deg, rgba(var(--brand-canopy-rgb), 0.98), rgba(181, 151, 112, 0.92));
  color: var(--brand-ink);
}

.mp-header-btn--ghost {
  background: rgba(var(--brand-sand-rgb), 0.06);
  border-color: rgba(var(--brand-sand-rgb), 0.20);
  color: rgba(var(--brand-sand-rgb), 0.88);
}

.mp-header-btn--ghost:hover {
  background: rgba(var(--brand-canopy-rgb), 0.18);
  border-color: rgba(var(--brand-canopy-rgb), 0.45);
  color: var(--brand-sand);
}

.mp-header-btn--accent:hover {
  transform: translateY(-1px);
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.3);
}

/* Separador entre las acciones y los controles de tema/idioma. */

.mp-header-toggles {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding-left: 0.75rem;
  margin-left: 0.25rem;
  border-left: 1px solid rgba(var(--brand-sand-rgb), 0.18);
}

.mp-close-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 50%;
  border: 1px solid rgba(var(--brand-sand-rgb), 0.2);
  color: var(--brand-sand);
  font-size: 1rem;
  transition: background-color 200ms ease, transform 220ms cubic-bezier(0.34, 1.6, 0.64, 1);
}

.mp-close-btn:hover {
  background: rgba(var(--brand-canopy-rgb), 0.18);
  transform: rotate(90deg);
}

/* ── Mapa ── */

.mp-main {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
}

#mp-map {
  position: absolute;
  inset: 0;
  /* El lienzo del mapa nace transparente y dejaba ver el fondo oscuro del
     shell hasta que pintaba el primer tile: negro → mapa claro, un destello.
     Este tono es el del propio estilo del mapa, así que la transición ya no
     se nota. */
  background: #eae6de;
}

/* El mapa se destapa ya encuadrado sobre la reserva en venta (lo hace
   master-plan.js al quedarse quieto). Así no se ve el salto entre el centro
   con el que nace el mapa y el encuadre real, que se leía como un parpadeo. */
#mp-map .maplibregl-canvas-container,
#mp-map .maplibregl-control-container {
  opacity: 0;
  transition: opacity .5s ease;
}
#mp-map.is-listo .maplibregl-canvas-container,
#mp-map.is-listo .maplibregl-control-container {
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  #mp-map .maplibregl-canvas-container,
  #mp-map .maplibregl-control-container { transition: none; }
}

.mp-hint {
  position: absolute;
  top: 1.25rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  /* En pantallas de 320px la píldora medía más que el viewport y dejaba la
     página con 10px de scroll horizontal. */
  max-width: calc(100% - 1.5rem);
  padding: 0.7rem 1.25rem;
  border-radius: 999px;
  background: rgba(7, 19, 22, 0.82);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(var(--brand-canopy-rgb), 0.3);
  color: var(--brand-canopy);
  font-size: 0.78rem;
  font-weight: 500;
  white-space: nowrap;
  animation: mpHintPulse 3s ease-in-out infinite;
  pointer-events: none;
}

@keyframes mpHintPulse {
  0%, 100% { opacity: 0.85; transform: translateX(-50%) translateY(0); }
  50%      { opacity: 1;    transform: translateX(-50%) translateY(-3px); }
}

/* Al cotizar el primer lote la instrucción ya cumplió: hay que apagar también
   la animación, porque un keyframe infinito le gana a la transición de
   opacidad y la píldora se quedaba en pantalla. */
.mp-hint.is-dismissed {
  opacity: 0;
  animation: none;
  transition: opacity 400ms ease;
  pointer-events: none;
}

/* Punto que acompaña a la instrucción: dibuja el gesto que hay que hacer
   (un toque sobre el plano) sin depender de un icono más de Font Awesome. */
.mp-hint-tap {
  position: relative;
  flex: 0 0 auto;
  width: 0.62rem;
  height: 0.62rem;
  border-radius: 50%;
  background: var(--brand-canopy);
}
.mp-hint-tap::after {
  content: '';
  position: absolute;
  inset: -0.35rem;
  border-radius: 50%;
  border: 1.5px solid var(--brand-canopy);
  animation: mpTapRing 1.9s ease-out infinite;
}

@keyframes mpTapRing {
  0%   { opacity: 0.9; transform: scale(0.55); }
  70%  { opacity: 0;   transform: scale(1.25); }
  100% { opacity: 0;   transform: scale(1.25); }
}

/* ── Fases de venta ──
   Cuatro tarjetas en el orden real de liberación. La que está en venta se
   distingue por color y punto vivo; las otras se leen sin invitar a hacer
   clic para cotizar, porque todavía no hay nada que cotizar en ellas. */

.mp-phases {
  position: relative;
  z-index: 4;
  display: grid;
  /* La barra llega vacía y solo se llena cuando responden los dos GeoJSON:
     sin altura reservada el mapa nacía más alto y daba un tirón hacia abajo
     al aparecer las cuatro reservas. Es la altura real de una fila. */
  min-height: 5rem;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.5rem;
  padding: 0.6rem 1.25rem 0.75rem;
  background: linear-gradient(to bottom, rgba(var(--brand-ink-rgb), 0.96), rgba(var(--brand-ink-rgb), 0.86));
  border-bottom: 1px solid rgba(var(--brand-sand-rgb), 0.08);
}

.mp-phase {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: 0.55rem 0.8rem;
  text-align: left;
  border-radius: 0.85rem;
  border: 1px solid rgba(var(--brand-sand-rgb), 0.12);
  background: rgba(var(--brand-ink-soft-rgb), 0.75);
  color: rgba(var(--brand-sand-rgb), 0.5);
  font-family: inherit;
  cursor: pointer;
  transition: border-color 200ms ease, background 200ms ease, color 200ms ease, transform 200ms ease;
}

.mp-phase:hover { transform: translateY(-1px); border-color: rgba(var(--brand-sand-rgb), 0.28); }
.mp-phase.is-active { border-color: rgba(var(--brand-canopy-rgb), 0.5); }

.mp-phase--live,
.mp-phase.is-live {
  color: rgba(var(--brand-sand-rgb), 0.92);
  border-color: rgba(var(--brand-canopy-rgb), 0.38);
  background: rgba(var(--brand-canopy-rgb), 0.09);
}

.mp-phase-name {
  font-family: var(--font-serif);
  font-size: 1.15rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  line-height: 1.15;
  color: inherit;
}

.mp-phase-state {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.66rem;
  letter-spacing: 0.04em;
  color: rgba(var(--brand-sand-rgb), 0.45);
}

.mp-phase.is-live .mp-phase-state { color: var(--brand-canopy); }

.mp-phase-dot {
  width: 0.42rem;
  height: 0.42rem;
  border-radius: 50%;
  background: #46c08b;
  box-shadow: 0 0 0 0 rgba(70, 192, 139, 0.6);
  animation: mpLiveDot 2.2s ease-out infinite;
}

@keyframes mpLiveDot {
  0%   { box-shadow: 0 0 0 0 rgba(70, 192, 139, 0.55); }
  70%  { box-shadow: 0 0 0 0.4rem rgba(70, 192, 139, 0); }
  100% { box-shadow: 0 0 0 0 rgba(70, 192, 139, 0); }
}

/* ── Resumen de la reserva en venta ── */

.mp-stats {
  position: absolute;
  top: 1.25rem;
  right: 1.25rem;
  z-index: 3;
  display: flex;
  gap: 1.4rem;
  padding: 0.8rem 1.2rem;
  border-radius: 1rem;
  background: rgba(7, 19, 22, 0.82);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(var(--brand-sand-rgb), 0.12);
}

.mp-stat { display: flex; flex-direction: column; gap: 0.1rem; }

.mp-stat-value {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--brand-canopy);
  white-space: nowrap;
}

.mp-stat-label {
  font-size: 0.6rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(var(--brand-sand-rgb), 0.5);
}

/* ── Leyenda ── */

.mp-legend {
  position: absolute;
  bottom: 1.25rem;
  left: 1.25rem;
  z-index: 3;
  max-width: calc(100% - 2.5rem);
  padding: 0.75rem 1.1rem;
  border-radius: 1rem;
  background: rgba(7, 19, 22, 0.82);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(var(--brand-sand-rgb), 0.12);
  font-size: 0.72rem;
}

.mp-legend-title {
  margin: 0 0 0.45rem;
  font-size: 0.6rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(var(--brand-sand-rgb), 0.5);
}

.mp-legend-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 0.9rem;
}

.mp-legend-row--sep {
  margin-top: 0.5rem;
  padding-top: 0.5rem;
  border-top: 1px solid rgba(var(--brand-sand-rgb), 0.1);
}

.mp-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: rgba(var(--brand-sand-rgb), 0.85);
}

.mp-legend-item i {
  display: inline-block;
  width: 0.7rem;
  height: 0.7rem;
  border-radius: 3px;
}

/* Marcador del acceso al proyecto sobre el plano. */
.mp-jt-marker {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--brand-canopy);
  border: 2px solid var(--brand-ink);
  box-shadow: 0 0 0 4px rgba(var(--brand-canopy-rgb), 0.3);
}

/* Globo de las reservas que aún no salen a la venta. */
.mp-popup-prox .maplibregl-popup-content {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.7rem 0.95rem;
  border-radius: 0.8rem;
  background: rgba(7, 19, 22, 0.94);
  border: 1px solid rgba(var(--brand-sand-rgb), 0.16);
  color: var(--brand-sand);
  font-family: var(--font-body);
  font-size: 0.78rem;
}
.mp-popup-prox .maplibregl-popup-content span {
  font-size: 0.7rem;
  color: rgba(var(--brand-sand-rgb), 0.6);
}
.mp-popup-prox .maplibregl-popup-tip { display: none; }

/* ── Panel de cotización ── */

.mp-panel {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 10;
  width: min(24rem, 92vw);
  background: linear-gradient(160deg, rgba(12, 29, 33, 0.98) 0%, rgba(7, 19, 22, 0.99) 100%);
  border-left: 1px solid rgba(var(--brand-canopy-rgb), 0.24);
  box-shadow: -30px 0 60px rgba(0, 0, 0, 0.4);
  transform: translateX(100%);
  transition: transform 460ms cubic-bezier(0.19, 1, 0.22, 1);
  overflow-y: auto;
}

.mp-panel.is-open {
  transform: translateX(0);
}

.mp-panel-inner {
  padding: 4.5rem 2rem 3rem;
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
}

/* Revelado escalonado del contenido — solo cuando el panel ya terminó de
   deslizarse (evita que el texto "llegue antes" que el propio panel). */

.mp-panel-inner > * {
  opacity: 0;
  transform: translateY(10px);
}

.mp-panel.is-open .mp-panel-inner > * {
  animation: mpPanelItemIn 480ms cubic-bezier(0.16, 1, 0.3, 1) both;
}

.mp-panel.is-open .mp-panel-inner > *:nth-child(1) { animation-delay: 80ms; }

.mp-panel.is-open .mp-panel-inner > *:nth-child(2) { animation-delay: 130ms; }

.mp-panel.is-open .mp-panel-inner > *:nth-child(3) { animation-delay: 180ms; }

.mp-panel.is-open .mp-panel-inner > *:nth-child(4) { animation-delay: 230ms; }

.mp-panel.is-open .mp-panel-inner > *:nth-child(5) { animation-delay: 280ms; }

.mp-panel.is-open .mp-panel-inner > *:nth-child(6) { animation-delay: 330ms; }

.mp-panel.is-open .mp-panel-inner > *:nth-child(7) { animation-delay: 380ms; }

/* La serie llegaba hasta el 7 y el panel ya tiene 10 elementos: los que se
   quedaban fuera entraban con delay 0, es decir antes que los de arriba. */
.mp-panel.is-open .mp-panel-inner > *:nth-child(8) { animation-delay: 430ms; }

.mp-panel.is-open .mp-panel-inner > *:nth-child(9) { animation-delay: 480ms; }

.mp-panel.is-open .mp-panel-inner > *:nth-child(10) { animation-delay: 530ms; }

.mp-panel.is-open .mp-panel-inner > *:nth-child(11) { animation-delay: 580ms; }

@keyframes mpPanelItemIn {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .mp-panel-inner > * { opacity: 1; transform: none; animation: none !important; }
}

.mp-panel-close {
  position: absolute;
  top: 1.15rem;
  right: 1.15rem;
  /* La franja de estado se anima con transform, y eso la pinta en la misma
     capa que los elementos posicionados: sin z-index propio el botón quedaba
     debajo de ella y no se podía cerrar el panel de un lote apartado. */
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 50%;
  /* Esta página no carga base.css, así que sin declararlo el botón se quedaba
     con el relleno gris que le pone el navegador: un disco opaco encima de la
     franja de color. Ahora se dibuja con el mismo tono que el texto de la
     franja sobre la que está, y deja ver el color de detrás. */
  background: transparent;
  border: 1px solid currentColor;
  color: var(--mp-estado-fg, var(--brand-sand));
  opacity: 0.55;
  cursor: pointer;
  font-size: 0.82rem;
  transition: opacity 200ms ease, background-color 200ms ease,
              transform 220ms cubic-bezier(0.34, 1.6, 0.64, 1);
}

.mp-panel-close:hover,
.mp-panel-close:focus-visible {
  opacity: 1;
  background: rgba(var(--brand-ink-rgb), 0.14);
  transform: rotate(90deg);
}

/* Franja de estado. Los márgenes negativos la sacan del padding del panel para
   que toque los tres bordes de arriba; el padding derecho de 4.5rem le deja
   sitio al botón de cerrar, que flota sobre ella. */
.mp-panel-estado {
  margin: -4.5rem -2rem 0;
  padding: 1.15rem 4.5rem 1.15rem 2rem;
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1.2;
}

.mp-panel-estado[hidden] { display: none; }

/* Cada uno con el color de texto que se lee contra su fondo, no con el que
   combina: oscuro sobre el naranja y el verde, claro sobre el vino. El tono va
   en una variable del panel y no sólo en la franja porque el botón de cerrar
   flota encima y tiene que teñirse igual. */
.mp-panel[data-estado="disponible"] { --mp-estado-fg: #05231a; }

.mp-panel[data-estado="apartado"]   { --mp-estado-fg: #1a1207; }

.mp-panel[data-estado="vendido"]    { --mp-estado-fg: #f8ebee; }

.mp-panel-estado--disponible {
  background: #1e9e5a;
  color: var(--mp-estado-fg);
}

.mp-panel-estado--apartado {
  background: #e8912d;
  color: var(--mp-estado-fg);
}

.mp-panel-estado--vendido {
  background: #8c1d2f;
  color: var(--mp-estado-fg);
}

.mp-panel-kicker {
  margin: 0;
  font-size: 0.68rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--brand-canopy);
  font-weight: 600;
}

.mp-panel-heading {
  margin: 0;
  font-family: var(--font-serif);
  text-transform: uppercase;
  line-height: 1;
  font-size: 1.9rem;
  font-weight: 400;
  color: var(--brand-sand);
}

.mp-panel-tipo {
  margin: 0;
  font-size: 0.82rem;
  color: rgba(var(--brand-sand-rgb), 0.72);
}

.mp-panel-calle {
  margin: -0.35rem 0 0;
  font-size: 0.74rem;
  letter-spacing: 0.04em;
  color: rgba(var(--brand-sand-rgb), 0.45);
}
.mp-panel-calle[hidden] { display: none; }

/* auto-fit con un mínimo: dos columnas cuando el panel es ancho, una sola
   cuando no cabe el precio completo. Sin media queries que adivinen el ancho
   del panel, que cambia con el viewport. */
.mp-panel-figures {
  display: grid;
  gap: 0.6rem;
  grid-template-columns: repeat(auto-fit, minmax(10.5rem, 1fr));
}

.mp-panel-figure {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 0.3rem;
  padding: 0.95rem 1.05rem;
  border-radius: 1rem;
  border: 1px solid rgba(var(--brand-sand-rgb), 0.1);
  background: rgba(var(--brand-ink-rgb), 0.5);
}

.mp-panel-figure--accent {
  border-color: rgba(var(--brand-canopy-rgb), 0.35);
  background: rgba(var(--brand-canopy-rgb), 0.08);
}

.mp-panel-figure-label {
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(var(--brand-sand-rgb), 0.6);
}

.mp-panel-figure-value {
  font-family: var(--font-body);
  /* Se encoge con el panel: "$15,005,000" a 2rem fijos desbordaba la caja en
     cuanto las dos cifras compartían fila. */
  font-size: clamp(1.4rem, 4.6vw, 1.85rem);
  line-height: 1.1;
  font-weight: 500;
  color: var(--brand-canopy);
  font-variant-numeric: tabular-nums;
}

/* ── Ficha del régimen de construcción ── */
.mp-panel-specs[hidden] { display: none; }

.mp-panel-specs {
  padding-top: 1.1rem;
  border-top: 1px solid rgba(var(--brand-sand-rgb), 0.12);
}

.mp-panel-specs-title {
  margin: 0 0 0.85rem;
  font-size: 0.66rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-weight: 600;
  color: rgba(var(--brand-sand-rgb), 0.5);
}

.mp-panel-specs-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.5rem;
  margin: 0;
}

.mp-panel-spec {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.65rem 0.75rem;
  border-radius: 0.7rem;
  background: rgba(var(--brand-ink-rgb), 0.42);
  border: 1px solid rgba(var(--brand-sand-rgb), 0.07);
  min-width: 0;
}

/* Un número impar de campos dejaba la última celda sola contra el borde
   izquierdo, con un hueco del mismo tamaño al lado. Que ocupe la fila entera:
   la rejilla se lee como una rejilla y no como una lista mal cortada. */
.mp-panel-spec:last-child:nth-child(odd) { grid-column: 1 / -1; }

.mp-panel-spec dt {
  font-size: 0.6rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: rgba(var(--brand-sand-rgb), 0.5);
  line-height: 1.35;
  /* Dos líneas siempre, aunque la etiqueta ocupe una. "Densidad" al lado de
     "Área común de uso exclusivo" dejaba las dos cifras de la fila a alturas
     distintas, y la rejilla se leía torcida. */
  min-height: 2.7em;
}

.mp-panel-spec dd {
  margin: 0;
  font-size: 0.98rem;
  font-weight: 500;
  color: var(--brand-sand);
  font-variant-numeric: tabular-nums;
}

.mp-panel-spec dd small {
  display: block;
  margin-top: 0.1rem;
  font-size: 0.58rem;
  letter-spacing: 0.08em;
  font-weight: 400;
  color: rgba(var(--brand-sand-rgb), 0.38);
}

.mp-panel-note {
  margin: 0;
  font-size: 0.74rem;
  line-height: 1.55;
  color: rgba(var(--brand-sand-rgb), 0.55);
}

.mp-panel-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.95rem 1.25rem;
  border-radius: 0.85rem;
  background: linear-gradient(135deg, rgba(var(--brand-canopy-rgb), 0.98), rgba(181, 151, 112, 0.92));
  color: var(--brand-ink);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-align: center;
  transition: transform 200ms ease, box-shadow 200ms ease;
}

.mp-panel-cta:hover {
  transform: translateY(-2px);
  box-shadow: 0 14px 30px rgba(0, 0, 0, 0.32);
}

.mp-panel-cta--ghost {
  background: transparent;
  border: 1px solid rgba(var(--brand-sand-rgb), 0.22);
  color: var(--brand-sand);
}

.mp-panel-cta--ghost:hover {
  background: rgba(var(--brand-sand-rgb), 0.06);
  box-shadow: none;
}

/* ── MapLibre popup override (hover en lote) ── */

.maplibregl-popup-content {
  background: rgba(7, 19, 22, 0.92);
  color: var(--brand-sand);
  border-radius: 0.75rem;
  font-family: var(--font-body);
  padding: 0.6rem 0.85rem;
  font-size: 0.78rem;
}

.maplibregl-ctrl-attrib {
  font-size: 0.65rem;
}

/* En pantallas medianas las cuatro fases ya no caben en una fila sin que el
   nombre de la reserva se parta: pasan a dos columnas. */
@media (max-width: 900px) {
  /* Dos filas: la altura reservada se duplica para que tampoco salte aquí. */
  .mp-phases { grid-template-columns: repeat(2, minmax(0, 1fr)); padding: 0.55rem 1rem 0.65rem; min-height: 9rem; }
  .mp-stats { gap: 1rem; padding: 0.65rem 0.9rem; }
  .mp-stat-value { font-size: 0.92rem; }
}

@media (max-width: 700px) {
  .mp-header { padding: 0.85rem 1rem; gap: 0.75rem; }
  .mp-brand-text strong { font-size: 1rem; }
  .mp-poi-filter { order: 3; width: 100%; justify-content: center; }
  .mp-legend { left: 0.75rem; bottom: 0.75rem; font-size: 0.66rem; padding: 0.6rem 0.85rem; }
  .mp-hint { font-size: 0.7rem; padding: 0.55rem 0.9rem; }
  /* En teléfono el resumen y la leyenda se apilan al pie, de borde a borde:
     flotando en esquinas opuestas se pisaban entre sí. */
  .mp-stats {
    top: auto;
    bottom: 2rem;
    left: 0.75rem;
    right: 0.75rem;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.6rem 0.9rem;
  }
  .mp-stat-value { font-size: 0.85rem; }
  .mp-stat-label { font-size: 0.53rem; letter-spacing: 0.1em; }

  .mp-legend {
    left: 0.75rem;
    right: 0.75rem;
    bottom: 5.7rem;
    max-width: none;
  }
  .mp-legend .mp-legend-row--sep { display: none; }

  /* En táctil el zoom se hace con los dedos: los botones solo taparían la
     leyenda. Queda la atribución, que es obligatoria, en la línea de abajo
     del todo para que no se cruce con el resumen ni con la leyenda. */
  .maplibregl-ctrl-bottom-right .maplibregl-ctrl-group { display: none; }
  .maplibregl-ctrl-bottom-right { bottom: -0.35rem; }
  .maplibregl-ctrl-attrib { font-size: 0.6rem; }
}

/* Teléfono angosto: las fases se vuelven una tira deslizable en vez de una
   rejilla que aplasta los nombres. */
@media (max-width: 520px) {
  .mp-phases {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding: 0.5rem 0.75rem 0.6rem;
  }
  .mp-phases::-webkit-scrollbar { display: none; }
  .mp-phase { flex: 0 0 10.5rem; scroll-snap-align: start; }
}

@media (prefers-reduced-motion: reduce) {
  .mp-shell { animation: none; }
  .mp-hint { animation: none; }
  .mp-panel { transition: none; }
}

/* ═══════════════════════════════════════════════════════════
   CALCULADORA / COTIZACIÓN — overlay a pantalla completa
   (misma calculadora que antes vivía en index.html#calculadora,
   ahora integrada aquí para que todo el flujo de cotización
   ocurra en una sola pestaña, sin ir y volver al index)
═══════════════════════════════════════════════════════════ */

.mp-calc-overlay {
  position: fixed;
  inset: 0;
  z-index: 900;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: linear-gradient(180deg, rgba(var(--brand-ink-soft-rgb), 0.97) 0%, rgba(var(--brand-shadow-rgb), 0.99) 100%);
  animation: mpCalcFadeIn 320ms ease both;
}

.mp-calc-overlay[hidden] { display: none; }

@keyframes mpCalcFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.mp-calc-close {
  position: fixed;
  top: max(1.25rem, env(safe-area-inset-top, 1.25rem));
  right: max(1.25rem, env(safe-area-inset-right, 1.25rem));
  z-index: 910;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.9rem;
  height: 2.9rem;
  border-radius: 50%;
  border: 1px solid rgba(var(--brand-sand-rgb), 0.22);
  background: rgba(7, 19, 22, 0.9);
  color: var(--brand-sand);
  font-size: 1rem;
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  transition: background-color 200ms ease, transform 220ms cubic-bezier(0.34, 1.6, 0.64, 1);
}

.mp-calc-close:hover {
  background: rgba(var(--brand-canopy-rgb), 0.2);
  transform: rotate(90deg);
}

.mp-calc-container {
  max-width: 920px;
  margin: 0 auto;
  padding: clamp(4rem, 8vw, 5.5rem) 1.5rem clamp(3rem, 6vw, 4rem);
}

.mp-calc-heading {
  text-align: center;
  margin-bottom: clamp(2rem, 4vw, 2.75rem);
}

.mp-calc-kicker {
  margin: 0 0 0.6rem;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--brand-canopy);
}

.mp-calc-title {
  margin: 0 0 0.75rem;
  font-family: var(--font-serif);
  text-transform: uppercase;
  line-height: 1;
  font-size: clamp(1.8rem, 4vw, 2.6rem);
  font-weight: 400;
  color: var(--brand-sand);
}

.mp-calc-copy {
  max-width: 40rem;
  margin: 0 auto;
  font-size: 0.95rem;
  line-height: 1.6;
  color: rgba(var(--brand-sand-rgb), 0.68);
}

.mp-calc-cta {
  width: 100%;
  margin-top: 0.75rem;
}

@keyframes cqSlideIn {
  from { transform: translateX(100%); opacity: 0; }
  to   { transform: translateX(0);    opacity: 1; }
}

@keyframes cqStrikeDraw1 {
  0%   { stroke-dashoffset: 340; opacity: 0; }
  6%   { opacity: 1; }
  92%  { stroke-dashoffset: -4; }
  100% { stroke-dashoffset: -4; opacity: 1; }
}

@keyframes cqStrikeDraw2 {
  0%   { stroke-dashoffset: 340; opacity: 0; }
  8%   { opacity: 0.88; }
  92%  { stroke-dashoffset: -4; }
  100% { stroke-dashoffset: -4; opacity: 0.88; }
}

@keyframes cqCashBannerIn {
  0%   { opacity: 0; transform: translateY(14px) scale(0.96); }
  55%  { opacity: 1; }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}

@keyframes cqCashStamp {
  0%   { opacity: 0; transform: rotate(-10deg) scale(0.4); }
  60%  { opacity: 1; transform: rotate(3deg) scale(1.08); }
  100% { opacity: 1; transform: rotate(-4deg) scale(1); }
}

@keyframes cqCashFadeUp {
  from { opacity: 0; transform: translateY(7px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes cqCashShine {
  from { background-position: 200% 0; }
  to   { background-position: -60% 0; }
}

@keyframes cqCashGlow {
  0%, 100% { text-shadow: 0 0 10px rgba(var(--brand-canopy-rgb), 0.32); }
  50%      { text-shadow: 0 0 26px rgba(var(--brand-canopy-rgb), 0.9), 0 0 10px rgba(255, 255, 255, 0.45); }
}

@keyframes cqSpin { to { transform: rotate(360deg); } }

/* ══════════════════════════════════════════════════════════════
   CONTROLES DE TEMA E IDIOMA EN LA BARRA
   ══════════════════════════════════════════════════════════════
   Copia de las reglas equivalentes de sections.css. No se pueden reutilizar
   directamente porque master-plan.html carga únicamente master-plan.css: si se
   omiten, los botones aparecen sin estilo. Se mantienen las mismas clases e
   ids para que theme.js e i18n.js los conecten sin código extra. */

.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border-radius: 50%;
  background: rgba(var(--brand-sand-rgb), 0.08);
  border: 1px solid rgba(var(--brand-sand-rgb), 0.16);
  color: rgba(var(--brand-sand-rgb), 0.78);
  font-size: 0.82rem;
  cursor: pointer;
  flex-shrink: 0;
  transition: background-color 240ms ease, border-color 240ms ease, color 240ms ease;
}

.theme-toggle:hover {
  background: rgba(var(--brand-canopy-rgb), 0.16);
  border-color: rgba(var(--brand-canopy-rgb), 0.42);
  color: var(--brand-canopy);
}

.lang-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
}

.lang-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border-radius: 50%;
  background: rgba(var(--brand-sand-rgb), 0.06);
  border: 1px solid transparent;
  font-family: var(--font-body);
  font-size: 0.62rem;
  font-weight: 700;
  color: rgba(var(--brand-sand-rgb), 0.68);
  line-height: 1;
  cursor: pointer;
  transition: border-color 220ms ease, background-color 220ms ease, color 220ms ease;
}

.lang-btn--active {
  border-color: rgba(var(--brand-canopy-rgb), 0.5);
  background: rgba(var(--brand-canopy-rgb), 0.1);
  color: var(--brand-canopy);
}

/* ══════════════════════════════════════════════════════════════
   BARRA EN TEMA CLARO
   ══════════════════════════════════════════════════════════════
   La barra tenía el fondo oscuro fijo (rgba(7,19,22,0.92)) en ambos temas, así
   que en claro quedaba una franja negra sobre un mapa claro. Ahora acompaña al
   tema, igual que el resto del sitio. */

html[data-theme="light"] .mp-header {
  background: rgba(252, 250, 245, 0.94);
  border-bottom-color: rgba(var(--brand-canopy-rgb), 0.22);
}

html[data-theme="light"] .mp-brand img {
  mix-blend-mode: normal;
  filter: none;
}

html[data-theme="light"] .mp-brand-text strong { color: #1a2b2e; }

html[data-theme="light"] .mp-brand-tao { border-left-color: rgba(26, 43, 46, 0.16); }

html[data-theme="light"] .mp-brand-tao-by { color: rgba(26, 43, 46, 0.5); }

html[data-theme="light"] .mp-header-btn--ghost {
  background: rgba(255, 255, 255, 0.9);
  border-color: rgba(var(--brand-canopy-rgb), 0.28);
  color: #1f4d43;
}

html[data-theme="light"] .mp-header-btn--ghost:hover {
  background: rgba(var(--brand-canopy-rgb), 0.14);
  color: #12211f;
}

html[data-theme="light"] .mp-header-btn--accent { color: #12211f; }

html[data-theme="light"] .mp-close-btn {
  border-color: rgba(26, 43, 46, 0.22);
  color: #1a2b2e;
}

html[data-theme="light"] .mp-header-toggles {
  border-left-color: rgba(26, 43, 46, 0.18);
}

html[data-theme="light"] .theme-toggle {
  background: rgba(255, 255, 255, 0.9);
  border-color: rgba(26, 43, 46, 0.18);
  color: #1a2b2e;
}

html[data-theme="light"] .lang-btn { color: rgba(26, 43, 46, 0.66); }

/* El sello "By TAO" es lo primero que sobra cuando falta ancho: la identidad
   ya la lleva el logo de Joy Tree que está a su lado. */

@media (max-width: 991.98px) {
  .mp-brand-tao { display: none; }
}

/* ── Barra en móvil: dos renglones deliberados, no un envoltorio accidental ──
   Antes la barra envolvía sola y salían tres renglones desiguales: la marca
   arriba, dos iconos sueltos y un botón ancho en medio, y los controles de
   tema/idioma abajo — 141px de alto sobre un mapa a pantalla completa.
   Ahora se declara el reparto: renglón 1 = marca + tema/idioma + cerrar,
   renglón 2 = los tres botones repartiéndose el ancho en partes iguales. */

@media (max-width: 1099.98px) {
  .mp-header {
    flex-wrap: wrap;
    align-items: center;
    row-gap: 0.7rem;
    column-gap: 0.5rem;
    padding: 0.75rem 1rem;
  }

  /* display:contents disuelve el contenedor para que marca, botones, toggles y
     cerrar sean todos hijos directos del flex de .mp-header y se puedan
     ordenar entre sí. */
  .mp-header-actions { display: contents; }

  .mp-brand           { order: 1; margin-right: auto; min-width: 0; }
  .mp-header-toggles  { order: 2; padding-left: 0.6rem; margin-left: 0; }
  .mp-close-btn       { order: 3; }

  .mp-header-links {
    order: 4;
    flex: 1 0 100%;
    /* Sin esto el min-size automático del flex item lo dejaba en el ancho
       mínimo de los tres botones (327px) y a 320px la barra se desbordaba. */
    min-width: 0;
    gap: 0.5rem;
  }

  /* Tres celdas iguales — el ancho lo reparte flex, no la longitud del texto. */
  .mp-header-links .mp-header-btn {
    flex: 1 1 0;
    min-width: 0;
    justify-content: center;
  }

  /* Con renglón propio ya caben las tres etiquetas: no hay que esconderlas. */
  .mp-header-btn--ghost span { display: inline; }
}

@media (max-width: 600px) {
  .mp-header-links .mp-header-btn {
    padding: 0.6rem 0.4rem;
    font-size: 0.6rem;
    letter-spacing: 0.03em;
    gap: 0.35rem;
  }
}

@media (max-width: 420px) {
  .mp-header-links .mp-header-btn { font-size: 0.55rem; padding: 0.55rem 0.3rem; }
  .mp-brand img { width: 2.2rem; }
  .mp-brand-text strong { font-size: 0.95rem; }
  .mp-close-btn { width: 2.2rem; height: 2.2rem; }
  .theme-toggle { width: 2rem; height: 2rem; }
  .lang-btn { width: 1.8rem; height: 1.8rem; }
}

/* A 320px la marca completa + tema/idioma + cerrar ya no caben en un renglón y
   la barra se iba a tres. El logo solo basta para identificar la página. */

@media (max-width: 359.98px) {
  .mp-brand-text { display: none; }
}
