/* ==========================================================================
   VEGAS DEL VERDE — styles/sections/ubicacion.css   ·  v4 «la banda satelital»
   Sección #ubicacion: mapa satelital "Google Earth", dirección, referencias,
   distancias, canales de atención (bloque con id="contacto") y formulario que
   abre WhatsApp. Prefijo propio: .ubi- · Depende de tokens.css y base.css.

   v2 · Esta hoja absorbe lo que antes vivía en styles/sections/contacto.css:
   esa hoja queda OBSOLETA y su <link> debe salir del <head>. Todo lo del
   antiguo bloque de contacto se renombró al prefijo .ubi- para que la sección
   sea autosuficiente y no dependa de una hoja que ya no se carga.

   Los overrides de Leaflet van scoped bajo #ubicacion a propósito: la hoja de
   Leaflet la inyecta js/mapa.js y podría quedar después de esta en el orden
   de cascada; la especificidad del id nos deja ganar sin usar !important.

   ==========================================================================
   v4 · POR QUÉ SE REHIZO LA COMPOSICIÓN

   El dueño dijo que el sitio «se sigue viendo muy genérico», y esta sección
   era el caso de libro: SEIS rectángulos con el mismo filete, el mismo relleno
   y el mismo fondo, apilados uno debajo de otro —dirección, referencias,
   distancias, tres canales y formulario—. Con todo en la misma caja no hay
   jerarquía: el visitante no sabe qué mirar primero y la página parece una
   plantilla rellenada. Cuatro decisiones:

   1 · EL MAPA VA A SANGRE Y PIERDE EL MARCO. v3 lo metía en un visor blanco
       con degradado, --radio-xl, --sombra-lg y dos escuadras decorativas. Era
       la única pieza del sitio con sombra grande y radio grande, y el marco
       pesaba más que la foto satelital: exactamente lo contrario de «la foto
       satelital manda» (CONTRATO-V2 §5.3). Ahora la vista cruza la pantalla de
       lado a lado, sin marco, sin sombra y a esquina viva, sujeta arriba y
       abajo por un filete. Es el mismo recurso que .viv-friso en #vivero: el
       único bloque que se sale del contenedor.
       Lo que SÍ se conserva del visor: la viñeta interior y el filete claro de
       dentro (dan profundidad sin ensuciar la imagen) y toda la geometría del
       PIN, que está medida para que el vértice de la punta caiga sobre
       7.0574425, -73.1144128. Del pin no se toca nada.

   2 · LA DIRECCIÓN SALE DE SU TARJETA Y SUBE A LA PORTADA. Es el dato que
       viene a buscar quien llega hasta aquí; no puede ir en una caja idéntica
       a la de las distancias. Ahora comparte primera línea con el titular, en
       dos columnas desiguales, colgada de un filete oliva.

   3 · REFERENCIAS Y DISTANCIAS DEJAN DE SER RECUADROS. Pasan al patrón
       .ubi-bloque: un filete horizontal de apertura, el encabezado en una
       columna estrecha y el contenido en la ancha. Es el gesto editorial que
       usa el resto del sitio y rompe la pila de cajas.

   4 · EL ÚNICO RECUADRO QUE QUEDA ES EL FORMULARIO. Y se queda a propósito:
       es lo único de la sección que es de verdad un objeto —una cosa que se
       rellena—, así que es lo único que merece un papel debajo. Los canales
       pasan a filas con regla, con el de WhatsApp como la única fila con
       cuerpo, porque es el canal real del negocio.

   Se conservan redondas, con el mismo criterio que .pildora en base.css («las
   esquinas vivas mandan en foto, tarjeta y botón; en los chips, no»): la
   píldora de referencia .ubi-ref, el disco de icono .ubi-canal__icono, la
   pastilla de activación táctil, la viñeta de error y el disco del pin.

   CONTRASTE — los pares que cambiaron de fondo al quitar las tarjetas.
   Sobre salvia (#dde5cd, luminancia 0,758), que es el fondo de .seccion--alt:
     tinta (--color-texto) ...................................... 11,9:1
     gris de rótulo (--color-texto-suave) ....................... 5,2:1
     terracota (--color-acento-texto) ........................... 4,6:1
   Los campos del formulario siguen midiéndose contra el papel del panel
   (--color-superficie-solida), que no ha cambiado: su filete oliva sigue
   dando 5,3:1 y el bosque del foco 11,4:1.
   ========================================================================== */

