/* ============================================================
   main.css — Kalixto Le Roy
   Hoja de estilos principal. Mobile-first.
   Sitio CLARO (crema) con texto carbón; el HERO es OSCURO (vídeo + overlay, texto claro).
   Paleta: contextos/estilos_marca.md (crema + carbón + dorado sutil; de Villa KAI).

   HTML que espera (FS-03..FS-09):
     <section class="hero">
       <video class="hero__video" autoplay muted loop playsinline preload="auto">
         <source src="/assets/videos/gran_canaria-web.mp4" type="video/mp4">
       </video>
       <div class="hero__overlay"></div>
       <div class="hero__content"> ...(futuro: logo/titular)... </div>
       <a class="hero__scroll" href="#siguiente" aria-label="Bajar">...</a>
     </section>
     <section id="siguiente" class="test"> ...párrafos de prueba... </section>
   ============================================================ */

/* ---- Paleta de marca (fuente: contextos/estilos_marca.md) ---- */
:root {
    --cream:      #F2F1ED;   /* fondo claro del sitio */
    --cream-deep: #EAE7DF;   /* secciones alternas / cards */
    --charcoal:   #1F1D1A;   /* hero, texto fuerte, footer */
    --text:       #2B2824;   /* texto sobre crema */
    --text-muted: #6E685E;   /* texto apagado */
    --on-dark:    #F7F6F3;   /* texto claro sobre el hero */
    --on-dark-transparent: #f7f6f3d5;   /* texto claro translúcido sobre el hero */
    --gold:       #B8945F;   /* acento sutil (botones/detalles) */
    --brown:      #836656;  /* acento secundario (botones/detalles) */
    --brown-transparent: #836656a8;  /* acento secundario translúcido (latido WA) */
    /* Carbón ACLARADO: `--charcoal` mezclado con un 15% de crema. Mantiene el tono cálido de
       la paleta pero se distingue de `--charcoal`/`--text`, que entre sí apenas se separan.
       Nació como hex suelto en `.wa-float` con la nota «si se queda, lo subimos a variable»;
       al necesitarlo el botón «Reservar» (RV-02) se cumplió esa promesa. */
    --charcoal-soft: #3F3D3A;
    --divider:    rgba(31, 29, 26, 0.12);
    /* Aire ARRIBA de cada sección del recorrido (villas, pasillo, servicios). Un solo número:
       antes eran tres sueltos —2,5rem + 1rem de título en villas, 1,25rem en servicios, 3rem en un
       @media— y cada retoque desalineaba unas secciones respecto a otras sin que se notara hasta
       verlas seguidas. */
    --aire-seccion: 3.5rem;
    /* Tipografía: Prata (serif de display) SOLO para marca/titulares; Lato para todo el texto.
       Prata es de alto contraste → cansa la vista en párrafos largos; Lato es humanista y legible. */
    --display-font: 'Prata', serif;
    --default-font: 'Lato', system-ui, -apple-system, "Segoe UI", sans-serif;
}

/* ---- Fuentes de marca (auto-hospedadas en /assets/fonts/) ----
   TTF por ahora (para ver cómo queda); pasar a WOFF2 antes de producción. */
@font-face {
    font-family: 'Charm';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('/assets/fonts/Charm-Regular.ttf') format('truetype');
}
@font-face {
    font-family: 'Charm';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('/assets/fonts/Charm-Bold.ttf') format('truetype');
}
@font-face {
    font-family: 'Prata';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('/assets/fonts/Prata-Regular.ttf') format('truetype');
}
/* Lato: solo declaramos los pesos que usamos → el navegador solo descarga estos,
   aunque en /assets/fonts/ estén todos los estilos del ZIP de Google. */
@font-face {
    font-family: 'Lato';
    font-style: normal;
    font-weight: 300;
    font-display: swap;
    src: url('/assets/fonts/Lato-Light.ttf') format('truetype');
}
@font-face {
    font-family: 'Lato';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('/assets/fonts/Lato-Regular.ttf') format('truetype');
}
@font-face {
    font-family: 'Lato';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('/assets/fonts/Lato-Bold.ttf') format('truetype');
}
/* Cursivas REALES (no la falsa que el navegador fabrica inclinando la normal) */
@font-face {
    font-family: 'Lato';
    font-style: italic;
    font-weight: 400;
    font-display: swap;
    src: url('/assets/fonts/Lato-Italic.ttf') format('truetype');
}
@font-face {
    font-family: 'Lato';
    font-style: italic;
    font-weight: 700;
    font-display: swap;
    src: url('/assets/fonts/Lato-BoldItalic.ttf') format('truetype');
}

/* ---- Reset mínimo ---- */
*, *::before, *::after { box-sizing: border-box; }

html {
    scroll-behavior: smooth;                    /* FS-08: el botón baja suave, sin JS */
    -webkit-tap-highlight-color: transparent;   /* FS-14: sin destello azul al tocar (iOS/Android) */
    /* Reserva SIEMPRE el hueco de la barra de scroll, exista o no. Sin esto, al abrir el menú
       (`body.nav-open { overflow: hidden }`) la barra desaparece y TODO el contenido salta ~15px
       a la derecha; al cerrar, vuelve. Con el hueco reservado, ese tirón no ocurre. */
    scrollbar-gutter: stable;
}

/* ---- Barra de scroll (escritorio) ----
   Se usan los pseudoelementos WebKit (Chrome/Edge/Safari/Opera) porque son los ÚNICOS que
   permiten ancho exacto y `border-radius`. Las propiedades estándar (`scrollbar-width` /
   `scrollbar-color`) no redondean y solo aceptan auto|thin|none.
   ⚠️ No se pueden declarar ambas a la vez: en Chrome moderno las estándar ANULAN a las WebKit
   y perderíamos el redondeo. Por eso las estándar van dentro de un @supports que solo se activa
   donde NO existen los pseudoelementos WebKit (Firefox). */
::-webkit-scrollbar {
    width: 8px;                       /* por defecto son 15-17px */
    height: 8px;                      /* scroll horizontal, si alguna vez aparece */
}
::-webkit-scrollbar-track {
    background: var(--cream-deep);    /* el crema alterno: se intuye sin llamar la atención */
}
::-webkit-scrollbar-thumb {
    background: var(--charcoal);
    border-radius: 8px;
    /* Borde transparente + background-clip: el pulgar queda ENCAJADO dentro del canal
       en vez de tocar los bordes. Detalle pequeño que se nota. */
    border: 2px solid transparent;
    background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover {
    background: var(--text);
    background-clip: padding-box;
}

@supports not selector(::-webkit-scrollbar) {
    /* Firefox: barra fina y con los colores de marca, aunque sin redondeo (no lo permite). */
    html {
        scrollbar-width: thin;
        scrollbar-color: var(--charcoal) var(--cream-deep);   /* pulgar / canal */
    }
}

body {
    margin: 0;
    font-family: var(--default-font);
    color: var(--text);                  /* texto carbón */
    background: var(--cream);             /* sitio CLARO */
}

/* FS-14: los botones mantienen NUESTROS estilos (sin la apariencia nativa de iOS) */
button {
    -webkit-appearance: none;
    appearance: none;
}

/* ============================================================
   HERO — oscuro: fondo de vídeo + overlay, texto claro (FS-04..FS-06, FS-08)
   ============================================================ */
/* min-height (no height): mide una pantalla COMO MÍNIMO, pero si el contenido no cabe —móvil en
   apaisado, fuente ampliada por accesibilidad, alemán con una línea más— el hero CRECE y la página
   hace scroll, en vez de recortar. Con height fijo + justify-content: flex-end, el sobrante salía
   por arriba y quedaba inalcanzable. Flex + flex:1 en el contenido para que siga llenando la
   pantalla (un height: 100% no funciona contra un padre de altura automática). */
.hero {
    position: relative;
    display: flex;
    width: 100%;
    min-height: 100vh;           /* fallback navegadores sin dvh */
    min-height: 100dvh;          /* móvil: evita el salto de la barra del navegador */
    overflow: hidden;
    background: var(--charcoal); /* si el vídeo tarda: fondo oscuro (no crema) */
}

/* FS-05: el vídeo llena el hero sin deformarse */
.hero__video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 32% center;   /* FS-15: base = inicio del paneo → sin salto al arrancar (iOS) */
    z-index: 1;
    pointer-events: none;          /* FS-15: fondo decorativo → no captura clicks (Safari) */
}

/* FS-12: paneo horizontal SOLO en vertical (el cover recorta ~74% del ancho en móvil).
   Desliza la ventana visible izquierda↔derecha, IDA Y VUELTA (alternate), lento → van
   apareciendo villas → playa → dunas. En escritorio (16:9) el vídeo ya llena → sin paneo.
   Nota: el vídeo ya se repinta cada frame → animar object-position no añade coste extra. */
@keyframes hero-pan {
    from { object-position: 32% center; }   /* no llega al extremo izquierdo (solo océano) */
    to   { object-position: 100% center; }
}
@media (orientation: portrait) {
    /* FS-13: solo panea cuando el vídeo reproduce de verdad (.is-playing lo añade hero.js) */
    .hero.is-playing .hero__video {
        animation: hero-pan 10s linear infinite alternate;
    }
}

/* FS-06: capa de oscurecido para que el texto/logo se lean */
.hero__overlay {
    position: absolute;
    inset: 0;
    background: rgba(31, 29, 26, 0.40);   /* carbón translúcido */
    z-index: 2;
}

/* Contenido del hero (futuro: logo/titular) — abajo, centrado horizontalmente, texto claro.
   El padding inferior deja aire suficiente sobre el indicador de scroll (que ocupa ~64px desde abajo). */
.hero__content {
    position: relative;
    z-index: 3;
    flex: 1;                     /* llena el hero, pero puede estirarse si el contenido lo pide */
    display: flex;
    flex-direction: column;      /* marca / h1 / subtítulo, uno debajo de otro */
    align-items: center;         /* en columna: centra en HORIZONTAL */
    justify-content: flex-end;   /* en columna: apoya el bloque ABAJO */
    /* Espaciado proporcional a la ALTURA visible: el 14dvh equivale a los 7.5rem en un móvil
       vertical típico (se ve igual que antes), pero en apaisado se comprime y cabe.
       El SUELO son 5.5rem = los 4rem que ocupa el indicador de scroll (bottom 1.25rem + 44px de alto)
       + 1.5rem de aire → el texto nunca invade su franja por muy baja que sea la pantalla. */
    padding: 1.5rem 1.5rem clamp(5.5rem, 14dvh, 7.5rem);
    text-align: center;
    color: var(--on-dark);
}
/* Marca: rótulo grande en Prata. font-weight 400 = el ÚNICO peso que tenemos
   → evita la "falsa negrita" que el navegador fabricaba antes (trazos sucios). */
.hero__brand {
    margin: 0;
    font-family: var(--display-font);
    font-weight: 400;
    font-size: 2rem;   /* RS-02: base móvil; los escalones de tablet/escritorio, en sus @media */
    line-height: 1.15;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.65);   /* mismo realce que el h1 */
}

/* H1: la keyword. Más pequeño que la marca y en Lato, en mayúsculas espaciadas. */
.hero__title {
    margin: 0.35rem 0 0;
    font-family: var(--default-font);
    font-weight: 400;
    font-style: normal;
    font-size: 0.85rem;   /* RS-02: base móvil (el letter-spacing en em escala solo) */
    letter-spacing: 0.09em;
    text-transform: uppercase;
    text-shadow: 0 1px 5px rgba(0, 0, 0, 0.95);   /* realce sobre el vídeo (igual que el subtítulo) */
}

/* Subtítulo: el posicionamiento (lujo accesible). Ancho limitado para que no se lea en línea larga. */
.hero__subtitle {
    /* grid con TODAS las frases en la misma celda (grid-area 1/1) → se superponen para el fundido
       y el bloque mide lo que la frase más alta, sin fijar alturas a mano (el alemán ocupa más). */
    display: grid;
    max-width: 34ch;
    margin: clamp(1rem, 13dvh, 7rem) auto 0;   /* proporcional a la altura (ver .hero__content) */
    font-family: 'Charm', cursive;   /* acento elegante (script): línea corta, no texto corrido */
    font-weight: 400;
    /* RS-02: base móvil. Charm tiene x-height pequeña → pide más cuerpo. El max-width en `ch`
       escala solo, así que sigue cortando a ~34 caracteres por línea a cualquier tamaño. */
    font-size: 1.25rem;
    line-height: 1.45;
    text-shadow: 0 1px 5px rgba(0, 0, 0, 0.95);   /* más realce: Charm es de trazo fino sobre vídeo */
}

/* Cada frase, apilada en la misma celda. Oculta salvo la que lleve .is-visible (la mueve subtitle.js). */
.hero__subtitle-part {
    grid-area: 1 / 1;
    opacity: 0;
    transition: opacity 0.9s ease;
}
/* Entrada CON RETARDO = fundido secuencial, no cruzado: al añadir .is-visible manda esta
   transición (espera 1.4s, lo que tarda la anterior en irse, y entonces aparece); al quitarla
   manda la de arriba (sin retardo → se va ya). Así nunca se ven dos frases superpuestas. */