.ubi {
  /* --- Tokens locales de la sección (valores que la fundación no cubre) ---- */
  /* La banda satelital crece: a sangre, un visor bajito parece una tira de
     imagen; a esta altura parece una ventana. */
  --ubi-alto-mapa: clamp(23rem, 62svh, 40rem);
  --ubi-control: 2.75rem;                       /* objetivo táctil de los +/- */
  --ubi-dur-pulso: calc(var(--dur-reveal) * 3); /* 2,7 s derivados del token  */
  --ubi-alto-control: 3rem;                     /* objetivo táctil del campo  */
  --ubi-icono: 2.75rem;

  /* El margen del .contenedor, reproducido con un porcentaje del ancho del
     bloque a sangre. Mismo recurso —y mismo motivo— que --viv-margen en
     vivero.css: 100vw INCLUYE la barra de scroll y metería un desbordamiento
     real que el overflow-x del body taparía sin arreglar. Lo usa el HUD para
     alinearse con la columna de texto en vez de con el canto de la pantalla.
     OJO: #ubicacion usa .contenedor--ancho, así que va contra --ancho-xl. */
  --ubi-margen: max(
    var(--padding-contenedor),
    calc((100% - var(--ancho-xl)) / 2)
  );
}

/* ==========================================================================
   1. PORTADA — el titular y la dirección, en la misma línea
   ========================================================================== */
.ubi-portada {
  display: grid;
  gap: var(--gap);
}

/* Dos columnas desiguales y alineadas por ABAJO: el titular manda en tamaño,
   la dirección manda en urgencia, y las dos apoyan en la misma línea de suelo.
   Es lo que convierte el arranque en una portada y no en un encabezado más. */
@media (min-width: 62em) {
  .ubi-portada {
    grid-template-columns: minmax(0, 1.25fr) minmax(0, 0.75fr);
    gap: var(--gap-lg);
    align-items: end;
  }
}

/* El encabezado ya no se centra: con la placa al lado, centrarlo dejaba la
   composición coja. Y suelta su margen inferior, que ahora lo pone la rejilla. */
.ubi-portada__texto {
  margin-bottom: 0;
}

/* La placa cuelga de un filete OLIVA —el contorno fuerte del sistema, 3:1 sobre
   salvia— y no de uno suave: es la única regla de la sección que tiene que
   verse a distancia. */
.ubi-placa {
  display: flex;
  flex-direction: column;
  gap: var(--esp-2xs);
  padding-top: var(--esp-md);
  border-top: 1px solid var(--color-borde-fuerte);
}

.ubi-direccion {
  font-style: normal;
  font-size: var(--fs-grande);
  font-weight: var(--peso-ligero);
  line-height: var(--alto-linea-base);
  color: var(--color-texto);
}

.ubi-coordenadas {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--esp-2xs);
  margin: 0;
  font-variant-numeric: tabular-nums;
}

.ubi-coordenadas__etiqueta {
  font-family: var(--fuente-titulo);
  font-size: var(--fs-micro);
  text-transform: uppercase;
  letter-spacing: var(--tracking-rotulo);
  color: var(--color-texto-suave);
}

/* ==========================================================================
   2. LA BANDA DEL MAPA  (a sangre: hija directa del <section>)
   ========================================================================== */
.ubi-mapa {
  margin: var(--gap-lg) 0 0;
}

.ubi-mapa__medio {
  position: relative;
  /* fallback para navegadores sin unidades svh (Safari iOS ≤ 15) */
  height: clamp(23rem, 62vh, 40rem);
  height: var(--ubi-alto-mapa);
  /* Esquina viva y sin sombra, como toda la fotografía del sitio desde v3.
     Los dos filetes horizontales son lo único que sujeta la banda: sin ellos,
     sobre la salvia, el borde superior de la vista satelital flota. */
  border-radius: 0;
  border-block: 1px solid var(--color-borde-suave);
  overflow: hidden;
  background-color: var(--tinta);
  isolation: isolate;
}

/* Viñeta sutil: da profundidad de "visor" sin ensuciar la imagen satelital.  */
.ubi-mapa__medio::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: var(--z-elevado);
  pointer-events: none;
  box-shadow: inset 0 0 0 1px rgb(var(--crema-rgb) / 0.18);
  background: radial-gradient(
    120% 90% at 50% 45%,
    rgb(var(--tinta-rgb) / 0) 55%,
    rgb(var(--tinta-rgb) / 0.28) 100%
  );
}

.ubi-mapa__lienzo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* ==========================================================================
   3. RESPALDO (visible por defecto: sin JS, sin red o con el CDN caído)
   ========================================================================== */
.ubi-mapa__respaldo {
  position: absolute;
  inset: 0;
  z-index: var(--z-base);
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 62%;
}

/* Cuando el mapa interactivo está listo, el respaldo se retira del todo. */
.ubi-mapa--interactivo .ubi-mapa__respaldo {
  display: none;
}

/* El pie del mapa: la foto va a sangre, el texto vuelve al contenedor. La fila
   lleva las clases .contenedor .contenedor--ancho en el marcado, así que el
   ancho y el relleno lateral ya vienen de base.css; aquí sólo se reparte. */
.ubi-mapa__pie {
  margin-top: 0;
  font-size: var(--fs-micro);
  color: var(--color-texto-suave);
}

.ubi-mapa__pie-fila {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--esp-2xs) var(--esp-sm);
  margin-top: var(--esp-sm);
}

.ubi-mapa__leyenda {
  display: block;
  max-width: var(--medida);
}

/* Un [hidden] dentro de un contenedor flex sigue siendo `display:none` mientras
   nadie le dé un display propio. Se escribe explícito porque aquí js/mapa.js
   enciende y apaga tres mensajes distintos, y si el crédito de Esri se colara
   con el mapa apagado estaríamos atribuyéndole una foto que no es suya. */
.ubi-mapa__pie [hidden],
.ubi-mapa__credito[hidden] {
  display: none;
}

.ubi-mapa--interactivo .ubi-mapa__nota-respaldo {
  display: none;
}

.ubi-mapa__aviso {
  color: var(--color-acento-texto);
}

/* «Repetir vuelo» es un mando del mapa, no una ruta: vive pegado al mapa, al
   otro extremo de su propia leyenda. Los botones para llegar van debajo. */
.ubi-mapa__repetir {
  flex: none;
}

/* ==========================================================================
   4. CAPA HUD
   ========================================================================== */
/* Con el mapa a sangre el HUD no se pega al canto de la pantalla: se alinea con
   la columna de texto usando el mismo margen que el contenedor. */
.ubi-hud {
  position: absolute;
  z-index: calc(var(--z-elevado) + 1);
  top: var(--esp-sm);
  left: var(--ubi-margen);
  display: flex;
  flex-direction: column;
  gap: var(--esp-3xs);
  padding: var(--esp-2xs) var(--esp-sm);
  max-width: calc(100% - var(--esp-2xl));
  border: 1px solid rgb(var(--crema-rgb) / 0.22);
  /* La hoja: radio pleno en dos esquinas opuestas. Es el mismo gesto con el que
     base.css §2 dibuja las viñetas de .lista-hojas, y es el motivo orgánico de
     la casa; aquí firma la vista satelital sin recurrir a un logotipo grande. */
  border-radius: 0 var(--radio-lg) 0 var(--radio-lg);
  background-color: rgb(var(--tinta-rgb) / 0.55);
  backdrop-filter: var(--blur-vidrio);
  -webkit-backdrop-filter: var(--blur-vidrio);
  color: var(--color-texto-inverso);
  pointer-events: none;
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .ubi-hud {
    background-color: rgb(var(--tinta-rgb) / 0.82);
  }
}

.ubi-hud__marca {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-family: var(--fuente-titulo);
  font-size: var(--fs-pequeno);
  font-weight: var(--peso-medio);
  text-transform: uppercase;
  letter-spacing: var(--tracking-rotulo);
  line-height: 1.2;
}

/* PNG con transparencia: base.css le pone a todo <img> un fondo gris de carga
   y aquí dejaría un cuadrado sucio detrás del símbolo. */
.ubi-hud__simbolo {
  width: 1.5em;
  height: 1.5em;
  flex: none;
  background-color: transparent;
}

/* La coordenada NO se repite aquí: se escribe una sola vez, en la placa de la
   dirección. El HUD sólo identifica la marca y el tipo de vista.            */
.ubi-hud__etiqueta {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font-family: var(--fuente-titulo);
  font-size: var(--fs-micro);
  text-transform: uppercase;
  letter-spacing: var(--tracking-rotulo);
  color: var(--verde-menta);
}

.ubi-hud__etiqueta::before {
  content: "";
  width: 0.45em;
  height: 0.45em;
  border-radius: var(--radio-full);
  background-color: var(--verde-menta);
  flex: none;
}

/* ==========================================================================
   5. PIN PEQUEÑO (lo inyecta js/mapa.js dentro de un L.divIcon)

   NO SE TOCA. v1 metía el símbolo del logo a 48 px anclado por el centro:
   tapaba la vista satelital y señalaba mal. v2 lo reduce al disco de --tam-pin
   (36 px) con una punta de --tam-pin-punta, y js/mapa.js ancla el icono en el
   VÉRTICE de la punta, que es lo que cae sobre 7.0574425, -73.1144128.
   La caja del divIcon mide [--tam-pin] × [--tam-pin + --tam-pin-punta].
   Cualquier retoque de forma aquí se paga en la precisión del mapa.
   ========================================================================== */
.ubi-pin {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
}

.ubi-pin__disco {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: var(--tam-pin);
  display: grid;
  place-items: center;
  border-radius: var(--radio-full);
  border: var(--borde-pin) solid var(--verde-bosque);
  background-color: rgb(var(--crema-rgb) / 0.96);
  box-shadow: var(--sombra-pin);
}

/* El prefijo .leaflet-container no es decorativo: leaflet.css trae
   «.leaflet-container .leaflet-marker-pane img { width: auto }» con
   especificidad (0,2,1). Sin subir la nuestra a (0,2,1) gana Leaflet, el
   símbolo se pinta a su tamaño natural (512 px), el disco queda vacío y la
   hoja se derrama sobre la vista satelital.                               */
.leaflet-container .ubi-pin__disco img {
  width: 62%;
  height: auto;
  background: none;
}