.hero__subtitle-part.is-visible {
    opacity: 0.92;
    transition: opacity 0.9s ease 0.9s;
}

/* FS-08: botón indicador de scroll (estilo "mouse", claro sobre el hero oscuro) */
.hero__scroll {
    position: absolute;
    left: 50%;
    bottom: 1.25rem;
    transform: translateX(-50%);
    z-index: 3;
    width: 24px;
    height: 36px;
    border: 2px solid rgba(247, 246, 243, 0.8);   /* --on-dark al 80% */
    border-radius: 12px;
    text-decoration: none;
}
.hero__scroll::before {
    content: "";
    position: absolute;
    left: 50%;
    top: 7px;
    width: 3px;
    height: 7px;
    margin-left: -1.5px;
    background: rgba(247, 246, 243, 0.9);
    border-radius: 2px;
    animation: scroll-wheel 1.6s ease-in-out infinite;
}
@keyframes scroll-wheel {
    0%   { opacity: 0; transform: translateY(0); }
    30%  { opacity: 1; }
    100% { opacity: 0; transform: translateY(4px); }
}

/* FS-13: señal de play — OCULTA por defecto, visible solo si el autoplay falla (.hero.needs-play) */
.hero__play {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 4;
    width: 76px;
    height: 76px;
    padding: 0;
    border: 2px solid rgba(247, 246, 243, 0.9);   /* --on-dark */
    border-radius: 50%;
    background: rgba(31, 29, 26, 0.35);            /* carbón translúcido */
    display: none;
    cursor: pointer;
}
.hero.needs-play .hero__play { display: block; }
.hero__play::before {   /* triángulo de "play" */
    content: "";
    position: absolute;
    top: 50%;
    left: 54%;
    transform: translate(-50%, -50%);
    border-style: solid;
    border-width: 11px 0 11px 18px;
    border-color: transparent transparent transparent rgba(247, 246, 243, 0.95);
}

/* ============================================================
   NAVBAR (NV) — barra fija sobre el hero + menú overlay con rombo
   El JS (nav.js, NV-05) alterna .is-open en .nav → dispara la X y el rombo (ambos CSS).
   ============================================================ */
.nav {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    z-index: 100;                         /* sobre el hero */
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.75rem 1.25rem 0.5rem;   /* menos aire arriba/abajo; laterales sin cambio */
    transition: background-color 0.3s ease, box-shadow 0.3s ease;
}

/* Logo (izq) — claro sobre el hero; por encima del overlay al abrir */
.nav__logo {
    position: relative;
    z-index: 2;
    display: block;
    color: var(--on-dark);
    text-decoration: none;
}

/* Opción A: logo como imagen (emblema cuadrado). Blanco SIEMPRE (sobre el vídeo y sobre la barra oscura). */
.nav__logo-img {
    display: block;
    height: 84px;    /* a afinar; el emblema es cuadrado (1:1) */
    width: auto;
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));   /* realce sutil (igual que la hamburguesa) */
}

/* NV-03: botón hamburguesa → X */
.nav__toggle {
    position: relative;
    z-index: 2;
    width: 32px;
    height: 22px;
    padding: 0;
    background: none;
    border: 0;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    /* sombra sutil de profundidad (sigue la forma de las líneas y de la X) */
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
}
.nav__toggle-line {
    display: block;
    width: 100%;
    height: 2px;
    background: var(--on-dark);
    border-radius: 2px;
    transition: transform 0.3s ease, opacity 0.3s ease;
}
.nav__toggle-line:nth-child(2) { width: 75%; margin-right: auto; }   /* medio más corta, pegada a la IZQUIERDA */
.nav.is-open .nav__toggle-line:nth-child(1) { transform: translateY(10px) rotate(45deg); }
.nav.is-open .nav__toggle-line:nth-child(2) { opacity: 0; }
.nav.is-open .nav__toggle-line:nth-child(3) { transform: translateY(-10px) rotate(-45deg); }

/* NV-04: menú overlay — rombo de proporción FIJA (cuadrado girado 45°) que crece con scale().
   Antes se usaba clip-path con %, que estiraba el rombo según el aspect-ratio de la pantalla.
   Ahora el rombo es una capa de fondo aparte (::before) → NO rota los enlaces y mantiene 1:1. */
.nav-menu {
    position: fixed;
    inset: 0;
    z-index: 1;                            /* bajo el logo/toggle */
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;                      /* recorta el sobrante del rombo (sin scroll horizontal) */
    pointer-events: none;                  /* cerrado: no bloquea clics */
}
/* El rombo: cuadrado girado 45°. Lado ≈ (ancho+alto)/√2 con margen → cubre toda la pantalla al escalar. */
.nav-menu::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: calc((100vw + 100vh) / 1.35);
    height: calc((100vw + 100vh) / 1.35);
    /* Carbón translúcido: deja ver el vídeo del hero por detrás. Al 70% por decisión de Andrés
       (ago-2026); antes iba al 92%. Cuanto más bajo, más se cuela el vídeo alrededor del panel. */
    background: rgba(31, 29, 26, 0.7);
    transform: translate(-50%, -50%) rotate(45deg) scale(0);   /* cerrado: rombo en un punto central */
    transition: transform 0.5s ease;
    z-index: -1;                           /* detrás de los enlaces */
}
.nav.is-open .nav-menu { pointer-events: auto; }
.nav.is-open .nav-menu::before {
    transform: translate(-50%, -50%) rotate(45deg) scale(1);   /* abierto: rombo crecido, llena la pantalla */
}

/* Enlaces del menú — fade tras abrir el rombo */
/* Banda a TODO el ancho que agrupa enlaces + selector de idioma: tapa el texto del hero sin
   verse como una caja flotando en el centro.
   ⚠️ Su color (`#2B2825`) se eligió un pelín más claro que el carbón puro para IGUALAR al rombo
   cuando este iba al 92%. Con el rombo al 70% ya no se funden: la banda es OPACA y su alrededor
   deja pasar bastante vídeo, así que el panel se distingue como una banda sólida sobre el fondo.
   Eso es lo buscado —el texto del menú se lee sobre color plano, no sobre imágenes en movimiento—,
   pero conviene saber que los dos valores están relacionados: si se toca la opacidad del rombo,
   este color es el que decide si la banda se nota más o menos.
   El fundido va AQUÍ (no en la lista) → cubre todo el contenido del menú de una vez. */
.nav-menu__panel {
    width: 100%;
    /* El scroll va AQUÍ, no en .nav-menu: aquel necesita su `overflow: hidden` para recortar el
       rombo (un cuadrado gigante girado), y ponerle `auto` generaría barras para abarcarlo entero.
       Con max-height, el panel nunca supera la pantalla → el `align-items: center` del padre deja
       de desbordar (si desbordara, el sobrante de ARRIBA sería inalcanzable: mismo problema que
       tuvimos en el hero). Y si el contenido no cabe —móvil apaisado, o con el desplegable de
       idioma abierto—, se hace scroll dentro del panel.
       overscroll-behavior: al llegar al final, el gesto NO se contagia a la página de detrás. */
    max-height: 100%;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 2.5rem 1.5rem;
    background: #2B2825;
    text-align: center;
    opacity: 0;
    transition: opacity 0.3s ease;
}
.nav.is-open .nav-menu__panel {
    opacity: 1;
    transition: opacity 0.4s ease 0.3s;    /* delay: aparece después del rombo */
}

.nav-menu__list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.nav-menu__link {
    display: inline-block;
    padding: 0.6rem 1rem;
    color: var(--on-dark);
    text-decoration: none;
    font-family: 'Charm', cursive;   /* misma script elegante del subtítulo del hero */
    font-size: 1.8rem;               /* Charm tiene x-height pequeña → sube el cuerpo */
    letter-spacing: 0.03em;
}
.nav-menu__link:hover,
.nav-menu__link:focus { color: var(--on-dark-transparent); }   /* el mismo crema, algo translúcido */
/* Página en la que se está: además del color, un subrayado dorado — el color por sí solo no
   basta para quien no lo distingue bien. El `aria-current` del HTML lo anuncia al lector. */
.nav-menu__link.is-current {
    color: var(--gold);
    /* Subrayado de TEXTO, no `border-bottom`. El borde se dibuja en el filo de la caja, o sea
       0,6rem por debajo por culpa del `padding` del enlace — la línea quedaba despegada de la
       palabra. Bajar ese `padding` no valía: desalinearía este enlace respecto a los demás.
       `text-decoration` se ancla a la LETRA y no depende del padding, así que la distancia se
       controla con un solo número (`text-underline-offset`) sin mover nada más.
       En `em` para que acompañe al cuerpo, que cambia entre móvil (1,8rem) y escritorio (1,2rem). */
    text-decoration: underline;
    text-decoration-color: var(--gold);
    text-decoration-thickness: 1px;
    text-underline-offset: 0.14em;
}

/* Selector de idioma (SI): desplegable con aspecto de <select>, hecho con enlaces reales.
   En Lato (no Charm): son palabras funcionales a tamaño pequeño y prima la legibilidad. */
.lang-switch {
    position: relative;
    margin-top: 1.75rem;   /* respira respecto a los enlaces, pero sin línea que los separe */
}

/* El disparador se ve como UN ENLACE MÁS del menú (mismo Charm, mismo tamaño y padding
   que .nav-menu__link): sin caja ni separador, para que no rompa la lista. */
.lang-switch__toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 1rem;
    background: none;
    border: 0;
    color: var(--on-dark);
    font-family: 'Charm', cursive;
    font-size: 1.6rem;
    letter-spacing: 0.03em;
    cursor: pointer;
    transition: color 0.2s ease;
}
.lang-switch__toggle:hover,
.lang-switch__toggle:focus { color: var(--on-dark-transparent); }   /* el mismo crema, algo translúcido */

.lang-switch__caret {                 /* flecha ▾ en CSS puro (sin imagen) */
    width: 0;
    height: 0;
    margin-left: 0.15rem;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 5px solid currentColor;
    transition: transform 0.2s ease;
}
.lang-switch.is-open .lang-switch__caret { transform: rotate(180deg); }

/* La lista desplegada */
.lang-switch__list {
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    z-index: 5;
    display: none;                    /* cerrada por defecto; el JS pone .is-open */
    min-width: 11rem;
    margin: 0.4rem 0 0;
    padding: 0.35rem 0;
    list-style: none;
    text-align: left;
    background: var(--charcoal);
    border: 1px solid rgba(247, 246, 243, 0.18);
}
.lang-switch.is-open .lang-switch__list { display: block; }

/* Se abre HACIA ARRIBA cuando no cabe debajo. La clase la decide nav.js midiendo el hueco real:
   el CSS no puede saberlo por su cuenta (sabe el alto de la ventana, pero no en qué punto de ella
   está el botón, que es lo que determina si cabe). Pasa sobre todo en móvil apaisado, donde el
   selector queda pegado al borde inferior. */
.lang-switch.opens-up .lang-switch__list {
    top: auto;
    bottom: 100%;
    margin: 0 0 0.4rem;
}

.lang-switch__link {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    padding: 0.55rem 0.9rem;
    color: var(--on-dark);
    text-decoration: none;
    font-family: 'Charm', cursive;
    font-size: 1.2rem;
    letter-spacing: 0.03em;
    transition: background-color 0.2s ease;
}
.lang-switch__link:hover,
.lang-switch__link:focus { background: rgba(247, 246, 243, 0.1); }
.lang-switch__link.is-current { color: var(--gold); }   /* idioma actual */

.lang-switch__flag {
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    /* Sin border-radius: los SVG YA vienen dibujados en círculo, no hay que recortarlos. */
}

/* NV-05: bloquear el scroll del body mientras el menú está abierto */
body.nav-open { overflow: hidden; }

/* NV-05: al pasar el hero, la barra pasa a fondo OSCURO; el logo y la hamburguesa
   se mantienen BLANCOS en todo momento (sobre el vídeo y sobre la barra oscura). */
/* `body.past-hero` cubre las páginas SIN hero (las legales), donde la barra debe nacer ya
   sólida: si no, saldría transparente con el texto en crema sobre un fondo crema — invisible.
   Un solo mecanismo para las dos situaciones, en vez de una regla aparte para esas páginas. */
.nav--solid,
body.past-hero .nav {
    background-color: var(--charcoal);
    box-shadow: 0 1px 12px rgba(0, 0, 0, 0.18);
}

/* ============================================================
   BOTÓN FLOTANTE DE WHATSAPP (WA) — siempre visible, abajo a la DERECHA
   Estático (sin latido). Dos estados según dónde esté:
     · SOBRE EL HERO  → marrón y crema TRANSLÚCIDOS: se integra con el vídeo sin taparlo.
     · FUERA DEL HERO → los mismos colores OPACOS: sobre la sección crema la transparencia
       lo desdibujaría, y ahí necesita cuerpo.
   Lo dispara `body.past-hero`, que pone nav.js con la geometría real (ver ahí el porqué).
   ============================================================ */
.wa-float {
    position: fixed;
    right: 1rem;
    /* env(safe-area-inset-bottom): en iPhone con barra de gesto, la esquina inferior es zona
       del sistema — sin esto, al pulsar el botón se abriría el multitarea. */
    bottom: calc(1.5rem + env(safe-area-inset-bottom));
    /* 90: por debajo de la barra (100) → el menú abierto lo tapa; y por debajo del banner de
       cookies (200) → mientras haya que consentir, queda cubierto a propósito (ver cookies.js). */
    z-index: 90;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 60px;
    height: 60px;
    border-radius: 50%;
    background: var(--brown-transparent);
    /* Sombra en CAPAS (así se consigue profundidad real, no una mancha plana):
         1) contacto — corta y cerrada: define el canto del círculo y lo asienta.
         2) ambiente — amplia y difusa: es la que da sensación de ALTURA.
         3) realce interior — una línea de luz en el borde superior, como si la luz cayera
            desde arriba; es lo que hace que el círculo parezca un objeto y no un recorte.
       Sin desplazamiento horizontal: la luz viene de arriba, no de un lado. */
    box-shadow:
        0 2px 4px rgba(0, 0, 0, 0.18),
        0 8px 20px rgba(0, 0, 0, 0.22),
        inset 0 1px 0 rgba(247, 246, 243, 0.28);
    /* El cambio entre estados es suave, no un salto seco (esto NO es el latido: solo suaviza
       el paso de translúcido a opaco al salir del hero). */
    transition: background-color 0.3s ease, color 0.3s ease, box-shadow 0.3s ease;
}
.wa-float__icon {
    display: block;
    width: 38px;
    height: 38px;
    /* Sin corrección de centrado óptico: se probó desplazarlo (3px y 1,5px arriba-derecha) para
       compensar que la cola del globo llega a la esquina inferior izquierda del viewBox, pero
       el conjunto quedaba peor — el ojo centra por la masa del globo, que ya está bien situada. */
    color: var(--on-dark-transparent);
    transition: color 0.3s ease;
}

/* Fuera del hero: los mismos colores, ya sin transparencia. La sombra sube un punto porque
   sobre el crema sí se aprecia (sobre el vídeo oscuro apenas se distinguía). */
body.past-hero .wa-float {
    /* Se quedó, así que subió a variable y a estilos_marca.md — y ahora la comparte con el
       botón «Reservar» de la ficha de villa (RV-02). */
    background: var(--charcoal-soft);
    box-shadow:
        0 2px 5px rgba(31, 29, 26, 0.16),
        0 10px 24px rgba(31, 29, 26, 0.20),
        inset 0 1px 0 rgba(247, 246, 243, 0.22);
}
/* Crema opaco: se probaron dorado (con y sin transparencia), marrón y el apagado de los
   enlaces del pie — todos perdían demasiado contraste sobre el círculo. El crema se queda. */
body.past-hero .wa-float__icon { color: var(--on-dark); }

/* ============================================================
   TESTIMONIOS (TS-03) — cierre de la portada
   Las citas se APILAN y se cruzan con opacidad; solo una es visible. Todas están en el DOM
   (bueno para SEO y para las IA, que no ejecutan la rotación).
   ============================================================ */
.testimonios {
    /* El mismo `--aire-seccion` que villas y servicios: las secciones del recorrido arrancan igual. */
    padding: var(--aire-seccion) 0 3.5rem;
    background: var(--cream-deep);   /* alterna con el crema de servicios y despega la sección */

    /* 🔑 **MARGEN y no padding, y hace falta por culpa del PIE.** `.footer` no se separa con un
       margen: usa `border-top: 8px solid var(--cream)` y confía en que el color coincida con la
       página para que se lea como aire (lo dice su propio comentario). Ese truco funciona mientras
       lo de arriba sea crema — y esta sección es `--cream-deep`, así que esos 8px dejaban de
       fundirse y la línea dorada quedaba pegada a la banda.
       El `padding` de arriba no sirve para esto: va DENTRO de la banda oscura, y lo que falta es
       crema FUERA.
       ✅ Global y sin acotar: en la ficha de villa detrás viene «← Ver todas las villas», que ya
       lleva `margin-top: var(--aire-seccion)`. Son hermanos, así que **los márgenes COLAPSAN** y
       queda el mayor — 3,5rem, no 7. */
    margin-bottom: var(--aire-seccion);
}
.testimonios__cabecera {
    max-width: 70ch;
    margin: 0 auto 2rem;
    padding: 0 1.5rem;
    text-align: center;
}
.testimonios__titulo {
    margin: 0 0 0.75rem;
    font-family: var(--display-font);
    font-weight: 400;
    font-size: 1.45rem;
    line-height: 1.25;
    color: var(--brown);
}
.testimonios__intro {
    margin: 0;
    color: var(--text);
    font-family: 'Charm', cursive;
    font-size: 1.1rem;
    line-height: 1.5;
}

/* 🔑 EL MARCO ES EL QUE MANDA EN LA ALTURA.
   Las citas van superpuestas en absoluto, así que el marco no las «ve» y colapsaría a cero. Con
   `display: grid` y todas las citas en LA MISMA CELDA, el marco mide lo que la MÁS LARGA y las
   demás se dibujan encima. Resultado: al cambiar de cita NO hay salto de maquetación, que es el
   defecto clásico de este efecto. */
.testimonios__marco {
    display: grid;
    max-width: 46rem;
    margin: 0 auto;
    padding: 0 1.5rem;
}
.testimonio {
    /* Todas en la celda 1/1 → se apilan sin sacarlas del flujo. */
    grid-area: 1 / 1;
    margin: 0;
    opacity: 0;
    /* `visibility` además de `opacity`: una cita a 0 de opacidad SIGUE siendo seleccionable con el
       ratón y la anuncian algunos lectores de pantalla. Sin esto, al arrastrar por la sección se
       seleccionan las seis citas superpuestas a la vez. */
    visibility: hidden;
    transition: opacity 0.8s ease, visibility 0.8s;
    text-align: center;
}
.testimonio.is-activa {
    opacity: 1;
    visibility: visible;
}
.testimonio__texto {
    /* ✍️ Sin firma debajo, la TIPOGRAFÍA sostiene la cita sola: cuerpo generoso y cursiva de marca.
       Las comillas las pone el CSS y no el texto, para que los archivos de idioma guarden la frase
       limpia — y para que Ángel pueda pegar las suyas sin preocuparse del formato. */
    margin: 0;
    font-family: 'Charm', cursive;
    font-size: 1.35rem;
    line-height: 1.55;
    color: var(--text);
}
/* 🌍 **LAS COMILLAS CAMBIAN CON EL IDIOMA, y esto no es un capricho tipográfico.**
   Cada mercado tiene las suyas, y usar las españolas en los tres delata la traducción:
       ES  «así»     · comillas latinas
       EN  “así”     · dobles altas
       DE  „así“     · la de apertura va ABAJO (Gänsefüßchen)
   Es el mismo cuidado que ya se tuvo con la preposición alemana en `meta_villa.php` (`auf` para
   una isla, `in` para una localidad): en el mercado alemán estos detalles se notan.
   🔤 Van en el CSS y no en `lang/*.php` para que los archivos de idioma guarden la frase LIMPIA —
   así Ángel pega sus textos reales sin preocuparse del formato.
   El gancho es el `lang` del `<html>`, que el front controller ya emite en cada página. */
.testimonio__texto::before { content: '«'; }
.testimonio__texto::after  { content: '»'; }
[lang="en"] .testimonio__texto::before { content: '\201C'; }
[lang="en"] .testimonio__texto::after  { content: '\201D'; }
[lang="de"] .testimonio__texto::before { content: '\201E'; }
[lang="de"] .testimonio__texto::after  { content: '\201C'; }

/* Quien pidió menos movimiento ve la primera cita fija: el JS no arranca la rotación, y aquí se
   quita también el fundido por si el estado cambia con la página abierta. */
@media (prefers-reduced-motion: reduce) {
    .testimonio { transition: none; }
}

@media (min-width: 768px) {
    .testimonios__titulo  { font-size: 1.6rem; }
    .testimonio__texto    { font-size: 1.5rem; }
}

/* ============================================================
   BANNER DE COOKIES + MODAL (CK-06)
   Oscuro, como la barra al hacer scroll y el pie → el sitio (crema) queda enmarcado.
   ⚖️ RECHAZAR y ACEPTAR tienen PESO VISUAL COMPARABLE a propósito: el criterio europeo es
   que rechazar sea tan fácil como aceptar. El patrón habitual —«Aceptar» en un botón vistoso
   y «Rechazar» en gris diminuto— es justo lo que las autoridades señalan como consentimiento
   no libre. «Personalizar» sí puede ser secundario: es una tercera vía, no la negativa.
   ============================================================ */
.cookie-banner {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 200;                     /* sobre la barra (100) y el WhatsApp (90) */
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 1rem 2rem;
    /* Arriba algo menos que abajo A PROPÓSITO: los botones aportan su propio relleno interno,
       que el ojo suma al hueco inferior. Con valores idénticos, el superior PARECE mayor.
       El `env(safe-area-inset-bottom)` solo suma en móviles con barra de gesto (0 en el resto):
       sin él, los botones quedarían bajo esa zona del sistema. */
    padding: 1rem 1rem calc(1.25rem + env(safe-area-inset-bottom));
    background: rgba(31, 29, 26, 0.95);   /* carbón al 95%: apenas se intuye el fondo */
    border-top: 1px solid rgba(184, 148, 95, 0.55);   /* filo dorado, apenas un trazo */
    color: var(--on-dark);
    /* Entra deslizándose desde abajo. Los 0.35s DEBEN coincidir con el setTimeout de
       cookies.js que pone display:none al ocultarlo; si no, desaparecería de golpe. */
    transform: translateY(100%);
    transition: transform 0.35s ease;
}
.cookie-banner.is-visible { transform: translateY(0); }

.cookie-banner__text {
    max-width: 62ch;
    font-size: 0.88rem;
    line-height: 1.55;
    color: rgba(247, 246, 243, 0.85);
    text-align: justify;
    /* La justificación en columnas estrechas abre huecos enormes entre palabras («ríos»),
       y en alemán es peor porque las palabras son largas. La partición con guiones los cierra,
       y funciona por idioma porque head.php pone el `lang` correcto en el <html>. */
    -webkit-hyphens: auto;
            hyphens: auto;
}
.cookie-banner__text strong {
    display: block;
    margin-bottom: 0.25rem;
    color: var(--on-dark);
    font-size: 0.95rem;
    letter-spacing: 0.02em;
}
.cookie-banner__text a { color: var(--gold); }

.cookie-banner__actions {
    display: flex;
    flex-wrap: wrap;
    /* Centra CADA fila: sin esto, al desbordar en móvil el botón que baja se pegaba a la
       izquierda (flex-start es el valor por defecto) y quedaba descuadrado. */
    justify-content: center;
    gap: 0.6rem;
}