/* Punta del pin: cuadrado girado 45°. El lado es la punta × √2 y se baja
   punta × √2/2, de modo que su vértice inferior queda EXACTAMENTE en el
   borde inferior de la caja del icono, que es donde ancla Leaflet.        */
.ubi-pin__disco::after {
  content: "";
  position: absolute;
  bottom: calc(var(--tam-pin-punta) * -0.7071);
  left: 50%;
  width: calc(var(--tam-pin-punta) * 1.4142);
  height: calc(var(--tam-pin-punta) * 1.4142);
  transform: translateX(-50%) rotate(45deg);
  border-right: var(--borde-pin) solid var(--verde-bosque);
  border-bottom: var(--borde-pin) solid var(--verde-bosque);
  background-color: rgb(var(--crema-rgb) / 0.96);
}

/* Latido muy contenido: llama la atención sin crecer hasta tapar el predio. */
.ubi-pin__halo {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: var(--tam-pin);
  border-radius: var(--radio-full);
  border: 1px solid var(--verde-menta);
  animation: ubi-pulso var(--ubi-dur-pulso) var(--ease-suave) infinite;
}

@keyframes ubi-pulso {
  0% {
    transform: scale(1);
    opacity: 0.6;
  }
  70% {
    transform: scale(1.7);
    opacity: 0;
  }
  100% {
    transform: scale(1.7);
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ubi-pin__halo {
    display: none;
  }
}

/* ==========================================================================
   6. BOTÓN DE ACTIVACIÓN TÁCTIL
   En pantallas táctiles el mapa arranca sin arrastre para no secuestrar el
   scroll de la página; este botón lo habilita. js/mapa.js lo muestra.
   ========================================================================== */
.ubi-mapa__activar {
  position: absolute;
  inset: 0;
  z-index: calc(var(--z-elevado) + 2);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding-bottom: var(--esp-xl);
  background-color: rgb(var(--tinta-rgb) / 0.12);
}

.ubi-mapa__activar[hidden] {
  display: none;
}

.ubi-mapa__activar-pastilla {
  padding: 0.65em 1.3em;
  border-radius: var(--radio-full);
  background-color: rgb(var(--crema-rgb) / 0.94);
  color: var(--tinta);
  font-family: var(--fuente-titulo);
  font-size: var(--fs-micro);
  font-weight: var(--peso-medio);
  text-transform: uppercase;
  letter-spacing: var(--tracking-rotulo);
  box-shadow: var(--sombra-md);
}

/* ==========================================================================
   7. OVERRIDES DE LEAFLET  (scoped por id, sin !important)
   ========================================================================== */
#ubicacion .leaflet-container {
  background-color: var(--tinta);
  font-family: var(--fuente-cuerpo);
  font-size: var(--fs-micro);
}

/* Los mandos se alinean con la columna de texto, igual que el HUD: con el mapa
   a sangre, pegarlos al canto de una pantalla de 2.560 px los deja fuera del
   alcance de la vista y del pulgar. */
#ubicacion .leaflet-bottom.leaflet-right {
  right: var(--ubi-margen);
}

#ubicacion .leaflet-control-zoom {
  border: 1px solid rgb(var(--verde-oliva-rgb) / 0.2);
  border-radius: 0;
  overflow: hidden;
}

#ubicacion .leaflet-control-zoom a {
  width: var(--ubi-control);
  height: var(--ubi-control);
  line-height: var(--ubi-control);
  border-bottom-color: rgb(var(--verde-oliva-rgb) / 0.16);
  background-color: rgb(var(--crema-rgb) / 0.94);
  color: var(--color-texto);
  font-family: var(--fuente-cuerpo);
  font-weight: var(--peso-normal);
}

#ubicacion .leaflet-control-zoom a:hover {
  background-color: var(--crema);
  color: var(--color-acento-texto);
}

#ubicacion .leaflet-control-attribution {
  padding: 0.25em 0.7em;
  background-color: rgb(var(--tinta-rgb) / 0.66);
  color: var(--color-texto-inverso-suave);
  font-size: var(--fs-micro);
}

#ubicacion .leaflet-control-attribution a {
  color: var(--verde-menta);
}

#ubicacion .leaflet-popup-content-wrapper,
#ubicacion .leaflet-popup-tip {
  background-color: var(--color-superficie-solida);
  color: var(--color-texto);
  box-shadow: var(--sombra-lg);
}

#ubicacion .leaflet-popup-content-wrapper {
  border-radius: 0;
}

#ubicacion .leaflet-popup-content {
  margin: var(--esp-sm) var(--esp-md);
  font-size: var(--fs-pequeno);
  line-height: var(--alto-linea-base);
}

#ubicacion .ubi-popup__titulo {
  display: block;
  font-family: var(--fuente-titulo);
  font-size: var(--fs-cuerpo);
  text-transform: uppercase;
  letter-spacing: var(--tracking-rotulo);
  color: var(--color-acento-texto);
}