/* ---- Botones ---- */
.cookie-btn {
    padding: 0.4rem 0.85rem;
    border-radius: 2px;
    font-family: 'Charm', cursive;
    font-size: 1rem;         /* Charm tiene x-height pequeña → pide más cuerpo que Lato */
    font-weight: 700;
    letter-spacing: 0.03em;  /* la script pide menos espaciado que la sans */
    cursor: pointer;
    transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
/* Aceptar y Rechazar: MISMO tamaño y misma presencia (ver nota de arriba). */
.cookie-btn--accept {
    background: var(--gold);
    border: 1px solid var(--gold);
    color: var(--charcoal);
}
.cookie-btn--accept:hover,
.cookie-btn--accept:focus-visible { background: #C9A46C; border-color: #C9A46C; }

.cookie-btn--reject {
    background: transparent;
    border: 1px solid rgba(247, 246, 243, 0.55);
    color: var(--on-dark);
    font-weight: 400;   /* el crema sobre carbón ya contrasta de sobra: no necesita negrita */
}
.cookie-btn--reject:hover,
.cookie-btn--reject:focus-visible { background: rgba(247, 246, 243, 0.12); }

/* Personalizar: mismo tratamiento que Rechazar (botón con borde), no un enlace suelto. */
.cookie-btn--customize {
    background: transparent;
    border: 1px solid rgba(247, 246, 243, 0.55);
    color: var(--on-dark);
    font-weight: 400;
}
.cookie-btn--customize:hover,
.cookie-btn--customize:focus-visible { background: rgba(247, 246, 243, 0.12); }

.cookie-btn--save {
    background: var(--gold);
    border: 1px solid var(--gold);
    color: var(--charcoal);
}
.cookie-btn--save:hover,
.cookie-btn--save:focus-visible { background: #C9A46C; border-color: #C9A46C; }

/* ---- Modal ---- */
.cookie-modal-overlay {
    position: fixed;
    inset: 0;
    z-index: 210;                     /* sobre el banner */
    /* display lo pone el JS (none ↔ flex) */
    align-items: center;
    justify-content: center;
    padding: 1rem;
    background: rgba(0, 0, 0, 0.6);
}
.cookie-modal {
    position: relative;
    width: 100%;
    max-width: 34rem;
    /* Igual que hicimos con el menú: en móvil APAISADO estos diálogos se desbordan y el
       sobrante queda inalcanzable. Con max-height + scroll interno, siempre se llega al final. */
    max-height: calc(100dvh - 2rem);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 2rem 1.5rem 1.5rem;
    background: var(--charcoal);
    border-top: 2px solid var(--gold);
    color: var(--on-dark);
}
.cookie-modal__close {
    position: absolute;
    top: 0.75rem;
    right: 0.75rem;
    display: flex;
    padding: 0.4rem;
    background: none;
    border: 0;
    color: rgba(247, 246, 243, 0.6);
    cursor: pointer;
    transition: color 0.2s ease;
}
.cookie-modal__close:hover,
.cookie-modal__close:focus-visible { color: var(--on-dark); }

.cookie-modal__title {
    margin: 0 0 0.75rem;
    font-family: var(--display-font);
    font-weight: 400;
    font-size: 1.5rem;
}
.cookie-modal__desc {
    margin: 0 0 1.5rem;
    font-size: 0.85rem;
    line-height: 1.6;
    color: rgba(247, 246, 243, 0.75);
}
.cookie-modal__desc a { color: var(--gold); }

.cookie-modal__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 0.6rem;
    margin-top: 1.5rem;
}

/* ---- Categorías ---- */
.cookie-category {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
    padding: 1rem 0;
    border-top: 1px solid rgba(247, 246, 243, 0.12);
}
.cookie-category__info { flex: 1; }
.cookie-category__name {
    margin-bottom: 0.2rem;
    font-size: 0.95rem;
    letter-spacing: 0.02em;
}
.cookie-category__desc {
    font-size: 0.8rem;
    line-height: 1.5;
    color: rgba(247, 246, 243, 0.6);
}
.cookie-category__tag {
    display: inline-block;
    margin-top: 0.45rem;
    padding: 0.15rem 0.5rem;
    border: 1px solid rgba(184, 148, 95, 0.5);
    color: var(--gold);
    font-size: 0.7rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

/* ---- Interruptores ---- */
.cookie-toggle {
    position: relative;
    flex-shrink: 0;
    width: 44px;
    height: 24px;
    margin-top: 0.15rem;
}
/* El input se oculta pero SIGUE EN EL DOM y recibe el foco: así el interruptor se maneja
   con teclado y lo anuncian los lectores de pantalla. Un div con onclick no haría nada de eso. */
.cookie-toggle input {
    position: absolute;
    opacity: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    cursor: pointer;
}
.cookie-toggle__slider {
    position: absolute;
    inset: 0;
    border: 1px solid rgba(247, 246, 243, 0.35);
    border-radius: 24px;
    background: rgba(247, 246, 243, 0.08);
    transition: background-color 0.2s ease, border-color 0.2s ease;
    pointer-events: none;
}
.cookie-toggle__slider::before {
    content: "";
    position: absolute;
    top: 3px;
    left: 3px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--on-dark);
    transition: transform 0.2s ease;
}
.cookie-toggle input:checked + .cookie-toggle__slider {
    background: var(--gold);
    border-color: var(--gold);
}
.cookie-toggle input:checked + .cookie-toggle__slider::before { transform: translateX(20px); }
.cookie-toggle input:disabled + .cookie-toggle__slider { opacity: 0.45; }
.cookie-toggle input:focus-visible + .cookie-toggle__slider {
    outline: 2px solid var(--gold);
    outline-offset: 2px;
}

/* (El molde de las PÁGINAS INTERIORES —legales, 404 y las que vengan— vive en
   assets/css/page.css, que solo se carga en ellas. Aquí se queda lo general —barra, botón
   flotante, `past-hero`—, que aplica a todo el sitio.) */

/* ============================================================
   PIE (CK-03) — reconstruido del original de Ángel (referencias/clon)
   Se conserva su estructura de bandas y la línea decorativa superior; se descartan sus
   colores y sus clases de framework. Oscuro para cerrar el sitio (que es claro) y hacer
   pareja con el hero. Centrado, como el original.
   ============================================================ */
.footer {
    position: relative;
    background: var(--charcoal);
    color: var(--on-dark);
    text-align: center;
    /* El HUECO también es un borde: al ser del color del fondo del sitio, se confunde con la
       página y se lee como aire entre la línea y el pie. Así todo queda DENTRO de la caja del
       pie, sin márgenes que puedan colapsar ni invadir la sección de arriba. */
    border-top: 8px solid var(--cream);
}
/* La línea decorativa (blanca en el original, aquí en dorado de marca) ocupa los primeros
   3px de ese borde → quedan 5px de aire crema entre ella y el cuerpo oscuro del pie. */
.footer::before {
    content: "";
    position: absolute;
    top: -8px;              /* -8 = borde exterior; el 0 del absolute empieza tras el borde */
    left: 0;
    right: 0;
    height: 3px;
    background: var(--gold);
}

.footer__brand { padding: 2.5rem 1.5rem 1rem; }
.footer__logo {
    display: block;
    width: 150px;
    height: auto;
    margin: 0 auto;
}

/* Contacto: NO estaba en el original. El pie es donde mucha gente baja a buscar el teléfono. */
.footer__contact {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.5rem 2rem;
    padding: 0 1.5rem 2rem;
}
.footer__contact-link {
    color: var(--on-dark);
    text-decoration: none;
    font-family: 'Charm', cursive;
    font-size: 1.35rem;
    letter-spacing: 0.02em;
    transition: color 0.2s ease;
}
.footer__contact-link:hover,
.footer__contact-link:focus { color: var(--gold); }

/* Legales + preferencias de cookies. Con gap en vez de las barras "|" del original:
   al envolverse en móvil, un separador suelto al final de línea queda huérfano. */
.footer__legal {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.5rem 1.5rem;
    padding: 1.25rem 1.5rem;
    border-top: 1px solid rgba(247, 246, 243, 0.12);
    font-size: 0.82rem;
    letter-spacing: 0.03em;
}
.footer__legal a,
.footer__prefs {
    color: var(--text-muted);
    text-decoration: none;
    transition: color 0.2s ease;
}
.footer__legal a:hover,
.footer__legal a:focus,
.footer__prefs:hover,
.footer__prefs:focus { color: var(--on-dark); }

/* El botón de preferencias debe leerse como un enlace más, no como un botón. */
.footer__prefs {
    padding: 0;
    background: none;
    border: 0;
    font-family: inherit;
    font-size: inherit;
    letter-spacing: inherit;
    cursor: pointer;
}

.footer__copyright {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.35rem 2rem;
    padding: 1.25rem 1.5rem;
    background: rgba(0, 0, 0, 0.25);   /* un punto más oscuro: cierra el sitio */
    color: var(--text-muted);
    font-size: 0.75rem;
    letter-spacing: 0.02em;
}

/* ============================================================
   Sección de prueba bajo el hero (FS-07) — sobre crema
   ============================================================ */
.test {
    max-width: 70ch;
    margin: 0 auto;
    padding: 4rem 1.5rem;
    color: var(--text);
}
.test h2   { color: var(--charcoal); margin-top: 0; }
.test p    { line-height: 1.7; margin: 0 0 1.2rem; }
.test code { color: var(--gold); }       /* guiño del acento dorado */

/* ---- Accesibilidad: respetar "reduce motion" (FS-09) ---- */
@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    .hero__scroll::before { animation: none; }
    .hero.is-playing .hero__video { animation: none; }   /* FS-12/13: sin paneo */
    /* NV-06: navbar sin transiciones (rombo, X, fondo y enlaces aparecen al instante) */
    .nav, .nav__toggle-line, .nav-menu::before, .nav-menu__panel { transition: none; }
    /* WA: el botón ya es estático; solo se quita la transición del cambio de estado. */
    .wa-float, .wa-float__icon { transition: none; }
}

/* ============================================================
   Escritorio / pantallas grandes (mobile-first → min-width)
   ============================================================ */
/* ============================================================
   Pantallas MUY estrechas (iPhone SE y similares: 375px de ancho y solo 667 de alto)
   Ahí el banner llegaba al 37% de la pantalla, sobre todo porque los tres botones no
   caben en una fila y saltan a dos. Se aprieta lo justo para que quepan en una.
   El corte en 380px deja intactos los móviles de 390px, donde ya se ve bien.
   ============================================================ */
@media (max-width: 380px) {
    .cookie-banner {
        padding: 0.75rem 0.75rem calc(0.9rem + env(safe-area-inset-bottom));
        gap: 0.75rem 1rem;
    }
    /* Menor cuerpo → más caracteres por línea → una línea entera menos. */
    .cookie-banner__text { font-size: 0.8rem; }
    .cookie-banner__actions { gap: 0.4rem; }
    .cookie-btn {
        padding: 0.35rem 0.6rem;
        font-size: 0.9rem;
        letter-spacing: 0.02em;
    }
}

/* ============================================================
   Pantallas BAJAS (móvil en apaisado: sobra ancho, falta alto — p. ej. 844×390)
   Aquí no vale mirar el ancho: el de arriba ni se activa. El problema es que el banner
   ocupaba entre el 26% y el 40% del alto, y que texto y botones estaban JUSTO en el límite
   de caber en una fila — al no caber, los botones bajaban y el banner pegaba un salto.
   No pisa al bloque anterior: el SE en vertical activa solo aquel; girado, solo este.
   ============================================================ */
@media (max-height: 480px) {
    .cookie-banner {
        padding: 0.6rem 1rem calc(0.6rem + env(safe-area-inset-bottom));
        gap: 0.5rem 1.5rem;
    }
    /* Al bajar el cuerpo, el bloque se estrecha SOLO (su ancho está en `ch`) → texto y botones
       caben en una fila y se evita el salto de altura. */
    .cookie-banner__text { font-size: 0.8rem; }
    .cookie-btn {
        padding: 0.3rem 0.7rem;
        font-size: 0.9rem;
    }
}

@media (min-width: 768px) {
    .test { padding: 6rem 2rem; }

    /* ---- NAVBAR EN ESCRITORIO (RS-01) ----
       MISMO HTML que en móvil: solo cambia la forma. Nada de una segunda barra duplicada
       (doble mantenimiento, enlaces repetidos en el DOM y líos de accesibilidad), ni de
       decidir el layout desde PHP (el servidor no sabe el tamaño de pantalla; el User-Agent
       no es fiable y romper el HTML por dispositivo rompe el caché).
       El menú deja de ser overlay y se convierte en una fila dentro de la propia barra. */

    .nav__toggle { display: none; }      /* fuera la hamburguesa */

    /* Menos aire vertical que en móvil (allí, 0.75/0.5rem) y algo más de margen lateral,
       que en pantallas anchas el contenido pegado al borde se ve descuidado. */
    .nav { padding: 0.25rem 2rem; }

    .nav-menu {
        position: static;                /* deja de ser overlay a pantalla completa */
        inset: auto;
        overflow: visible;               /* para que el desplegable de idioma no se recorte */
        pointer-events: auto;            /* siempre operativo: ya no hay estado abierto/cerrado */
    }
    .nav-menu::before { content: none; } /* sin rombo: es un recurso solo de móvil */

    .nav-menu__panel {
        width: auto;
        padding: 0;
        background: none;                /* sin banda: los enlaces van sobre el hero */
        display: flex;
        align-items: center;
        gap: 1.5rem;
        opacity: 1;                      /* visible siempre (en móvil lo revelaba .is-open) */
        /* Se ANULA el scroll del overlay móvil: aquí el panel es una fila estrecha dentro de la
           barra, y recortarla haría que el desplegable de idioma (position: absolute, se abre
           hacia abajo) quedara cortado y generase una barra de scroll dentro del navbar. */
        max-height: none;
        overflow: visible;
    }

    .nav-menu__list {
        display: flex;
        align-items: center;
        gap: 0.5rem;
    }

    /* Logo más pequeño → barra menos alta (en móvil son 84px). */
    .nav__logo-img { height: 64px; }

    /* En escritorio los menús son más discretos: 1.8rem se vería enorme en un portátil. */
    .nav-menu__link,
    .lang-switch__toggle { font-size: 1.2rem; }

    /* Banderas algo menores que en móvil (allí son 32px), acordes a la barra más baja. */
    .lang-switch__flag { width: 22px; height: 22px; }

    .lang-switch { margin-top: 0; }      /* en móvil iba debajo; aquí va en la misma fila */
    .lang-switch__list {                 /* el desplegable se alinea a la derecha, no centrado */
        left: auto;
        right: 0;
        transform: none;
    }

    /* Los enlaces llevan el mismo realce que el logo: aquí van sobre el vídeo, sin banda detrás. */
    .nav-menu__link,
    .lang-switch__toggle { text-shadow: 0 1px 3px rgba(0, 0, 0, 0.65); }
    /* Con la barra sólida ya no hace falta el realce. */
    .nav--solid .nav-menu__link,
    .nav--solid .lang-switch__toggle,
    body.past-hero .nav-menu__link,
    body.past-hero .lang-switch__toggle { text-shadow: none; }

    /* ---- La opción actual, en tablet y escritorio: SIN dorado ----
       En móvil el menú es una pantalla completa y el dorado luce; aquí, en una fila junto al logo
       y las banderas, ese acento llamaba más que el propio contenido. Se queda solo el subrayado,
       y en el color de la letra.
       `currentColor` y no `--on-dark` para la línea: así sigue al texto también en `:hover`, que
       lo aclara — con un color fijo, la línea se quedaría más marcada que la palabra.
       ♿ No se pierde accesibilidad: el criterio era «que el estado no dependa SOLO del color», y
       el subrayado sigue siendo esa segunda señal. El `aria-current` del HTML no se toca. */
    .nav-menu__link.is-current {
        color: var(--on-dark);
        text-decoration-color: currentColor;
    }

    /* ---- RS-02 · Tipografía del hero: escalón TABLET ---- */
    .hero__brand    { font-size: 2.3rem; }
    .hero__title    { font-size: 0.92rem; }
    .hero__subtitle { font-size: 1.38rem; }
}

/* ============================================================
   Escritorio (RS-02) — segundo y último escalón tipográfico
   ============================================================ */
@media (min-width: 1024px) {
    .hero__brand    { font-size: 2.8rem; }
    .hero__title    { font-size: 1.05rem; }
    .hero__subtitle { font-size: 1.55rem; }
}

/* ============================================================
   VP-03 — Carrusel de villas de la portada
   El carrusel es `scroll-snap`, no una librería: el asomo de las tarjetas vecinas, el
   deslizamiento táctil y el encaje los hace el navegador. El JS solo añade flechas y automatismo.
   ============================================================ */
.villas {
    /* 🔑 `--aire-seccion` (definido en `:root`) es EL MISMO número para todas las secciones del
       recorrido. Aquí sirve dos veces: arriba separa del hero, y abajo separa del bloque de texto
       que sigue (SEO-00·b).
       ⚠️ Antes este `padding-bottom` era además el hueco que precedía al PASILLO, que no tiene
       padding propio. Al meterse el bloque de texto entre medias, ese papel pasó al
       `margin-bottom` de `.intro-seo`.

       🔑 **POR QUÉ ABAJO SE RESTA 1.5rem Y ARRIBA NO** (17-ago-2026). `.villas__pista` lleva
       `padding: 0.5rem 7% 1.5rem`: esos 24px de abajo existen para que el `overflow-x: auto` no
       recorte el borde de las tarjetas, y son necesarios. Pero **caen justo debajo de la última
       tarjeta**, así que se SUMABAN a este padding y el hueco real bajo el carrusel era de 80px
       cuando el resto de secciones respiran 56.
       Arriba no pasa: los 0.5rem del carril quedan por DEBAJO del título de la sección, que es lo
       que el ojo toma como principio del bloque.
       ⚖️ El `calc` mantiene `--aire-seccion` como única fuente de verdad del hueco PERCIBIDO; si
       algún día cambia el `padding-bottom` de la pista, hay que cambiar el número de aquí. */
    padding: var(--aire-seccion) 0 calc(var(--aire-seccion) - 1.5rem);
    background: var(--cream);
    /* La barra de navegación es `position: fixed` y taparía el título al saltar aquí desde el
       menú o desde el indicador del hero. `scroll-margin-top` le dice al navegador dónde
       detenerse: justo por debajo de la barra (medida: 104 px en móvil, 72 en escritorio).
       ⚠️ Este valor es la ALTURA DE LA BARRA y nada más: no se ajusta según el `padding` de la
       sección. El `padding` añade su aire por debajo del punto de parada, que es lo que se quiere. */
    scroll-margin-top: 6.5rem;
}
.villas__cabecera {
    max-width: 70ch;
    /* El hueco entre la frase y el carrusel sale de este margen inferior (la pista solo añade
       0,5rem de `padding` por arriba). Se toca aquí y no en la pista: ese `padding` es lo que
       evita que la sombra del borde superior de las tarjetas se recorte al desplazarlas. */
    margin: 0 auto 1.5rem;
    padding: 0 1.5rem;
    text-align: center;
}
.villas__titulo {
    /* Sin margen propio: TODO el aire de arriba lo pone `--aire-seccion` en la sección. Repartirlo
       entre dos sitios era justo lo que impedía comparar esta sección con la de servicios. */
    margin: 0 0 0.75rem;
    /* La misma tipografía que el nombre de marca del hero (`--display-font`, Prata).
       Prata tiene más presencia que Charm al mismo cuerpo. Bajado un escalón más (2 → 1,75 rem)
       a petición de Andrés: ya NO iguala al rótulo de marca del hero, y es deliberado — el hero da
       la bienvenida y puede pesar más que el encabezado de un bloque de catálogo.
       Escalones de tablet y escritorio, más abajo, junto a los de la frase. */
    font-family: var(--display-font);
    font-weight: 400;
    font-size: 1.45rem;
    line-height: 1.25;
    color: var(--brown);
}
.villas__intro {
    margin: 0;
    color: var(--text);
    /* Charm, como el título. Sube de cuerpo porque una manuscrita se lee más pequeña que una de
       palo seco al mismo tamaño nominal. Va en `--text` y no en el marrón del título: así
       acompaña sin competir con él. */
    font-family: 'Charm', cursive;
    /* ⚠️ YA NO iguala al subtítulo del hero. Lo hizo hasta ago-2026 (los mismos tres escalones,
       1,25 / 1,38 / 1,55) con el argumento de que eran «la misma voz de la marca». Andrés decidió
       bajar el cuerpo de las secciones y NO el del hero: la divergencia es INTENCIONADA, no un
       descuido — el hero recibe al visitante, estas frases solo presentan un bloque.
       Los escalones van más abajo, junto a los del título — con la regla base delante, o el
       `@media` no ganaría (ver la nota de allí). */
    font-size: 1.1rem;
    line-height: 1.5;
}

.villas__marco { position: relative; }

/* ---- La pista ----
   `scroll-snap-type: x mandatory` hace que se detenga siempre encajada en una tarjeta.
   El `padding` lateral es lo que deja ASOMAR la villa siguiente: la pista de scroll empieza
   antes del borde de la pantalla, así se ve que hay más y se puede arrastrar. */
.villas__pista {
    display: flex;
    gap: 1.5rem;
    padding: 0.5rem 7% 1.5rem;
    overflow-x: auto;
    /* 🔑 `safe center` y NO `center` a secas.
       Centra las tarjetas cuando CABEN (una villa, o dos en escritorio) y se comporta como «al
       principio» cuando NO caben. Sin el `safe`, al desbordar el contenido, la parte que sobra
       por la IZQUIERDA queda inalcanzable: no hay forma de llegar a la primera tarjeta.
       Comprobado en Chrome: con 4 tarjetas y `center` a secas, la primera queda a −373 px.
       Un navegador que no entienda `safe` descarta la línea y se queda alineado a la izquierda:
       degrada a lo de antes, no rompe nada. */
    justify-content: safe center;
    scroll-snap-type: x mandatory;
    /* Evita que al llegar al final el navegador lo tome por el gesto de «atrás». */
    overscroll-behavior-x: contain;
    /* La barra se oculta: el asomo de la tarjeta vecina ya dice que hay más contenido. */
    scrollbar-width: none;
}
.villas__pista::-webkit-scrollbar { display: none; }
.villas__pista:focus-visible { outline: 2px solid var(--gold); outline-offset: 4px; }

.villa {
    flex: 0 0 min(93%, 34rem);
    min-width: 0;              /* la regla de Flex de AD-04: sin esto no encoge */
    /* Toda la tarjeta abre la villa. `relative` es el anclaje del enlace estirado de más abajo
       (`.villa__cta::after`), y el cursor avisa de que se puede pulsar en cualquier punto. */
    position: relative;
    cursor: pointer;
    scroll-snap-align: center;
    display: flex;
    flex-direction: column;
    background: #fff;
    border: 1px solid var(--divider);
    border-top: 3px solid var(--gold);
    overflow: hidden;
}

/* ---- Fotos apiladas que se cruzan ---- */
/* Cuando solo hay UNA villa, la tarjeta crece: 32 rem centradas en una pantalla ancha se ven
   pequeñas y perdidas. Es el escenario con el que arranca Ángel, así que conviene que luzca. */
.villa:only-child { flex-basis: min(93%, 40rem); }

.villa__fotos {
    position: relative;
    aspect-ratio: 4 / 3;
    background: var(--cream-deep);
}
.villa__foto {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    transition: opacity 1.2s ease;
}
.villa__foto.is-activa { opacity: 1; }
/* Villa sin fotos: marco neutro con el rombo de la marca insinuado, nunca un hueco roto. */
/* ── Banda «Próximamente» (PX-03) ──
   Franja horizontal sobre la foto, no un lazo diagonal: se lee de un vistazo, no recorta el texto
   en alemán («Demnächst») y no necesita rotaciones que descuadren en móvil. */
.villa__banda {
    position: absolute;
    top: 1rem;
    left: 0;
    /* 🔑 **Por encima de las fotos.** Se apilan en `position: absolute` dentro de este mismo
       contenedor, así que sin `z-index` la banda quedaría DEBAJO de la foto activa. */
    z-index: 2;
    margin: 0;
    padding: 0.45rem 1.25rem 0.45rem 1rem;
    background: var(--charcoal-soft);
    color: var(--on-dark);
    font-size: 0.8rem;
    font-weight: 700;
    /* Sin `text-transform: uppercase` (decidido con Andrés, 22-ago-2026): las mayúsculas gritaban
       y no encajan con el registro del sitio. El texto sale de `lang/*.php` tal cual se escribió
       —«Próximamente», «Coming soon», «Demnächst»—, así que **la mayúscula inicial la decide cada
       idioma**, no el CSS.
       ⚠️ Y con el espaciado más corto: 0,08em es de versalitas; en minúscula separa demasiado. */
    letter-spacing: 0.03em;
    /* Pegada al borde izquierdo y redondeada solo por dentro: parece una etiqueta puesta encima
       de la foto, no un rectángulo flotando. */
    border-radius: 0 3px 3px 0;
}

.villa__fotos--vacio {
    background:
        linear-gradient(135deg, transparent 47%, rgba(184,148,95,0.25) 47%, rgba(184,148,95,0.25) 53%, transparent 53%),
        var(--cream-deep);
}

.villa__cuerpo {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    padding: 1.5rem 1.5rem 1.75rem;
}
.villa__nombre {
    margin: 0 0 0.4rem;
    font-family: 'Charm', cursive;
    font-weight: 400;
    font-size: 1.3rem;
    line-height: 1.2;
    color: var(--charcoal);
}
.villa__precio {
    /* Aire por arriba para separarlo del nombre de la villa: son dos cosas distintas y pegadas
       se leían como un bloque. */
    margin: 0.9rem 0 1.25rem;
    color: var(--text-muted);
    font-size: 0.88rem;
}
.villa__precio strong {
    color: var(--brown);
    /* Charm, como el botón y los títulos. Sube de cuerpo porque una manuscrita se lee más
       pequeña que una de palo seco al mismo tamaño nominal.
       Se retira `tabular-nums`: Charm no trae cifras de ancho fijo y pedirlas no haría nada;
       aquí tampoco hace falta, porque es un número suelto, no una columna que alinear. */
    font-family: 'Charm', cursive;
    font-weight: 400;
    font-size: 1.15rem;
    line-height: 1;
}
.villa__unidad { color: var(--text-muted); }

.villa__servicios {
    margin: 0 0 1.5rem;
    padding: 0;
    list-style: none;
    border-top: 1px solid var(--divider);
}
.villa__servicio {
    display: flex;
    align-items: center;
    /* Cuando nombre y precio no caben en una línea, el precio BAJA a su propio renglón en vez de
       disputarle el sitio al nombre. Sin esto, un precio muy ancho —el peor caso medido:
       «15 € / durch den Verbrauch», 163px de 171 disponibles— dejaba la caja del nombre en 7px y
       el texto se salía por encima. `overflow-wrap` no salva eso: no hay hueco ni para una letra. */
    flex-wrap: wrap;
    /* Poco aire entre renglones (el primer valor) y el de siempre entre columnas (el segundo):
       el precio caído debe leerse pegado a SU servicio, no flotando entre dos. */
    gap: 0.2rem 0.75rem;
    padding: 0.55rem 0;
    border-bottom: 1px solid var(--divider);
    font-size: 0.85rem;
}
.villa__icono {
    flex: 0 0 auto;
    width: 24px;
    height: 24px;
    object-fit: contain;
}
.villa__servicio-nombre {
    flex: 1 1 auto;
    /* 🔑 EL SUELO QUE DISPARA EL SALTO DE LÍNEA. Antes era `min-width: 0`, que dejaba encoger la
       caja hasta cero: el nombre, por ser el único elástico de la fila, absorbía TODO el recorte
       mientras el precio (`flex: 0 0 auto` + `nowrap`) no cedía ni un píxel.
       Con un suelo de 8 caracteres, cuando nombre y precio no caben juntos el `flex-wrap` del
       padre manda el precio al renglón siguiente en vez de aplastar el nombre. */
    min-width: 8ch;
    /* …pero encoger la CAJA no reparte el TEXTO. Con un nombre de una sola palabra sin puntos de
       corte —«Wäscheservice», «Lavandería»— no hay dónde partir, así que el texto se salía de su
       caja y aterrizaba encima del precio, que va pegado a la derecha con `nowrap`.
       Medido antes del arreglo: en alemán a 344px «Wäscheservice» se salía 86px, y seguía saliéndose
       49px hasta en un iPhone de 390. También pasaba en español e inglés en pantallas estrechas.
       `anywhere` autoriza el corte DENTRO de la palabra sólo cuando no hay otro remedio; con
       `break-word` el navegador puede decidir no partirla y el desbordamiento vuelve. */
    overflow-wrap: anywhere;
    color: var(--text);
}
.villa__servicio-precio {
    flex: 0 0 auto;
    /* Pegado a la derecha SIEMPRE, esté en la misma línea que el nombre o haya caído al renglón
       de abajo. En la primera línea es redundante (el nombre ya empuja al crecer), pero en la
       segunda es lo único que evita que el precio aparezca alineado a la izquierda, debajo del
       nombre y leyéndose como si fuera otra cosa. */
    margin-left: auto;
    color: var(--text-muted);
    font-size: 0.8rem;      /* la UNIDAD y «Incluido», en la tipografía de lectura */
    white-space: nowrap;
}
/* Solo la cifra —número, € y la barra— en Charm. Sube de cuerpo porque una manuscrita se lee
   más pequeña que una de palo seco al mismo tamaño nominal. */
.villa__cifra {
    color: var(--brown);
    font-family: 'Charm', cursive;
    font-size: 0.92rem;
    line-height: 1;
}

/* Aviso de que quedan servicios fuera de la tarjeta. Va en cursiva y en tono apagado: es una
   invitación, no un dato más de la lista. */
.villa__mas {
    margin: -0.5rem 0 1.4rem;
    color: var(--text-muted);
    font-size: 0.92rem;
    font-style: italic;
    line-height: 1.55;
}

/* `margin-top: auto` empuja el botón al fondo: con villas de 5 y de 6 servicios, los botones
   quedan alineados entre tarjetas en vez de bailar según el contenido. */
.villa__cta {
    margin-top: auto;
    align-self: flex-start;
    padding: 0.6rem 2rem;
    background: var(--brown);
    border: 1px solid var(--brown);
    border-radius: 2px;
    color: var(--on-dark);
    /* Charm, como el resto de la voz de marca. Y por eso SIN mayúsculas ni letras separadas:
       una tipografía manuscrita en versalitas y con `letter-spacing` se vuelve ilegible. */
    font-family: 'Charm', cursive;
    font-weight: 400;
    font-size: 1.1rem;
    line-height: 1.2;
    letter-spacing: normal;
    text-transform: none;
    text-decoration: none;
    transition: background-color 0.2s ease;
}
/* ---- Enlace estirado: la tarjeta entera es pulsable ----
   Un pseudo-elemento del PROPIO botón se estira sobre toda la tarjeta. El botón sigue ahí y se ve
   igual; lo que cambia es su zona sensible.

   ⚠️ **Por qué no se envuelve la tarjeta en un `<a>`**, que sería lo primero que uno piensa: es
   HTML válido, pero el nombre accesible del enlace pasaría a ser TODO el contenido de la tarjeta —
   un lector de pantalla anunciaría «enlace: Villa Tal, desde 320 €, noche, Desayuno, 50 €, día,
   Lavandería…» de un tirón. Así el enlace sigue teniendo un nombre corto («Ver la villa X», el
   `aria-label` de VP-03) y en el árbol de accesibilidad hay UN solo enlace, no dos.

   Efecto secundario buscado: como el pseudo-elemento forma parte del botón, pasar el ratón por
   cualquier punto de la tarjeta activa su `:hover` y el botón se oscurece — el aviso visual sale
   gratis, sin una regla aparte.

   Peaje asumido: dentro de la tarjeta ya no se puede seleccionar el texto con el ratón. Es el
   precio conocido de este patrón y aquí no molesta: no hay nada que copiar. */
.villa__cta::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
}

.villa__cta:hover,
.villa__cta:focus-visible { background: var(--charcoal); border-color: var(--charcoal); }

/* ---- Flechas: solo en escritorio ---- */
.villas__flecha { display: none; }

/* ⚠️ Los escalones del título van AQUÍ, después de su regla base, y no junto a los del hero.
   Un `@media` NO añade especificidad: si la regla base se declara después, gana ella aunque la
   del media query sea «más concreta». Como el bloque VP-03 está al final del archivo, poner
   `.villas__titulo` en los @media del hero (más arriba) no tenía ningún efecto. */
@media (min-width: 768px) {
    .villas__titulo { font-size: 1.6rem; }
    .villas__intro  { font-size: 1.2rem; }
}

@media (min-width: 1024px) {
    .villas { scroll-margin-top: 4.5rem; }   /* la barra es más baja en escritorio */
    .villas__titulo { font-size: 1.8rem; }
    .villas__intro  { font-size: 1.35rem; }
    .villas__pista { padding-left: 5%; padding-right: 5%; }
    .villa { flex-basis: 32rem; }
    .villa:only-child { flex-basis: 40rem; }

    /* ⚠️ `:not([hidden])` NO es un adorno.
       El navegador oculta los elementos con `hidden` mediante `[hidden] { display: none }` en su
       hoja INTERNA, y las reglas del autor siempre le ganan. Sin este `:not(...)`, este
       `display: block` pisaba el atributo y las flechas se veían en escritorio y tableta aunque
       el JS las hubiera marcado como ocultas por no haber nada que desplazar.
       En móvil no se notaba: allí la regla base es `display: none` y nadie la contradice. */
    .villas__flecha:not([hidden]) {
        display: block;
        position: absolute;
        top: 45%;
        z-index: 2;
        width: 3.25rem;
        height: 3.25rem;
        background: #fff;
        border: 1px solid var(--divider);
        border-radius: 50%;
        cursor: pointer;
        /* DOS sombras, no una: la primera, corta y densa, da el filo; la segunda, amplia y
           difusa, despega el botón del fondo. Una sola sombra grande deja un borrón gris, y una
           sola corta no levanta nada. Y en tono carbón —el de la marca— en vez de negro puro,
           que sobre el crema se ve sucio. */
        box-shadow: 0 1px 2px rgba(31, 29, 26, 0.16),
                    0 6px 16px rgba(31, 29, 26, 0.18);
        transition: box-shadow 0.2s ease, transform 0.2s ease, background-color 0.2s ease;
    }
    .villas__flecha:hover {
        background: #fff;
        /* Al pasar por encima sube un pelo y la sombra crece: el botón «se levanta». */
        transform: translateY(-2px);
        box-shadow: 0 2px 4px rgba(31, 29, 26, 0.18),
                    0 10px 24px rgba(31, 29, 26, 0.24);
    }
    /* Al pulsar vuelve abajo: sin esto, el botón se queda flotando y el clic no «responde». */
    .villas__flecha:active {
        transform: translateY(0);
        box-shadow: 0 1px 2px rgba(31, 29, 26, 0.2);
    }
    .villas__flecha:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
    /* La punta de flecha: un cuadrado girado 45° con dos lados. Sin imágenes ni iconos. */
    .villas__flecha::before {
        content: "";
        position: absolute;
        top: 50%;
        left: 50%;
        width: 0.7rem;
        height: 0.7rem;
        border-top: 2px solid var(--brown);
        border-right: 2px solid var(--brown);
    }
    .villas__flecha--prev { left: 1.5rem; }
    .villas__flecha--prev::before { transform: translate(-30%, -50%) rotate(-135deg); }
    .villas__flecha--next { right: 1.5rem; }
    .villas__flecha--next::before { transform: translate(-70%, -50%) rotate(45deg); }
}