#ubicacion .leaflet-container a.leaflet-popup-close-button {
  width: var(--esp-lg);
  height: var(--esp-lg);
  color: var(--color-texto-suave);
}

/* ==========================================================================
   8. CÓMO LLEGAR — los dos botones, pegados al mapa (lo pide el BRIEF)
   ========================================================================== */
/* A la izquierda y no centrados: la sección entera se lee alineada al margen
   izquierdo, y un par de botones centrados en medio de una columna alineada es
   el tic de plantilla que veníamos a quitar. */
.ubi-acciones {
  display: flex;
  flex-wrap: wrap;
  gap: var(--esp-sm);
  align-items: center;
  margin-top: var(--esp-lg);
}

/* ==========================================================================
   9. EL PATRÓN DE BLOQUE — referencias y distancias
   Filete de apertura, encabezado en la columna estrecha, contenido en la
   ancha. Sustituye a los dos recuadros de v3.
   ========================================================================== */
.ubi-bloque {
  display: grid;
  gap: var(--gap);
  margin-top: var(--esp-seccion-sm);
  padding-top: var(--esp-lg);
  border-top: 1px solid var(--color-borde-suave);
}

.ubi-bloque__encabezado {
  display: flex;
  flex-direction: column;
  gap: var(--esp-xs);
  min-width: 0;
}

@media (min-width: 62em) {
  .ubi-bloque {
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    gap: var(--gap-lg);
    align-items: start;
  }
}

/* --- Referencias ---------------------------------------------------------- */
.ubi-refs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--esp-2xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* El radio pleno se queda: .ubi-ref es un chip, y los chips conservan la forma
   por el mismo motivo que .pildora en base.css. */
.ubi-ref {
  padding: 0.45em 0.95em;
  border: 1px solid var(--color-borde-suave);
  border-radius: var(--radio-full);
  background-color: rgb(var(--blanco-rgb) / 0.55);
  font-size: var(--fs-pequeno);
  line-height: 1.35;
  color: var(--color-texto);
}

/* La foto trae los mismos sitios señalados sobre el terreno: es la prueba de
   la lista de al lado, no un adorno. Va sin recorte para no perder ningún pin. */
.ubi-refs__figura {
  margin: 0;
  min-width: 0;
}

/* LA HOJA — norma del sitio, arbitrada por el director de arte: la foto que
   vive DENTRO de la maqueta lleva dos esquinas curvas en diagonal y dos vivas.
   Ésta es la única foto de la sección que está dentro (el mapa sangra y se
   queda a esquina viva, que es lo que manda cuando la imagen toca el canto de
   la ventana).

   LA DIAGONAL NO ES LIBRE, LA ELIGE LA FOTO. Abierta con Read: el archivo
   tiene la barra amarilla de marca pegada a la esquina de arriba a la
   izquierda y los distintivos de Google Maps y Waze pegados a la de abajo a la
   derecha. Curvar esa diagonal recortaría las dos. Va la contraria —arriba a
   la derecha es cielo, abajo a la izquierda es arbolado— y no se pierde nada.

   El filete se queda: la imagen lleva rótulos sobre fondo claro y sin él se
   derrama sobre la salvia de la sección. Y sigue el <img> entero, sin recorte,
   para no perder ningún pin. */
.ubi-refs__foto {
  width: 100%;
  height: auto;
  border-radius: 0 var(--radio-xl) 0 var(--radio-xl);
  border: 1px solid var(--color-borde-suave);
}

/* ==========================================================================
   10. DISTANCIAS
   ========================================================================== */
/* El encabezado ocupa menos que en el bloque de referencias: son dos líneas de
   texto contra siete filas de datos, y la tabla necesita todo el ancho que
   pueda para que las barras cortas (10 km) sigan siendo legibles. */
@media (min-width: 62em) {
  .ubi-dist {
    grid-template-columns: minmax(0, 0.6fr) minmax(0, 1.4fr);
  }
}

.ubi-dist__lista {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  list-style: none;
  min-width: 0;
  border-top: 1px solid var(--color-borde-suave);
}

.ubi-dist__item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: var(--esp-3xs) var(--esp-sm);
  padding-block: var(--esp-xs);
  border-bottom: 1px solid var(--color-borde-suave);
}

.ubi-dist__lugar {
  font-family: var(--fuente-titulo);
  font-size: var(--fs-pequeno);
  letter-spacing: var(--track-titulo);
  color: var(--color-texto);
}

.ubi-dist__km {
  font-size: var(--fs-pequeno);
  font-variant-numeric: tabular-nums;
  color: var(--color-texto-suave);
  white-space: nowrap;
}

.ubi-dist__barra {
  grid-column: 1 / -1;
  grid-row: 2;
  display: block;
  height: var(--esp-3xs);
  /* v3: la barra de distancia es un instrumento de medida, no una pastilla.
     A 4 px de alto el radio pleno se comía los dos extremos del dato. */
  border-radius: 0;
  background-color: rgb(var(--verde-oliva-rgb) / 0.12);
  overflow: hidden;
}