/* ---- Menos movimiento: se apagan los DOS automatismos ---- */
@media (prefers-reduced-motion: reduce) {
    .villas__pista { scroll-behavior: auto; }
    .villa__foto   { transition: none; }
    /* La sombra sí se queda —es realce, no movimiento—, pero el salto del botón se retira. */
    .villas__flecha,
    .villas__flecha:hover { transform: none; transition: box-shadow 0.2s ease; }
}

/* ============================================================
   VP-05 — El pasillo: sección anclada con zoom por scroll
   ============================================================ */
.pasillo {
    /* El «depósito» de scroll. Los 180vh son 100 de imagen en pantalla + 80 de recorrido para el
       zoom. Más que esto empieza a sentirse que la página te secuestra. */
    /* 340vh = 100 de imagen en pantalla + 240 de recorrido para el zoom. Cuanto más alta, más
       despacio y más largo se siente el acercamiento. */
    height: 340vh;
    /* Altura de la IMAGEN, que ahora es también la del marco. Vive aquí (y no en el marco) para
       que los `@media` puedan cambiarla en un solo sitio; el marco la hereda.
       · TECHO 92dvh — pantalla más ancha que alta: la altura que pediría el 90% de ancho no cabe.
       · SUELO 88dvh — pantalla muy estrecha y alta (Galaxy Fold): sin él la imagen sale corta.
       En un móvil normal la proporción de la foto cae entre los dos y no recorta nada. */
    --alto-pasillo: clamp(88dvh, calc(90vw * 1497 / 704), 92dvh);
    /* Crema, como el resto del sitio: la sección NO se separa del recorrido de la página.
       Se probó en carbón (la foto leída como cuadro iluminado en una sala oscura) y Andrés lo
       descartó: cortaba el hilo entre las villas y los servicios. En crema, lo que ocurre es
       que **la propia foto es la que oscurece**, sin que la página cambie de mundo. */
    background: var(--cream);
    /* 🔑 La línea de tiempo se ata A LA SECCIÓN, no a la imagen.
       La imagen vive dentro de un contenedor `sticky`: mientras está pegada NO se mueve respecto
       a la ventana, así que un `view()` sobre ella se queda congelado en un progreso fijo — se
       midió y devolvía siempre la misma escala, 1,125, en todo el recorrido.
       La sección sí atraviesa la pantalla, y es la que marca el avance. */
    view-timeline-name: --pasillo;
    view-timeline-axis: block;
}

/* El marco se queda pegado arriba mientras se recorre la sección, y se suelta al acabarla.
   `100dvh` y no `100vh`: en móvil, `vh` no descuenta la barra del navegador y la imagen quedaría
   cortada por abajo — el mismo motivo por el que el hero usa `dvh`. */
.pasillo__marco {
    position: sticky;
    /* 🔑 EL MARCO MIDE LO QUE LA IMAGEN, no la pantalla entera.
       Antes era `top: 0; height: 100dvh` con la imagen centrada dentro: como la imagen ocupa el
       88–92% de la altura, sobraba un 4–6% de crema ARRIBA y otro tanto ABAJO — unos 50 px por
       lado. Ese sobrante no se ve en el código (son cajas, no píxeles pintados) pero SÍ en
       pantalla, y se sumaba al `--aire-seccion` de las secciones vecinas: el pasillo y los
       servicios parecían tener el doble de margen que las villas aunque los tres midieran 56 px.
       Ahora el marco ES la imagen, y el centrado en pantalla lo da el `top` del sticky. Mismo
       efecto a la vista, sin caja fantasma alrededor. */
    top: calc((100dvh - var(--alto-pasillo)) / 2);
    height: var(--alto-pasillo);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;          /* al crecer, la imagen no debe desbordar la ventana */
}

/* ---- La ventana: el marco por el que se mira ----
   Su tamaño NO cambia en todo el recorrido. Es quien recorta, así que el crecimiento de la
   imagen se percibe como acercamiento y no como un rectángulo ensanchándose.

   📱 En MÓVIL manda el ANCHO: 90% de la pantalla, y la altura sale de la proporción de la foto.
   Antes mandaba la altura (92% de la pantalla) y el ancho salía de ahí — en un móvil normal eso
   dejaba la ventana en torno al 70% del ancho, bastante más estrecha de lo que se quería.
   (Se probó al 95% y quedaba demasiado justo a los bordes; el 90% deja respirar la imagen.)
   El `clamp()` tiene un TECHO y un SUELO, y cada uno resuelve un móvil distinto:
     · TECHO 92dvh — pantalla más ancha que alta (móvil girado, ventana baja): la altura que
       pediría el 90% de ancho no cabe, así que se topa y el `cover` recorta arriba y abajo.
       Sin él la sección se desbordaría.
     · SUELO 88dvh — pantalla MUY ESTRECHA y alta (Galaxy Fold plegado, 344×882). Ahí el 90% de
       ancho son solo 310 px, la altura que le toca por proporción se queda corta, y como la
       imagen va centrada sobraba un dedo de crema arriba y otro abajo. Con el suelo la imagen
       llena la pantalla igual que en cualquier móvil y el `cover` recorta un poco por los lados.
   En un móvil normal la proporción de la foto cae justo entre los dos, así que no recorta nada:
   el `clamp` solo actúa en los extremos. */