.ubi-dist__relleno {
  display: block;
  width: var(--ubi-pct, 0%);
  min-width: var(--esp-lg);
  height: 100%;
  border-radius: inherit;
  background-image: linear-gradient(90deg, var(--verde-menta), var(--verde-oliva));
  transform-origin: left center;
  transform: scaleX(0);
  transition: transform var(--dur-lenta) var(--ease-salida);
  transition-delay: var(--reveal-delay, 0ms);
}

/* Las barras crecen cuando el bloque entra en pantalla (clase .visible del
   observador global). Sin JS quedan dibujadas desde el principio. */
.ubi-dist.visible .ubi-dist__relleno,
html:not(.js) .ubi-dist__relleno {
  transform: scaleX(1);
}

@media (min-width: 40em) {
  .ubi-dist__item {
    grid-template-columns: minmax(8rem, 13rem) minmax(0, 1fr) auto;
    align-items: center;
  }

  .ubi-dist__barra {
    grid-column: 2;
    grid-row: 1;
  }
}

/* ==========================================================================
   11. CANALES Y FORMULARIO  (antes sección #contacto, ahora el cierre de ésta)
   El bloque de canales conserva id="contacto": es el destino del menú y de los
   enlaces externos que ya circulan.
   ========================================================================== */
.ubi-hablar {
  display: grid;
  gap: var(--gap-lg);
  align-items: start;
  margin-top: var(--esp-seccion-sm);
  padding-top: var(--esp-seccion-sm);
  border-top: 1px solid var(--color-borde-suave);
}

@media (min-width: 64em) {
  .ubi-hablar {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  }
}

/* --- Canales -------------------------------------------------------------- */
/* v4: dejan de ser cuatro tarjetas iguales y pasan a ser una lista con regla.
   El hueco de 8 px entre filas no es estético: son objetivos táctiles vecinos
   y el contrato pide separarlos (WCAG 2.5.8). El relleno lateral entra para
   que el resalte del hover tenga cuerpo; el titular lleva el mismo, así que
   todo el bloque sigue alineado por dentro. */
.ubi-canales {
  display: flex;
  flex-direction: column;
  gap: var(--esp-2xs);
  scroll-margin-top: calc(var(--alto-header) + var(--esp-md));
}

.ubi-canales > .titulo-seccion {
  padding-inline: var(--esp-sm);
  margin-bottom: var(--esp-2xs);
}

.ubi-canal {
  display: flex;
  align-items: flex-start;
  gap: var(--esp-sm);
  padding: var(--esp-md) var(--esp-sm);
  border: 0;
  border-top: 1px solid var(--color-borde-suave);
  border-radius: 0;
  background-color: transparent;
  color: var(--color-texto);
  text-decoration: none;
  transition:
    border-color var(--transicion),
    background-color var(--transicion);
}

/* Lo que responde al puntero es el filete y el papel, no un salto: en este
   sistema nada flota. */
a.ubi-canal:hover,
a.ubi-canal:focus-visible {
  color: var(--color-texto);
  border-top-color: var(--color-borde-fuerte);
  background-color: rgb(var(--blanco-rgb) / 0.5);
}

/* La única fila con cuerpo, porque es el canal real del negocio: por aquí se
   confirma la disponibilidad y por aquí entran las reservas. */
.ubi-canal--destacado {
  border: 1px solid rgb(var(--verde-menta-rgb) / 0.55);
  background-color: rgb(var(--verde-menta-rgb) / 0.18);
}

/* Aquí el hover NO oscurece el fondo, cierra el filete. Subir la veladura de
   menta al 28 % dejaba el pie de la fila (--color-texto-suave) en 4,51:1, o
   sea rozando el mínimo de AA por el lado malo; el filete a verde bosque da la
   misma respuesta visual y no toca ningún contraste de texto. */
a.ubi-canal--destacado:hover,
a.ubi-canal--destacado:focus-visible {
  border-color: var(--verde-bosque);
  background-color: rgb(var(--verde-menta-rgb) / 0.18);
}

.ubi-canal__icono {
  display: grid;
  place-items: center;
  width: var(--ubi-icono);
  height: var(--ubi-icono);
  flex: none;
  border-radius: var(--radio-full);
  background-color: rgb(var(--verde-oliva-rgb) / 0.14);
  color: var(--color-acento-texto);
}

.ubi-canal__icono svg {
  width: 1.35em;
  height: 1.35em;
}

.ubi-canal--destacado .ubi-canal__icono {
  background-color: var(--verde-menta);
  color: var(--tinta);
}

/* El horario es la única fila que NO se pulsa: es un <div>, no un enlace. Su
   disco baja al gris de rótulo para que nadie lo intente. En una lista de
   cuatro filas idénticas, tres pulsables y una no, el color del icono es lo
   único que lo dice sin escribirlo. */