.pasillo__ventana {
    width: 90%;
    height: 100%;              /* la altura ya la fija el marco con `--alto-pasillo` */
    max-width: 90%;
    overflow: hidden;
}

.pasillo__img {
    /* `cover` y no `contain`: la imagen RELLENA la ventana. En móvil, al tener la ventana la
       proporción exacta de la foto, cubrir y contener dan lo mismo — no se pierde nada. */
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* El zoom final, como variable: la ventana de escritorio es mucho más ancha, así que allí la
       imagen ya parte más cerca y el mismo factor llega mucho más lejos. Se ajusta por tramo. */
    --zoom-final: 2;
    /* El zoom apunta al EMBLEMA. Medido sobre el archivo: el rombo ocupa 448×334 px y su centro
       cae al 49% horizontal y 50% vertical — o sea, prácticamente el centro geométrico.
       (Mi primera estimación a ojo, 47%, estaba desviada; esta sale de medir el brillo del cartel.) */
    transform-origin: 50% 50%;
    will-change: transform;
}

/* ---- El zoom, dirigido por el scroll ----
   `animation-timeline: view()` ata el avance de la animación a la posición de la sección dentro de
   la ventana: no hay JavaScript, ni escucha de `scroll`, ni cálculos en cada fotograma. Lo lleva
   el compositor del navegador.
   `animation-range` acota el tramo: empieza cuando la sección entra del todo y termina antes de
   que salga, para que el zoom ocurra mientras la imagen está pegada y no a medio entrar. */
/* El zoom no ocupa todo el recorrido: se queda quieto mientras la sección entra, crece durante
   el tramo en que está pegada, y se queda quieto mientras sale. Así el efecto ocurre cuando la
   imagen llena la pantalla, que es cuando se ve. */
/* Los porcentajes acotan el zoom al tramo en que la imagen está PEGADA; antes y después la
   sección está entrando o saliendo y la imagen se queda quieta.
   📐 Si se cambia la altura de la sección hay que recalcularlos, y la fórmula es sencilla. Para
   una sección de N×vh, el recorrido `cover` mide (N+1)×vh, así que:
        inicio = 1 / (N+1)        fin = N / (N+1)
   Con N = 3,4 → 1/4,4 = 23% y 3,4/4,4 = 77%.
   (No depende del tamaño de la pantalla: al estar la altura en `vh`, la proporción es constante.) */
@keyframes pasillo-zoom {
    0%,  23%  { transform: scale(1); }
    77%, 100% { transform: scale(var(--zoom-final)); }
}

@supports (animation-timeline: view()) {
    .pasillo__img {
        animation: pasillo-zoom linear both;
        animation-timeline: --pasillo;
        /* `cover` = todo el tiempo que la sección toca la pantalla, de entrar a salir.
           ⚠️ Dos rangos que NO funcionan aquí, y cuestan de diagnosticar porque no dan error:
             · `contain` describe «la sección cabe entera en la ventana» — con 180vh no ocurre
               NUNCA, así que el rango es vacío y la escala se queda clavada.
             · `entry 100% exit 0%` parece lo lógico («desde que ha entrado hasta que empieza a
               salir»), pero en un elemento MÁS ALTO que la ventana esos dos hitos van al revés:
               `exit 0%` sucede antes que `entry 100%` → tramo de longitud negativa, sin animación.
           Con `cover` el recorrido siempre existe, y el reparto lo hacen los fotogramas. */
        animation-range: cover;
    }
}

@media (min-width: 768px) {
    /* En tablet y escritorio la ventana se ENSANCHA (0,60 en vez de 0,47 de la foto) para que la
       imagen no arranque como una columna estrecha. Al rellenar con `cover`, eso recorta arriba y
       abajo alrededor de un 27% por lado — decisión de Andrés: prefiere presencia a conservar el
       techo y el suelo. **Las paredes convergiendo se mantienen enteras**, que es lo único
       imprescindible: son las que sostienen la perspectiva y el efecto de avanzar.
       Aquí manda de nuevo la ALTURA (al revés que en móvil): `width: auto` deja que la proporción
       9/10 derive el ancho, y el `max-width` hace de tope en ventanas muy bajas.
       ⚠️ El `max-width` se REPONE al 95% a propósito: el bloque base bajó al 90% por el móvil, y
       en tablet vertical ese tope es justo el que manda (la altura pediría más ancho del que hay).
       Sin esta línea, ajustar el móvil habría estrechado la tablet de rebote. */
    .pasillo          { --alto-pasillo: 88dvh; }
    .pasillo__ventana { width: auto; height: 100%; aspect-ratio: 9 / 10; max-width: 95%; }
    /* Menos zoom aquí que en móvil: con la ventana a 9/10 la imagen ya arranca recortada y
       cercana, así que un 1,4 recorre lo mismo que un 2 en la ventana estrecha del móvil.
       Además mantiene la nitidez: por encima de 1,5 la foto empieza a estirarse de verdad. */
    .pasillo__img { --zoom-final: 1.4; }
}

/* ---- Menos movimiento: sin anclaje y sin zoom ----
   Un elemento que crece mientras se hace scroll es de los efectos que más malestar provocan a
   quien tiene sensibilidad vestibular. Aquí no se suaviza: se retira. La sección pasa a ser una
   imagen normal, a pantalla y sin más.

   ⚠️ Va DESPUÉS del bloque de escritorio a propósito. Las dos son media queries, así que tienen la
   MISMA especificidad y gana la última: estando antes, un escritorio con «menos movimiento» volvía
   a recibir `height: 88%` y `aspect-ratio: 9/10` sobre un marco ya sin altura, y la ventana se
   descuadraba. Por eso también se reponen aquí `width` y `aspect-ratio`, no solo la altura. */
@media (prefers-reduced-motion: reduce) {
    .pasillo            { height: auto; padding: 3rem 0; }
    .pasillo__marco     { position: static; height: auto; }
    .pasillo__ventana   { width: 95%; height: auto; aspect-ratio: auto; max-height: 80vh; }
    .pasillo__img       { height: auto; max-height: 80vh; width: 100%; animation: none; transform: none; }
}


/* ============================================================
   SV-04 — Sección «Servicios» (última del home)
   Rejilla de 1 / 2 / 3 columnas. El encabezado repite el patrón de «Nuestras villas» (Prata
   para el título, Charm para la frase): son la misma voz y deben sonar igual.
   ============================================================ */
.servicios {
    /* El mismo `--aire-seccion` que villas: las tres secciones del recorrido arrancan igual. */
    padding: var(--aire-seccion) 0 3.5rem;
    background: var(--cream);
    /* Mismo valor que `.villas`, porque es la ALTURA DE LA BARRA fija y nada más — no una
       compensación del padding. Con las dos secciones usando `--aire-seccion` no hay nada que
       compensar, y el número vuelve a significar lo que dice. */
    scroll-margin-top: 6.5rem;
}
.servicios__cabecera {
    max-width: 70ch;
    margin: 0 auto 1.75rem;
    padding: 0 1.5rem;
    text-align: center;
}
.servicios__titulo {
    margin: 0 0 0.75rem;
    font-family: var(--display-font);
    font-weight: 400;
    font-size: 1.45rem;
    line-height: 1.25;
    color: var(--brown);
}
.servicios__intro {
    margin: 0;
    color: var(--text);
    font-family: 'Charm', cursive;
    font-size: 1.1rem;
    line-height: 1.5;
}

/* ---- La rejilla ----
   🔑 FLEX Y NO GRID, y no es indiferente. Con `grid: repeat(3, 1fr)`, si Ángel marca 5 servicios
   la última fila deja dos tarjetas pegadas a la izquierda y un hueco a la derecha. Es exactamente
   lo que se corrigió en el carrusel de villas («que se vea centrado siempre, sea una, dos o 10»).
   Con flex + `justify-content: center`, la fila incompleta se centra sola.

   El número de columnas es UNA VARIABLE y el ancho de la tarjeta se deriva de ella: así cada
   escalón cambia un solo número en vez de repetir el `calc` tres veces (y desincronizarlo). */
.servicios__rejilla {
    --columnas: 1;
    --hueco: 1.5rem;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--hueco);
    /* Tope de 75rem: el tramo de 3 columnas llega hasta cualquier ancho, y sin freno las tarjetas
       crecerían sin fin en un monitor de 2560 px. Con el tope se quedan en ~384 px. */
    max-width: 75rem;
    margin: 0 auto;
    padding: 0 1.5rem;
}
.servicio {
    /* Entre N tarjetas hay N-1 huecos: por eso se restan antes de repartir. */
    flex: 0 0 calc((100% - (var(--columnas) - 1) * var(--hueco)) / var(--columnas));
    min-width: 0;              /* la regla de Flex de AD-04: sin esto no encoge y desborda */
    display: flex;
    flex-direction: column;
    /* Blanco y filete fino, como las tarjetas de villa, pero SIN el remate dorado de arriba
       (decisión de Andrés): con hasta 15 tarjetas juntas, ese trazo repetido pesaba demasiado.
       En el carrusel funciona porque son tres o cuatro y muy grandes; aquí serían una reja. */
    background: #fff;
    border: 1px solid var(--divider);
    overflow: hidden;
}
.servicio__cabeza {
    padding: 1.25rem 1.25rem 1rem;
    text-align: center;
}
.servicio__nombre {
    /* Tipografía de LECTURA, no Charm (decisión de Andrés): son nombres cortos que se repiten
       hasta 15 veces, y una manuscrita en bloque cansa. Charm se reserva para las frases de marca. */
    margin: 0 0 0.75rem;
    font-weight: 700;
    font-size: 1rem;
    line-height: 1.3;
    letter-spacing: 0.02em;
    color: var(--charcoal);
}
.servicio__icono {
    display: block;
    width: 40px;
    height: 40px;
    margin: 0 auto;
    object-fit: contain;       /* los 16 son cuadrados; `contain` respeta el que no lo fuera */
}
.servicio__foto {
    display: block;
    width: 100%;
    height: auto;
    /* Las fotos subidas van de 1,0 a 1,87 de proporción (medido). Sin imponer una, cada tarjeta
       tendría una altura de imagen distinta y la rejilla saldría dentada. Se elige 3/2 porque es
       la proporción más frecuente entre las subidas → la que menos recorta. */
    aspect-ratio: 3 / 2;
    object-fit: cover;
}
/* Precio de la tarjeta · SOLO se pinta dentro de una ficha de villa: en la portada no hay villa
   elegida y por tanto no hay precio que mostrar. Se separa del texto con un filete para que no se
   lea como una línea más de la descripción. */
.servicio__precio {
    margin: auto 0 0;                  /* `auto` arriba: se pega abajo aunque las tarjetas midan distinto */
    padding: 0.7rem 1.25rem 1.1rem;
    border-top: 1px solid var(--divider);
    color: var(--text-muted);
    font-size: 0.85rem;
    text-align: center;
}
.servicio__cifra {
    color: var(--brown);
    font-family: 'Charm', cursive;
    font-size: 1.05rem;
    line-height: 1;
}

.servicio__texto {
    margin: 0;
    padding: 1.1rem 1.25rem 1.5rem;
    color: var(--text);
    /* Charm, como la frase de entrada de la sección y la de villas: aquí la descripción deja de
       ser una ficha técnica y pasa a sonar como la voz de la marca.
       Sube de cuerpo respecto al palo seco que había (0,98 → 1,2 rem) porque Charm tiene la
       x-height pequeña y al mismo tamaño nominal se lee bastante más chica — el mismo ajuste que
       ya se hizo en `.villas__intro`. */
    font-family: 'Charm', cursive;
    font-size: 1.1rem;
    line-height: 1.45;
    text-align: center;
}

/* ⚠️ Los escalones van DESPUÉS de las reglas base: un `@media` NO añade especificidad, así que
   una regla base declarada más abajo le ganaría. Ya pasó dos veces con `.villas__titulo`. */
@media (min-width: 768px) {
    .servicios__rejilla { --columnas: 2; }
    .servicios__titulo  { font-size: 1.6rem; }
    .servicios__intro   { font-size: 1.2rem; }
}

@media (min-width: 1024px) {
    .servicios__rejilla { --columnas: 3; }
    .servicios          { scroll-margin-top: 4.5rem; }   /* la barra es más baja en escritorio */
    .servicios__titulo  { font-size: 1.8rem; }
    .servicios__intro   { font-size: 1.35rem; }
}


/* ============================================================
   SEO-00·b — Bloque de texto de la portada (entre el carrusel y el pasillo)
   ============================================================ */
.intro-seo {
    background: var(--cream);
    /* ⚠️ EL AIRE DE ABAJO NO ES DECORATIVO: es el hueco que precede al PASILLO, que no tiene
       padding propio. Antes lo ponía el `padding-bottom` de `.villas`; al colocarse este bloque
       entre las dos, el papel pasó aquí. Si se quita, el pasillo nace pegado al texto. */
    margin-bottom: var(--aire-seccion);
}
.intro-seo__cuerpo {
    /* EXACTAMENTE los mismos números que `.villa-ficha__cuerpo` (villa.css) y que la tarjeta de
       servicios. No es casualidad: son los dos bloques de prosa larga del sitio y deben tener la
       misma medida de columna, o al pasar de la portada a la ficha el texto parece encogerse. */
    width: 80%;
    max-width: 46rem;
    margin: 0 auto;
}
.intro-seo__parrafo {
    margin: 0 0 1rem;
    color: var(--text);
    /* 🔤 PRUEBA DE TIPOGRAFÍA (17-ago-2026): se pasa de Prata a Lato para ver cómo queda.
       Prata era decisión de marca de Andrés (ago-2026), pero iba contra lo que dice el propio
       `:root` de main.css: «Prata es de alto contraste → cansa la vista en párrafos largos; Lato
       es humanista y legible». Y estos son los DOS bloques de prosa larga del sitio.
       Los TITULARES siguen en Charm: lo que cambia es solo el cuerpo. */
    font-family: var(--default-font);
    /* Sube un pelo: Prata tiene la x-height muy grande y Lato, al mismo cuerpo nominal, se lee
       algo más pequeña. Sin este ajuste el cambio parecería un encogimiento del texto. */
    font-size: 1.05rem;
    line-height: 1.7;
    /* Justificado + partición, igual que en la ficha. `hyphens` NO es opcional: sin él, el
       justificado abre huecos enormes: en alemán, con sus palabras compuestas, es donde peor se ve.
       El navegador solo sabe partir si conoce el idioma, y lo sabe (`head.php` pone `lang`). */
    text-align: justify;
    hyphens: auto;
}
.intro-seo__parrafo:last-child { margin-bottom: 0; }

/* La pregunta que abre la segunda mitad del bloque (texto de Ángel, 22-ago-2026).
   Charm y `--brown`, como los títulos de «Nuestras villas» y «Nuestros servicios»: es un titular
   más del recorrido de la portada y tiene que leerse como tal.
   ⚠️ `text-align: left` explícito — el bloque va justificado, y un titular justificado en un
   renglón corto abre huecos absurdos entre palabras. */
.intro-seo__pregunta {
    margin: 1.75rem 0 1rem;
    font-family: 'Charm', cursive;
    font-weight: 400;
    font-size: 1.35rem;
    line-height: 1.3;
    color: var(--brown);
    text-align: left;
}

/* El cierre es la llamada a la acción: mismo cuerpo que el texto pero destacado y CENTRADO.
   Sin justificar: es una línea suelta, no prosa — justificarla abriría huecos entre palabras. */
.intro-seo__cierre {
    margin: 1.5rem 0 0;
    color: var(--brown);
    font-family: var(--default-font);
    font-size: 1.05rem;
    line-height: 1.6;
    font-weight: 700;
    text-align: center;
}

@media (min-width: 768px) {
    .intro-seo__pregunta { font-size: 1.5rem; }
}


/* ============================================================
   SEO-01·b — PROPIEDADES de la villa (ficha técnica + registros)
   Se pintan dentro de la misma tarjeta que los servicios, después de ellos.
   ============================================================ */

/* 🔗 LAS DOS LISTAS SON UNA SOLA FICHA (17-ago-2026, Andrés). El `margin-bottom` de 1.5rem que
   `.villa__servicios` da a toda lista abría un hueco entre propiedades y servicios que las hacía
   leer como dos tablas distintas. Se anula SOLO cuando hay servicios detrás: si la lista de
   propiedades es la última, su aire de abajo sigue haciendo falta para separarla del «y más
   servicios» y del botón.
   `:has()` es lo que permite preguntar «¿tengo un hermano detrás?». Un navegador que no lo
   entienda descarta la regla y vuelve al hueco de antes: degrada, no rompe. */
.villa__propiedades:has(+ .villa__servicios) {
    margin-bottom: 0;
}

/* ⚠️ EL FILETE CAMBIÓ DE LISTA EL 17-ago-2026, al pasar las propiedades DELANTE de los servicios.
   La regla de fondo no ha cambiado: **la raya la lleva la PRIMERA lista y no la segunda**, porque
   la de arriba ya termina con el `border-bottom` de su último renglón y, a 1.5rem de distancia,
   dos líneas paralelas se leen como un error de maqueta. Lo que separa los bloques es el AIRE.
   Por eso `.villa__propiedades` ya NO anula su borde (ahora es la primera) y sí lo anula la lista
   de servicios cuando viene detrás de ella. */
.villa__propiedades + .villa__servicios {
    border-top: none;
}

.villa__propiedad-valor {
    /* Hermana de `.villa__servicio-precio` —mismo sitio, mismo peso visual— pero NO la misma
       clase, por una diferencia que importa:
       🔑 aquella lleva `white-space: nowrap` para que un precio no se parta por la mitad; aquí el
       valor puede ser «San Bartolomé de Tirajana», que TIENE que poder partir o se sale de la
       tarjeta en móvil. Por eso `flex-shrink` es 1 (puede encoger) y no 0. */
    flex: 0 1 auto;
    margin-left: auto;
    color: var(--text-muted);
    font-size: 0.8rem;
    /* A la derecha también cuando ocupa dos renglones: alineado a la izquierda se leería como si
       fuera otro dato distinto y no el valor de su etiqueta. */
    text-align: right;
    /* Un topónimo largo sin espacios donde partir se saldría igual. Mismo remedio que ya hizo
       falta en `.villa__servicio-nombre` con «Wäscheservice». */
    overflow-wrap: anywhere;
}

/* ---- Registros turísticos: letra legal, y tiene que parecerlo ---- */
.villa__registros {
    /* No lleva filete, por lo mismo que las listas de arriba: lo que lo separa del resto es el AIRE
       y el TAMAÑO — se lee como una nota al pie, que es lo que es.

       ➡️ A LA DERECHA (17-ago, Andrés). Encaja con la columna de valores de la ficha —que ya va a la
       derecha— y despeja el flanco izquierdo, donde mandan los iconos. Alinea las DOS inscripciones,
       la canaria y la estatal: son el mismo bloque legal y separarlas a lados distintos las haría
       parecer cosas sin relación.

       🔑 `margin-top: auto` — ESTE BLOQUE ES EL QUE SE APOYA EN EL FONDO (17-ago, opción B).
       Antes el `auto` lo llevaba `.villa__cta`, y con un bloque de alto VARIABLE debajo el botón
       quedaba a distinta altura en cada villa: medido 1063px con dos registros, 1093 con uno y 1138
       sin ninguno. Pasándole el `auto` aquí, el botón queda el ÚLTIMO y cae siempre en el mismo
       punto — se alinean por ESTRUCTURA, sin reservar ningún alto a mano ni números mágicos.

       ⚠️ Y EL AIRE DE ARRIBA VA EN `padding`, NO EN `margin`. Con `margin-top: auto` no hay forma de
       garantizar un mínimo: en la tarjeta MÁS ALTA no sobra espacio libre, el `auto` se resuelve en
       0 y los registros se pegarían al último servicio. El `padding` se respeta siempre.

       ⚠️ Y ABAJO, NADA. La tarjeta ya trae su propio `padding-bottom`; con un margen aquí se sumaban
       los dos y dejaban ~48px de blanco muerto que hacían parecer que la tarjeta cerraba antes de
       donde acababa. */
    margin: auto 0 0;
    padding-top: 1.5rem;
    text-align: right;
}

/* El botón ya NO se apoya en el fondo cuando hay registros: lo hacen ellos, y él va detrás con su
   propia separación. Sin este reajuste habría DOS `margin-top: auto` en la misma columna flex, y el
   navegador REPARTE el espacio libre entre todos los `auto` — abriendo un hueco de más encima del
   botón y volviendo a desalinearlo.
   ⚠️ Cuando NO hay registros el selector no aplica y `.villa__cta` conserva su `auto`: se apoya en
   el fondo él solo. Las dos situaciones dejan el botón exactamente en el mismo sitio. */
.villa__registros ~ .villa__cta {
    margin-top: 1rem;
}

.villa__registro {
    margin: 0 0 0.6rem;
}
.villa__registro:last-child {
    margin-bottom: 0;
}
.villa__registro-etiqueta,
.villa__registro-numero {
    /* En BLOQUE: la etiqueta arriba y el número debajo. En la misma línea, un
       `VV-35-1-0001234` partiría por cualquier sitio en una columna de 306px. */
    display: block;
    color: var(--text-muted);
}
.villa__registro-etiqueta {
    /* Más pequeña aún (segundo ajuste, 17-ago). Es el texto MENOS importante de la tarjeta: está
       porque la ley obliga a publicarlo, no porque ayude a decidir. Su tamaño debe decir eso.
       ⚠️ 0.5rem = 8px es EL SUELO. Por debajo deja de leerse, y este dato es justo el que la ley
       exige PUBLICAR: hacerlo ilegible sería incumplir por otra vía. Si hiciera falta restarle
       más presencia, tocar el COLOR (más apagado), no el tamaño. */
    font-size: 0.5rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.villa__registro-numero {
    /* El número se deja un punto POR ENCIMA de su etiqueta: es el dato que alguien podría querer
       comprobar de verdad (un huésped, una inspección), y la etiqueta solo lo nombra. */
    font-size: 0.58rem;
    /* El número no tiene espacios: sin esto se sale de la tarjeta en pantallas estrechas. */
    overflow-wrap: anywhere;
}


/* ---- BOTÓN DE WHATSAPP EN LÍNEA (RV-02, mudado aquí en FAQ-04) ----
   Vivía en `villa.css` cuando solo lo usaba la ficha de villa. Ahora lo usan la ficha Y el FAQ,
   que cargan hojas distintas (`villa.css` / `page.css`), así que la única casa posible es esta:
   `main.css` se carga en todas las páginas. Se mueve TAL CUAL —ni un valor cambiado— y el orden
   del cascade no le afecta: ninguna otra hoja toca `.boton-reservar`. */
.boton-reservar {
    /* `inline-flex` y no `flex`: así el botón mide lo que su contenido y el `text-align` del padre
       lo centra. Con `flex` ocuparía todo el ancho de la ficha. */
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.85rem 2rem;
    /* 🎨 **LOS MISMOS COLORES QUE EL BOTÓN FLOTANTE DE WHATSAPP** en su estado `past-hero`, que
       es el que tiene puesto cuando el visitante está leyendo esta zona de la página: carbón
       aclarado con el crema encima. Los dos botones llevan a WhatsApp, así que **se ven iguales**
       — y el mismo glifo en ambos refuerza la lectura.
       🔗 Por eso `--charcoal-soft` dejó de ser un hex suelto: la comparten dos sitios. */
    background: var(--charcoal-soft);
    color: var(--on-dark);
    /* ✍️ **SIN `font-family`: hereda Lato**, la del cuerpo del sitio — y es deliberado, no un
       olvido. Se probaron Charm y Prata y las dos se descartaron (ver RV-02 en tareas.md): aquí
       manda que se lea de un vistazo, no que decore. Charm es cursiva y Prata es de titular; un
       botón es una ACCIÓN.
       📏 1,1rem: un punto por encima del texto normal, lo justo para que pese como CTA.
       `letter-spacing` de 0,02em, que es lo que le sienta bien a una palo seco. */
    font-size: 1.1rem;
    letter-spacing: 0.02em;
    line-height: 1;
    text-decoration: none;
    /* Objetivo táctil cómodo en móvil sin depender del `padding` (WCAG pide 44px). */
    min-height: 44px;
}
/* 🚫 **SIN HOVER, a propósito** (decidido con Andrés tras probar tres versiones: carbón + empujón,
   café un 10% más oscuro y un 5%). El botón se queda quieto.
   ♿ **OJO si algún día se toca:** aquí NO se declara `outline: none`, así que el **anillo de foco
   del navegador sigue funcionando** para quien navega con teclado. Quitar el hover es una decisión
   estética; quitar el foco sería dejar sin señal a quien no usa ratón. */

.boton-reservar__icono {
    /* 📐 Relativo al TEXTO, no en píxeles: el glifo viene sin `width`/`height` (RV-01) justo para
       esto. El flotante lo quiere a 36px, donde es todo el botón; aquí acompaña a una palabra y
       tiene que crecer con ella si el visitante amplía la fuente. */
    width: 1.55em;
    height: 1.55em;
    flex-shrink: 0;   /* que el texto largo del alemán no lo aplaste */
}