.ubi-canal--estatico .ubi-canal__icono {
  background-color: rgb(var(--verde-oliva-rgb) / 0.08);
  color: var(--color-texto-suave);
}

.ubi-canal__cuerpo {
  display: flex;
  flex-direction: column;
  gap: var(--esp-3xs);
  min-width: 0;
}

.ubi-canal__etiqueta {
  font-family: var(--fuente-titulo);
  font-size: var(--fs-micro);
  font-weight: var(--peso-medio);
  text-transform: uppercase;
  letter-spacing: var(--tracking-rotulo);
  color: var(--color-texto-suave);
}

.ubi-canal__valor {
  font-size: var(--fs-grande);
  font-weight: var(--peso-ligero);
  line-height: var(--alto-linea-titulo);
  overflow-wrap: anywhere;
}

.ubi-canal__pie {
  font-size: var(--fs-pequeno);
  color: var(--color-texto-suave);
}

/* --- Formulario ----------------------------------------------------------- */
/* EL ÚNICO RECUADRO QUE QUEDA EN LA SECCIÓN, y se queda a propósito: es lo
   único que es de verdad un objeto —una cosa que se rellena—, así que es lo
   único que merece un papel debajo. Al ser el único, además, se lee como el
   final del recorrido sin necesidad de ningún adorno. */
.ubi-form {
  display: flex;
  flex-direction: column;
  gap: var(--esp-sm);
  padding: var(--esp-lg);
  border: 1px solid var(--color-borde-fuerte);
  border-radius: 0;
  background-color: var(--color-superficie-solida);
}

.ubi-form__intro {
  max-width: var(--medida);
  margin: 0;
}

.ubi-campos {
  display: grid;
  gap: var(--esp-md);
  margin-top: var(--esp-2xs);
}

@media (min-width: 34em) {
  .ubi-campos {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .ubi-campo--ancho {
    grid-column: 1 / -1;
  }
}

/* El campo es un <p>: hay que neutralizar las reglas de párrafo de base.css */
.ubi-campo {
  display: flex;
  flex-direction: column;
  gap: var(--esp-3xs);
  max-width: none;
  margin: 0;
}

.ubi-campo + .ubi-campo {
  margin-top: 0;
}

/* ETIQUETA VISIBLE SIEMPRE. Nunca un placeholder haciendo de etiqueta: en
   cuanto el usuario escribe, un placeholder-etiqueta desaparece y deja el
   campo sin nombre. */
.ubi-campo__etiqueta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5em;
  font-family: var(--fuente-titulo);
  font-size: var(--fs-pequeno);
  font-weight: var(--peso-medio);
  letter-spacing: var(--track-titulo);
  color: var(--color-texto);
}

.ubi-campo__marca,
.ubi-campo__opcional {
  font-family: var(--fuente-titulo);
  font-size: var(--fs-micro);
  font-weight: var(--peso-normal);
  text-transform: uppercase;
  letter-spacing: var(--tracking-rotulo);
}

/* El coral se queda, a propósito, con el mismo criterio que .ubi-ref con el
   radio: la migración de v3 pasó los RÓTULOS a gris, y «obligatorio» no es un
   rótulo decorativo sino la marca semántica de un campo requerido. El color es
   parte de lo que informa, y va a juego con el mensaje de error del
   formulario. .ubi-campo__opcional, que sí es un rótulo, va en gris. */
.ubi-campo__marca {
  color: var(--color-acento-texto);
}

.ubi-campo__opcional {
  color: var(--color-texto-suave);
}

.ubi-campo__control {
  width: 100%;
  min-height: var(--ubi-alto-control);
  padding: 0.7em 0.85em;
  /* CONTORNO DE CONTROL, no filete decorativo. WCAG 1.4.11 pide 3:1 para el
     borde que identifica un campo. Sobre el papel del panel (.ubi-form, que
     es quien pinta --color-superficie-solida) el filete decorativo
     --color-borde daba 1,66:1 y el relleno blanco 1,04:1: el hueco donde hay
     que escribir no se veía. --color-borde-fuerte (oliva) da 5,33:1 contra el
     papel y 5,57:1 contra el propio relleno. */
  border: 1px solid var(--color-borde-fuerte);
  /* Esquina viva, igual que el .btn al que acompañan: quien delimita el campo
     es el filete, no la forma. */
  border-radius: 0;
  /* Blanco puro de marca: la fundación no tiene un rol semántico para "campo
     de formulario". Solo separa el hueco del papel; no es lo que lo delimita. */
  background-color: var(--blanco);
  color: var(--color-texto);
  font-family: var(--fuente-cuerpo);
  font-size: var(--fs-cuerpo);
  line-height: var(--alto-linea-base);
  transition:
    border-color var(--transicion-rapida),
    box-shadow var(--transicion-rapida);
}

/* El reposo ya es el filete fuerte, así que hover y foco solo pueden ir a
   MÁS: bosque (11,4:1 contra el papel), el mismo verde con el que base.css
   dibuja el aro de :focus-visible. El foco dobla además el filete por dentro
   para que también se note con ratón, cuando no hay aro. */
.ubi-campo__control:hover {
  border-color: var(--verde-bosque);
}

.ubi-campo__control:focus {
  border-color: var(--verde-bosque);
  box-shadow: inset 0 0 0 1px var(--verde-bosque);
}

.ubi-campo__control--area {
  min-height: auto;
  resize: vertical;
}

.ubi-campo__control[aria-invalid="true"] {
  border-color: var(--color-alerta);
  box-shadow: inset 0 0 0 1px rgb(var(--rojo-baya-rgb) / 0.4);
}

.ubi-campo__pista {
  display: block;
  font-size: var(--fs-micro);
  color: var(--color-texto-suave);
}

/* EL ERROR VA JUNTO A SU CAMPO, debajo y dentro del mismo <p>, nunca en un
   resumen lejano: quien lo lee tiene que ver a la vez qué está mal y dónde. */
.ubi-campo__error {
  display: flex;
  align-items: flex-start;
  gap: 0.4em;
  font-size: var(--fs-micro);
  font-weight: var(--peso-medio);
  color: var(--color-alerta);
}

/* Mientras está vacío no ocupa sitio ni se anuncia. */
.ubi-campo__error:empty {
  display: none;
}

.ubi-campo__error::before {
  content: "!";
  display: inline-grid;
  place-items: center;
  width: 1.15em;
  height: 1.15em;
  flex: none;
  margin-top: 0.15em;
  border-radius: var(--radio-full);
  background-color: var(--color-alerta);
  color: var(--color-texto-inverso);
  font-size: var(--fs-micro);
  line-height: 1;
}

/* --- Estado, envío y legal ------------------------------------------------ */
.ubi-form__estado {
  max-width: none;
  margin: 0;
  padding: var(--esp-2xs) var(--esp-sm);
  border-left: 2px solid var(--color-acento);
  border-radius: 0;
  background-color: rgb(var(--verde-menta-rgb) / 0.14);
  font-size: var(--fs-pequeno);
  color: var(--color-texto);
}

.ubi-form__estado:empty {
  display: none;
}

.ubi-form__estado--error {
  border-left-color: var(--color-alerta);
  background-color: rgb(var(--rojo-baya-rgb) / 0.1);
}

.ubi-form__directo[hidden] {
  display: none;
}

.ubi-form__directo {
  align-self: flex-start;
}

.ubi-form__legal {
  max-width: var(--medida);
  margin: 0;
  font-size: var(--fs-micro);
  color: var(--color-texto-suave);
}

/* ==========================================================================
   12. AJUSTES MÓVIL
   ========================================================================== */
@media (max-width: 30em) {
  .ubi {
    --ubi-alto-mapa: clamp(19rem, 56svh, 26rem);
  }

  .ubi-hud {
    top: var(--esp-2xs);
    padding: var(--esp-3xs) var(--esp-2xs);
  }

  .ubi-acciones .btn {
    flex: 1 1 100%;
  }

  .ubi-form {
    padding: var(--esp-md);
  }

  /* Sin relleno lateral en las filas: a 375 px cada píxel de ancho cuenta y el
     resalte del hover no existe en táctil. */
  .ubi-canales > .titulo-seccion,
  .ubi-canal {
    padding-inline: 0;
  }

  .ubi-canal--destacado {
    padding-inline: var(--esp-sm);
  }
}

/* ==========================================================================
   13. COMPATIBILIDAD TEMPORAL CON `en/index.html`
   BORRAR EN CUANTO SE TRADUZCA LA ARQUITECTURA v3 AL INGLÉS.

   La página inglesa es todavía un corte de v1: conserva #experiencias,
   #bienestar, #cultura, #aves, #biodiversidad y #contacto como secciones
   propias, y su ubicación usa el marcado antiguo —.ubi-info, .ubi-tarjeta y
   .ubi-mapa__marco— que el español ya no tiene. No es un archivo de esta
   sección y no se toca, pero tampoco se deja caer: estas tres reglas son lo
   mínimo para que esa página siga leyéndose mientras se rehace.

   No las uses en marcado nuevo. En español, la dirección va en .ubi-placa,
   las referencias y las distancias en .ubi-bloque, y el mapa no lleva marco.
   ========================================================================== */
.ubi-info {
  display: grid;
  gap: var(--gap);
  margin-top: var(--gap-lg);
}

@media (min-width: 52em) {
  .ubi-info {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
    align-items: start;
  }
}

.ubi-tarjeta {
  display: flex;
  flex-direction: column;
  gap: var(--esp-xs);
  padding: var(--esp-lg);
  border: 1px solid var(--color-borde-suave);
  border-radius: 0;
  background-color: var(--color-superficie);
}

.ubi-mapa__marco {
  position: relative;
  border: 1px solid var(--color-borde-suave);
  border-radius: 0;
  background-color: var(--color-superficie-solida);
}
