/* =====================================================================
   Access Home — motion.css  ·  BLOQUE C (base)
   Agente: ah-motion. Encolado desde functions.php del child.

   QUE PUEDE HABER AQUI (y nada mas):
     transform · opacity · clip-path · filter · mix-blend-mode ·
     position:sticky/fixed · @keyframes · transition
   QUE NO: color, tipografia, tamano de letra, interlineado, espaciados
   de maquetacion. Todo eso es del Site Settings y del Style tab de
   Elementor (wiki §0). Y NUNCA se redefine --e-global-color-*: si hace
   falta un color de marca se LEE con var(--e-global-color-...).

   Los unicos colores que aparecen aqui son los del velo y el telon de la
   apertura, que no son texto ni maquetacion: son capas de efecto.
   ===================================================================== */

/* ---------------------------------------------------------------------
   1 · TOKENS — guion-movimiento.md §1
   Tres duraciones, cuatro curvas, un retardo y un escalonado. Se declaran
   UNA sola vez, aqui, y se repiten en motion.js (objeto AH.T). Si un dia
   cambia la duracion de entrada, se cambia en estos dos sitios y afecta a
   toda la web. En cuanto alguien escribe un `.7s` a mano, esto se rompe.
   --------------------------------------------------------------------- */
:root{
  --ah-dur-entrada:1s;
  --ah-dur-inter:.5s;
  --ah-dur-salida:.3s;
  --ah-retardo-base:.15s;
  --ah-escalonado:.08s;

  --ah-sale-suave:cubic-bezier(.25,1,.5,1);   /* TODAS las entradas */
  --ah-entra-seco:cubic-bezier(.5,0,.75,0);   /* salidas */
  --ah-barrido:cubic-bezier(.76,0,.24,1);     /* mascaras y barridos */
  --ah-lineal:linear;                         /* solo lo atado al scroll */

  /* El velo beige (punto 12 de la lista del cliente, 09/09/2026).
     UN SOLO token: cambiar el tono de todas las fotos del sitio es
     cambiar este numero. Nunca foto a foto. */
  --ah-velo-color:#F4F4ED;                    /* lino de marca */
  --ah-velo-opacidad:.16;                     /* 16 % */
  --ah-foto-filtro:saturate(.88) contrast(1.02);

  --ah-negro:#0A0A0A;                         /* solo el telon de la apertura */
  --ah-lino:#F4F4ED;                          /* solo la calma de la salida */
}

/* ---------------------------------------------------------------------
   2 · EL VELO BEIGE
   Va por DEFECTO sobre toda foto de contenido del sitio, para que no haya
   que marcar 225 fichas a mano: si depende de que alguien acuerde una
   clase, tarde o temprano entra una foto sin velo y se ve.

   Son dos capas encima de la fotografia:
     a) el filtro  — baja saturacion y sube un punto de contraste
     b) el velo    — lino de marca en multiplicar sobre la foto ya filtrada
   Multiplicando, los grises oscurecen el lino y conservan su calidez; con
   opacidad lo grisearian y se perderia el tono de marca.

   ⚠️ El velo cubre la CAJA del contenedor de la imagen, asi que la imagen
   tiene que llenarla (que es lo normal: en esta web las fotos van a sangre
   o a caja completa, sin radio y sin marco). Para una imagen mas estrecha
   que su caja, se le pone `ah-foto` a la propia imagen y el velo se ajusta.
   --------------------------------------------------------------------- */

/* a) el filtro */
.elementor-widget-image img,
.elementor-widget-theme-post-featured-image img,
.elementor-widget-image-carousel img,
.elementor-widget-image-gallery img,
.ah-foto img,
img.ah-foto{
  filter:var(--ah-foto-filtro);
}

/* b) el velo. `isolation` encierra el multiplicar dentro de la caja de la
      foto: sin el, el modo de fusion se propaga al fondo de la seccion. */
.elementor-widget-image > .elementor-widget-container,
.elementor-widget-theme-post-featured-image > .elementor-widget-container,
.elementor-widget-image-carousel > .elementor-widget-container{
  position:relative;
  isolation:isolate;
}

/* ⚠️ CORRECCION DEL BLOQUE E (10/09/2026), avisada por `ah-home`.
   `.ah-foto{position:relative}` tiraba al flujo cualquier elemento que
   Elementor hubiera posicionado desde Avanzado → Posicion: las diez capas
   del hero y las cuatro casillas de servicios son `absolute`, y con la regla
   plana se apilaban una debajo de otra.
   La causa: Elementor declara `.elementor-element{position:var(--position,relative)}`
   —MISMA especificidad que `.ah-foto`— y motion.css se encola despues, asi
   que ganabamos nosotros y le borrabamos el `absolute`.
   La cura no es pelear con esa declaracion: es REPETIRLA. Leyendo la misma
   variable, un elemento posicionado conserva su `absolute`/`fixed` y uno
   normal recibe el `relative` que el velo necesita. Una linea, y ni un
   `!important` en toda la hoja. */
.ah-foto{
  position:var(--position,relative);
  isolation:isolate;
}
.elementor-widget-image > .elementor-widget-container::after,
.elementor-widget-theme-post-featured-image > .elementor-widget-container::after,
.elementor-widget-image-carousel > .elementor-widget-container::after,
.ah-foto::after{
  content:"";
  position:absolute; inset:0;
  background:var(--ah-velo-color);
  mix-blend-mode:multiply;
  opacity:var(--ah-velo-opacidad);
  pointer-events:none;
}

/* La valvula de escape. Un logotipo, un icono o una captura de pantalla no
   son fotografia y con el velo se ensucian. Se marca con `ah-sin-velo`. */
.ah-sin-velo img,
img.ah-sin-velo{ filter:none }
.ah-sin-velo > .elementor-widget-container::after,
.ah-sin-velo::after{ content:none }

/* La foto-mapa de la zona: en grises, y la desatura LA WEB, no el cliente
   (wordpress.md §4.b). El equipo sube la captura en color y se conserva el
   original; si un dia se cambia de idea, se cambia en esta linea para las
   veinte zonas a la vez. Grises + el mismo velo, para que el mapa y las
   fotos de la ficha se lean como una sola superficie. */
.ah-mapa img{ filter:grayscale(1) var(--ah-foto-filtro) }

/* ---------------------------------------------------------------------
   3 · EL SISTEMA DE REVELADO  (guion-movimiento.md §3)
   Cada elemento declara su revelado con `data-rev`. El JS no conoce ni una
   clase de maquetacion: solo atributos, asi que el motion sobrevive a
   cualquier cambio de la plantilla.

     data-rev="bloque"   opacidad + 24 px de subida        · 1 s
     data-rev="izq"      desliza desde la izquierda        · 0,55 s
     data-rev="linea"    la regla de 1 px se dibuja        · 1 s
     data-rev-w          contenedor: sus hijos escalonados · 0,08 s
     data-rev-first      lista repetida: solo el primero anima

   ⚠️ El estado inicial cuelga de `html.ah-rev`, que la pone el JS. Sin JS
   no hay clase, no hay `opacity:0` y la pagina se ve entera: el movimiento
   es una capa encima, nunca la condicion para leer.
   --------------------------------------------------------------------- */
.ah-rev [data-rev]{
  transition:opacity var(--ah-dur-entrada) var(--ah-sale-suave) var(--ah-rev-d,0s),
             transform var(--ah-dur-entrada) var(--ah-sale-suave) var(--ah-rev-d,0s),
             clip-path var(--ah-dur-entrada) var(--ah-sale-suave) var(--ah-rev-d,0s);
  will-change:opacity, transform;
}
.ah-rev [data-rev="bloque"]{ opacity:0; transform:translateY(24px) }
/* `izq` es el revelado de los titulares de seccion: entra deslizando y
   RAPIDO —0,55 s en vez de 1 s—, porque el titular es lo primero que se
   lee de cada bloque y no puede hacerse esperar. */
.ah-rev [data-rev="izq"]{ opacity:0; transform:translateX(-52px); transition-duration:.55s }
.ah-rev [data-rev="linea"]{ clip-path:inset(0 100% 0 0) }
.ah-rev [data-rev].ah-visto{ opacity:1; transform:none; clip-path:inset(0) }

/* En movil el deslizamiento lateral se recorta: 52 px en una pantalla de
   390 se leen como un tiron. La pieza sigue entrando, mas corta. */
@media (max-width:640px){
  .ah-rev [data-rev="izq"]{ transform:translateX(-24px) }
}

/* ---------------------------------------------------------------------
   4 · LA APERTURA DE MARCA  (guion-movimiento.md §5.0)
   Una sola vez por sesion. El markup lo construye motion.js; aqui va su
   ropa, porque la hoja SI bloquea el pintado y el script va con `defer`.

   4.a · EL PRE-TELON. Es lo que evita el destello: la hoja se aplica en el
   primer fotograma, asi que la pantalla ya esta en negro antes de que el
   script exista. En cuanto motion.js arranca pone `ah-js` y decide: si la
   apertura ya se vio en esta sesion, quita el telon de inmediato (cero
   espera) y si no, monta la apertura dentro.
   ⚠️ La animacion `ah-rescate` es la red de seguridad: si el script NO
   llega a ejecutarse —bloqueado, error de red, JS desactivado— el telon se
   retira solo a los 1,2 s y la pagina se ve entera igualmente. `ah-js` la
   cancela, para que el telon no se desvanezca por debajo de la apertura.
   --------------------------------------------------------------------- */
html:not(.ah-abierto)::before{
  content:"";
  position:fixed; inset:0; z-index:99990;
  background:var(--ah-negro);
  animation:ah-rescate .4s var(--ah-sale-suave) 1.2s forwards;
}
html.ah-js:not(.ah-abierto)::before{ animation:none }
html.ah-abierto::before{ content:none }
@keyframes ah-rescate{ to{ opacity:0; visibility:hidden } }

/* mientras la apertura esta puesta, la pagina no se mueve */
html.ah-bloqueado, html.ah-bloqueado body{ overflow:hidden }

/* 4.b · el telon */
.ah-telon{
  position:fixed; inset:0; z-index:99991;
  background:var(--ah-negro);
  display:grid; place-content:center; justify-items:center;
}
.ah-telon[hidden]{ display:none }
.ah-telon.ah-listo{ cursor:pointer }   /* se ve que es pulsable */

.ah-telon__marca{ display:grid; justify-items:center; transform-origin:50% 50% }

/* el wordmark, RELLENO en lino, con un fundido de 0,7 s.
   Decision de Sergio 09/09/2026: ya no se escribe, aparece puesto. */
.ah-telon__wm{ width:min(46vw,620px); opacity:0;
               transition:opacity .7s var(--ah-sale-suave) }
.ah-telon__wm img{ display:block; width:100%; height:auto; filter:none }
.ah-telon.ah-entrado .ah-telon__wm{ opacity:1 }
@media (max-width:900px){ .ah-telon__wm{ width:78vw } }

/* «Real Estate · Since 1999» — un 45 % mas grande que en el prototipo
   (punto 2 de la lista del cliente): era clamp(8px,1.05vw,11px), ahora
   clamp(11.5px,1.5vw,16px). El texto es el mismo, solo sube de cuerpo.
   El tamano de un rotulo que solo existe dentro de esta capa no sale de
   ningun Style tab: no hay widget que lo aloje. */
.ah-telon__tagline{
  margin-top:clamp(14px,2.4vw,26px);
  font-size:clamp(11.5px,1.5vw,16px);
  letter-spacing:.34em; text-transform:uppercase; text-align:center;
  color:var(--ah-lino);
  opacity:0; transition:opacity .4s var(--ah-sale-suave);
}
.ah-telon.ah-rematado .ah-telon__tagline{ opacity:.62 }

/* el indicador: icono «SS» relleno + «Scroll» */
.ah-telon__pista{
  position:absolute; left:50%; bottom:clamp(28px,5vh,54px);
  transform:translateX(-50%);
  display:grid; justify-items:center; gap:10px;
  opacity:0; transition:opacity .3s var(--ah-sale-suave);
}
.ah-telon.ah-rematado .ah-telon__pista{ opacity:1 }
.ah-telon__pista img{ width:22px; height:22px; display:block; filter:none }
.ah-telon__pista span{
  font-size:9px; letter-spacing:.3em; text-transform:uppercase;
  color:var(--ah-lino);
}

/* 4.c · la calma en lino. El telon se va con un salto (×24 acelerando) y
   la pantalla se queda en lino AL 90 %, no al 100: el hero ya se adivina
   por detras y la pausa se lee como transicion, no como pantalla. */
.ah-fogonazo{
  position:fixed; inset:0; z-index:99992;
  background:var(--ah-lino);
  opacity:0; pointer-events:none;
}

/* Con la reduccion de movimiento activada no hay apertura: ni salto, ni
   fundido, ni calma. El telon se retira y ya esta. Y todo lo revelado se
   ve puesto y quieto. Sin excepciones: es accesibilidad, y en un publico
   que incluye a gente mayor comprando casa, es sentido comun. */
@media (prefers-reduced-motion:reduce){
  .ah-rev [data-rev]{
    opacity:1 !important; transform:none !important;
    clip-path:none !important; transition:none !important;
  }
  .ah-telon__wm,
  .ah-telon__tagline,
  .ah-telon__pista{ transition:none }
}


/* =====================================================================
   =====================  B L O Q U E   E  =============================
   Motion especifico, sobre las plantillas ya montadas por ah-home,
   ah-propiedades y ah-paginas. Todo cuelga de las clases y atributos que
   ellos pusieron desde Avanzado -> Clases/Atributos: aqui NO se ha tocado
   `_elementor_data` de ninguna pagina ni plantilla.

   Sigue rigiendo el limite del bloque C: transform, opacity, clip-path,
   filter, mix-blend-mode, position y @keyframes. Lo unico que se sale de
   ahi es la MAQUETA de las piezas que imprime un shortcode del plugin
   (`.ah-filtros`, `.ah-extras`, `.ah-orden`, `.ah-compartir`) y el cromo
   que construye motion.js —visor, pop-up de video, raton, boton de bajar—:
   es markup que ningun Style tab de Elementor puede alcanzar, porque no
   hay widget que lo aloje. Ni un color de texto, ni una tipografia, ni un
   tamano de letra de contenido en toda esta seccion.
   ===================================================================== */

/* ---------------------------------------------------------------------
   E.0 - LA CABECERA: transparente sobre el hero, negra al despegarse

   Reparto con `ah-estructura`: la plantilla (post 46) deja el fondo del
   contenedor TRANSPARENTE en el control nativo y le pone la clase
   `ah-cab`. Aqui vive UNICAMENTE el estado `ah-cab--solida`, que es
   mecanismo —una clase que pone y quita el JS segun la posicion del
   scroll—, no maquetacion: por eso puede ir en hoja externa.

   Por que se vuelve negra cuando la SECCION 2 le llega y no cuando acaba
   el hero: con el revelado, Mision sube POR DELANTE del hero durante todo
   ese tramo. Si la cabecera siguiera transparente, el wordmark en lino
   desapareceria en cuanto tuviera el blanco de Mision detras
   (decision 03/09/2026).

   El color se LEE del kit, no se redefine: `primary` es el negro #0A0A0A
   de los Ajustes del sitio. El literal es solo la red por si la variable
   no existiese.

   ⚠️ El estado se escribe con la clase DOS VECES —`.ah-cab.ah-cab--solida`,
   especificidad 0,2,0— y no con `!important`. Elementor imprime el fondo
   transparente del contenedor como `.elementor-element-173d491{...}`
   (0,1,0) en la hoja del post 46, que se encola DESPUES de esta: con una
   sola clase empatan y gana la ultima, asi que la cabecera se quedaba
   transparente para siempre. Comprobado en navegador el 10/09/2026.
   --------------------------------------------------------------------- */
.ah-cab{ transition:background-color var(--ah-dur-inter) var(--ah-sale-suave) }
.ah-cab.ah-cab--solida{ background-color:var(--e-global-color-primary,#0A0A0A) }

/* Sergio, 11/09/2026: hueco blanco entre la cabecera y el carrusel de la
   ficha. La causa: `.ah-cab--solida` la pone `AH.cabecera()` en JS —que
   corre con `defer`, DESPUES del primer pintado— y encima lleva la
   transicion de 0,5 s de arriba, pensada para el paso transparente/solida
   de la home. En una pagina SIN hero (ficha, listado, zona, articulo,
   las paginas de contenido) esos dos motivos dejan una ventana real —no
   solo un instante— en la que la cabecera esta transparente y se ve el
   blanco del `body` detras.
   La cura no depende de que el JS llegue a tiempo: `:has()` decide en el
   PROPIO CSS, antes de que se pinte nada, si la pagina tiene hero. Sin
   el, negro solido y sin transicion desde el primer fotograma. */
body:not(:has(.ah-sec-hero)) .ah-cab{
  background-color:var(--e-global-color-primary,#0A0A0A);
  transition:none;
}

/* Sergio, 11/09/2026, con capturas de las dos: el hueco blanco SEGUÍA ahí
   con sesión iniciada, en el listado. Causa distinta a la de arriba —esta
   solo la ve un administrador—: la barra de WordPress es `position:fixed;
   top:0`, y `body.admin-bar` empuja el CONTENIDO 32px hacia abajo (46px
   en móvil) con un margen — pero la cabecera de Elementor, tambien
   `position:fixed`, lleva su propio `top:0px` fijo y no se entera de ese
   margen: se queda pegada arriba, con sus primeros 32px tapados por la
   barra de WordPress, y el contenido arranca 32px mas abajo de donde
   ella termina. La medida en vivo, simulando la barra real: cabecera
   0-70px, contenido a partir de 102px — 32px de hueco, ni uno mas ni
   uno menos que la barra. Se corrige bajando la cabecera esos mismos
   32/46px cuando hay sesion, que es la convencion de siempre de WordPress
   para cualquier cabecera fija propia.
   ⚠️ Especificidad: el `top:0px` de Elementor sale en
   `.elementor-46 .elementor-element.elementor-element-173d491` — TRES
   clases, (0,3,0). Hacen falta cuatro para ganar sin `!important`. */
body.admin-bar.admin-bar .ah-cab.ah-cab{ top:32px }
@media screen and (max-width:782px){
  body.admin-bar.admin-bar .ah-cab.ah-cab{ top:46px }
}

/* ---------------------------------------------------------------------
   E.1 - EL HERO: el ciclo de las diez fotos
   Diez `image` absolutas dentro de `.ah-hero-capas`, con z-index 1..10.
   El recorrido lo monta motion.js envolviendo `.ah-sec-hero` en un
   `.ah-recorrido` alto: el hero se queda CLAVADO y el recorrido pasa por
   debajo. Es el mismo esqueleto del prototipo (contenedor alto + hijo
   pegajoso) y no obliga a sacar el hero del flujo.
   --------------------------------------------------------------------- */
.ah-recorrido{ position:relative; z-index:1 }
.ah-recorrido > .ah-sec-hero{ position:sticky; top:0 }

/* El apilado. Un elemento `sticky` es un elemento POSICIONADO, asi que se
   pinta por encima de cualquier bloque que no lo este, aunque venga
   despues en el HTML y tenga fondo opaco (errores-conocidos.md). La cura
   es que todas las secciones vivan en la misma capa: se usa `data-bg`,
   que ya declaran todas, asi que una seccion nueva entra sola. */
[data-bg]{ position:relative; z-index:2 }

/* Las capas. La 1 se queda puesta debajo de todas: si el JS falla, el hero
   tiene foto igual. Las otras nueve entran por opacidad. */
.ah-hero-capa{ opacity:0; will-change:opacity }
.ah-hero-capas > .ah-hero-capa:first-child{ opacity:1 }
.ah-hero-capa img{ width:100%; height:100%; object-fit:cover; display:block }

/* EL VELO DEL HERO. Clonado al pixel de `.velo` de `prototipo/_loader.tpl.html`
   (lineas 113-127). NO es un filtro sobre la foto: es una capa aparte, asi que
   se puede bajar entera sin tocar la imagen.

   DOS degradados, no uno a pantalla completa: una BANDA arriba, que es lo que
   hace legible el menu sobre la foto ahora que la cabecera es transparente
   (medido por ah-motion: en 6 de las 10 fotos del ciclo la luminancia de la
   franja de 74 px esta entre 159 y 177 y el lino del wordmark en 243), y una
   CUNA desde la esquina inferior izquierda, donde va el titular. El centro y
   la derecha quedan limpios, que es donde estan el cielo y el agua.

   ⚠️ POR QUE VA POR CLASE Y NO EN «Fondo → Superposicion» (control nativo):
   el control nativo de degradado de Elementor admite DOS paradas de color
   (color + color_b, con sus dos posiciones). Los dos degradados del prototipo
   tienen TRES cada uno, y la parada intermedia no es decorativa: sin ella, en
   la franja del menu el velo cae de .377 a .43 de opacidad. Fuera de la
   tolerancia cero. Es el caso previsto en CLAUDE.md: «si un control nativo no
   llega al valor exacto, se clava por clase con el CSS del child theme».
   Y no es espaciado, es la geometria de un mecanismo del hero, que esta
   cerrado y aprobado desde el 03/09 y el cliente no edita.

   z-index 1: por encima de `.ah-hero-capas` (0) y por debajo de
   `.ah-hero-texto` (2), el raton y el boton de bajar (6). */
.ah-sec-hero::before{
  content:""; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:
    linear-gradient(180deg, rgba(10,10,10,.58) 0%, rgba(10,10,10,.16) 12%, rgba(10,10,10,0) 22%),
    linear-gradient(18deg,  rgba(10,10,10,.82) 0%, rgba(10,10,10,.40) 30%, rgba(10,10,10,0) 56%);
  transition:opacity var(--ah-dur-salida) var(--ah-sale-suave);
}

/* Los titulares se RELEVAN: nunca hay dos en pantalla a la vez, asi que se
   apilan en la misma celda en vez de ocupar cuatro alturas de titular. */
.ah-hero-titulares{ display:grid }
.ah-hero-titulares > .ah-hero-tit{ grid-area:1/1 }
.ah-hero-tit{
  opacity:0; transform:translateY(14px); pointer-events:none;
  transition:opacity var(--ah-dur-entrada) var(--ah-sale-suave),
             transform var(--ah-dur-entrada) var(--ah-sale-suave);
}
.ah-hero-tit.ah-tit-activo{ opacity:1; transform:none; pointer-events:auto }

/* ⚠️ El titular que no esta de turno se apaga aunque el revelado generico
   lo haya dado por visto. `ah-home` le puso `data-rev="bloque"` al primero
   y `.ah-rev [data-rev].ah-visto{opacity:1}` (0,3,0) ganaba a
   `.ah-hero-tit` (0,1,0): se quedaba encendido DEBAJO de los relevos y se
   leian dos frases superpuestas. Este selector empata en especificidad y
   va despues, asi que manda; motion.js ademas le retira el atributo.
   Dos cinturones para el mismo pantalon, y con razon: el fallo solo se ve
   cuando llega el segundo relevo, o sea, tarde. */
.ah-rev .ah-hero-tit:not(.ah-tit-activo){ opacity:0; transform:translateY(14px) }

/* Sin JS no hay clase, y entonces manda el primero: la pagina se lee. */
html:not(.ah-js) .ah-hero-titulares > .ah-hero-tit:first-child{ opacity:1; transform:none }

/* El subtitulo se retira mientras esta el tercer relevo, que ES esa misma
   frase palabra por palabra (decision 03/09). La misma frase dos veces,
   una encima de la otra, no se sostiene. */
.ah-hero-sub{ transition:opacity var(--ah-dur-inter) var(--ah-sale-suave) }
/* El subtitulo lleva data-rev="bloque", asi que `.ah-rev [data-rev].ah-visto`
   (0,3,0) le gana a esta regla si se queda en (0,2,0) -- se queda encendido
   debajo del relevo. Se dobla la clase para empatar en especificidad y
   ganar por orden de aparicion, sin !important. */
.ah-hero-sub.ah-hero-sub.ah-sub-fuera{ opacity:0 }

/* El raton con la ruedita. Es la UNICA excepcion a la regla 3 del guion
   ("nada se mueve si el usuario no ha hecho scroll"): su trabajo es
   justamente pedir el scroll. Se apaga en cuanto el dia arranca. */
/* ⚠️ RESET DE BOTON, y no es cosmetico: el kit de Elementor declara
   `.elementor-kit-7 button` (especificidad 0,1,1), que GANA a cualquier
   clase suelta del child (0,1,0). Sin este reset el raton, el boton de
   bajar y el cue del carril salen con FONDO NEGRO, borde negro, relleno
   de 18x34 y la tipografia de boton — es lo que se veia en «Scroll» y la
   flecha (punto 20 de la lista del 10/09).
   La cura es doblar la clase para subir a 0,2,0. Sin `!important`. */
.ah-raton.ah-raton,
.ah-bajar.ah-bajar,
.ah-carril__cue.ah-carril__cue{
  -webkit-appearance:none; appearance:none;
  background:none; background-color:transparent;
  border:0; border-radius:0; padding:0;
  font:inherit; letter-spacing:inherit; text-transform:none;
  color:inherit; box-shadow:none;
}

/* ⚠️ El raton DEJA DE SER DECORATIVO (punto 19, Sergio 10/09): pasa a ser
   el boton de «siguiente seccion» del hero, asi que es un <button> de
   verdad, alcanzable con el teclado y con nombre accesible. Ya no lleva
   `aria-hidden` ni `pointer-events:none`.
   Sube 15 px sobre su posicion anterior: clamp(18px,3.5vh,34px) + 15. */
.ah-raton.ah-raton{
  position:absolute; left:50%; bottom:clamp(33px,calc(3.5vh + 15px),49px);
  transform:translateX(-50%);
  width:22px; height:34px; z-index:6;
  border:1px solid rgba(244,244,237,.55); border-radius:11px;
  opacity:.85; cursor:pointer;
  transition:opacity var(--ah-dur-salida) var(--ah-sale-suave),
             transform var(--ah-dur-inter) var(--ah-sale-suave);
}
.ah-raton:hover{ transform:translate(-50%,3px) }
.ah-raton:focus-visible{ outline:1px solid var(--ah-lino); outline-offset:6px }
.ah-raton::after{
  content:""; position:absolute; left:50%; top:7px;
  width:2px; height:6px; margin-left:-1px;
  background:var(--ah-lino); border-radius:1px;
  animation:ah-ruedita 1.8s var(--ah-sale-suave) infinite;
}
@keyframes ah-ruedita{
  0%,12%   { transform:translateY(0);    opacity:0 }
  30%      { opacity:1 }
  70%,100% { transform:translateY(11px); opacity:0 }
}
.ah-raton.ah-fuera{ opacity:0; pointer-events:none }
/* Con reduccion de movimiento la ruedita no late: es el unico bucle de
   la web y la regla 5 del guion no admite excepciones. */
@media (prefers-reduced-motion:reduce){ .ah-raton::after{ animation:none; opacity:1 } }

/* El boton de bajar. SOLO en el hero (Sergio, 09/09): el resto de la
   pagina se queda con la flecha del carril, porque dos indicadores de
   "sigue bajando" compitiendo en cada seccion son uno de mas en una web
   que no debe marear. */
.ah-bajar.ah-bajar{
  position:absolute; right:clamp(18px,3vw,40px); bottom:clamp(18px,3.5vh,34px);
  z-index:6; width:44px; height:44px; padding:0;
  display:grid; place-content:center;
  background:none; border:1px solid rgba(244,244,237,.45);
  border-radius:0;                       /* radio 0: regla de la casa */
  cursor:pointer;
  transition:transform var(--ah-dur-inter) var(--ah-sale-suave),
             opacity var(--ah-dur-salida) var(--ah-sale-suave);
}
.ah-bajar::before{
  content:""; width:9px; height:9px;
  border-right:1px solid var(--ah-lino); border-bottom:1px solid var(--ah-lino);
  transform:translateY(-2px) rotate(45deg);
}
.ah-bajar:hover{ transform:translateY(3px) }
.ah-bajar.ah-fuera{ opacity:0; pointer-events:none }

/* Movil (guion §6): el recorrido se acorta —lo mide motion.js— y el boton
   de bajar desaparece, que en 390 px compite con el CTA primario. */
@media (max-width:640px){ .ah-bajar{ display:none } }

/* ---------------------------------------------------------------------
   E.2 - EL CONTADOR DE LAS CIFRAS
   Aqui solo hace falta reservar el ancho: la cifra la reescribe el JS y,
   sin cifras tabulares, al pasar de 7 a 225 el numero cambia de anchura y
   BAILA. Es el detalle que separa una web cuidada de una con efectos.
   --------------------------------------------------------------------- */
.ah-cifra__n,
.ah-cifra__n .elementor-heading-title{ font-variant-numeric:tabular-nums }

/* ---------------------------------------------------------------------
   E.3 - LAS CASILLAS DE SERVICIOS
   Cuatro en fila. Las cerradas ensenan su numero y su rotulo; la abierta
   CRECE, se pone en color y aparece el resto.
   Se anima `flex-grow`, que es lo que las expande de verdad: animando
   `width` aparecerian ya abiertas, y ademas `width` provoca repintado
   (regla 4 del guion).
   --------------------------------------------------------------------- */
.ah-serv-pista{ display:flex; align-items:stretch }
/* El reposo lo pone Elementor: `_flex_size:custom` deja `flex-grow:1` en
   `.elementor-element`, misma especificidad que `.ah-serv-casilla`, y como
   su hoja va antes... gana la nuestra si la declaramos. Medido el 10/09:
   sale 1. Se deja asi a proposito y solo se declara la casilla ABIERTA —
   `.ah-serv-casilla.ah-abierta` es (0,2,0) y ese si manda—. La proporcion
   queda 3,2 : 1 : 1 : 1, o sea la abierta se lleva la mitad del ancho y
   las tres cerradas un sexto cada una, que es lo que se buscaba. Menos
   CSS peleando y el mismo resultado. */
.ah-serv-casilla{
  min-width:0; cursor:pointer;
  transition:flex-grow var(--ah-dur-entrada) var(--ah-sale-suave);
}
.ah-serv-casilla.ah-abierta{ flex-grow:3.2; cursor:default }

/* Las cerradas, en blanco y negro y apagadas; la abierta, en color.
   El gris NO se hace con `filter:grayscale()` sobre el contenedor: el
   filtro lo heredarian el rotulo y el numero, y el texto tambien se
   desaturaria y perderia contraste. Se hace con `background-blend-mode`,
   que actua SOLO sobre el fondo y deja el contenido intacto. Y el apagado
   sube el propio velo de la casa, sin capa nueva. */
.ah-serv-casilla:not(.ah-abierta){
  background-blend-mode:luminosity;
  --ah-velo-opacidad:.46;
}
.ah-serv-casilla.ah-abierta{ background-blend-mode:normal }

/* Sergio, 10/09/2026: degradado de negro a transparente, de arriba a abajo,
   SOLO en las cerradas — es lo que le falta al numero en fantasma para
   leerse con garantia sea cual sea la foto de fondo (el n.2 era el que
   menos contraste tenia). `::before` pinta detras del contenido en flujo
   porque es el primer hijo generado y `.ah-serv-num`/`.ah-serv-pie` son
   positioned (var(--position,relative) de Elementor), asi que ganan en
   orden de pintado sin necesidad de z-index. */
.ah-serv-casilla:not(.ah-abierta)::before{
  content:''; position:absolute; inset:0 0 auto 0; height:38%;
  pointer-events:none;
  background:linear-gradient(180deg, rgba(10,10,10,.55) 0%, rgba(10,10,10,0) 100%);
}

/* Lo que solo se ve con la casilla abierta. El TITULO ya no esta en esta
   lista (10/09/2026): en el prototipo (`.sv2__tit`) nunca se oculta, solo
   se ocultan el parrafo y el boton — WordPress lo escondia de mas y el
   titulo ("Valora tu propiedad", "Gestiona tu alquiler"...) desaparecia
   entero en las tres casillas cerradas. */
.ah-serv-texto, .ah-serv-cta{
  opacity:0; transition:opacity var(--ah-dur-inter) var(--ah-sale-suave);
}
.ah-serv-casilla.ah-abierta .ah-serv-texto,
.ah-serv-casilla.ah-abierta .ah-serv-cta{ opacity:1 }
/* Sin JS las cuatro se ven enteras: el contenido nunca depende del motion. */
html:not(.ah-js) .ah-serv-texto,
html:not(.ah-js) .ah-serv-cta{ opacity:1 }

/* El cuadradito de la etiqueta "Servicios" (Sergio, 10/09/2026): en el
   prototipo esta seccion es la UNICA que usa un cuadrado de 7 px en vez
   del guion "—" que llevan el resto de microetiquetas de la home. Va por
   `::before` sobre el propio texto, tal y como se pidio, en vez de tocar
   el widget con un elemento HTML aparte. */
.ah-serv-eti .elementor-heading-title{
  display:flex; align-items:center; gap:9px;
}
.ah-serv-eti .elementor-heading-title::before{
  content:''; width:7px; height:7px; background:currentColor; flex:0 0 auto;
}

/* Por debajo de 992 px se apila: cuatro casillas creciendo en horizontal
   en 390 px no dejan nada legible. Se abren igual al pulsar, pero en
   vertical y con su propio alto. */
@media (max-width:991px){
  .ah-serv-pista{ display:block }
  .ah-serv-casilla{ width:100%; transition:none }
}

/* ↩️ 17/09/2026 (cliente): en MÓVIL el acordeón no se entendía —tres casillas grises y
   medio vacías—. Por debajo de 768 px las cuatro son rectángulos iguales en una columna,
   TODAS en color y con texto y botón a la vista, como la abierta. El JS sigue poniendo
   `.ah-abierta` al pulsar, pero aquí ya no cambia nada. Mismo selector (0,2,0) que las
   reglas de arriba: gana por ir después. */
@media (max-width:767px){
  .ah-serv-casilla:not(.ah-abierta){ background-blend-mode:normal; --ah-velo-opacidad:.16; cursor:default }
  .ah-serv-casilla.ah-abierta{ cursor:default }
  .ah-serv-casilla:not(.ah-abierta)::before{ content:none }
  .ah-serv-casilla .ah-serv-texto,
  .ah-serv-casilla .ah-serv-cta{ opacity:1 }
}

/* ---------------------------------------------------------------------
   E.4 - LA CITA DE VALORACION
   Entra borrosa y a baja opacidad, se ENFOCA al cruzar el centro y se
   vuelve a desenfocar al salir. Va ATADA AL SCROLL: no es una animacion,
   asi que si paras se queda quieta donde estes. Por eso puede ir y venir
   sin romper la regla 1 del guion (§7, matiz del 03/09).
   El valor lo escribe motion.js en linea.
   --------------------------------------------------------------------- */
.ah-val-cita{ will-change:filter, opacity }

/* En movil, SIN desenfoque. No es una preferencia: en pantalla estrecha la
   cita ocupa casi todo el alto y su centro nunca llega a coincidir con el
   de la pantalla, asi que se quedaria a medio enfocar todo el rato, justo
   lo contrario del efecto.
   El `!important` hace falta y esta acotado a esta regla: el JS escribe
   `filter` EN LINEA y un estilo en linea gana a cualquier hoja. Ademas
   motion.js limpia esos estilos al cruzar a movil redimensionando, para
   que el desenfoque no se quede puesto. */
@media (max-width:860px){
  .ah-val-cita{ filter:none !important; opacity:1 !important }
}

/* ---------------------------------------------------------------------
   E.5 - TESTIMONIOS: relevo y autocarrusel
   Las tres citas se apilan en la misma celda: es un RELEVO, no una lista.
   --------------------------------------------------------------------- */
/* ⛔ `.ah-test-citas{display:grid}` retirado el 10/09: ese contenedor lo
   pintaba la version a mano y ya no existe. Las reglas de `.ah-test-cita`
   se conservan como red por si alguna plantilla la sigue usando. */
.ah-test-citas > .ah-test-cita{ grid-area:1/1 }
.ah-test-cita{
  opacity:0; transform:translateY(10px); pointer-events:none;
  transition:opacity var(--ah-dur-salida) var(--ah-entra-seco),
             transform var(--ah-dur-salida) var(--ah-entra-seco);
}
.ah-test-cita.ah-test-activa{
  opacity:1; transform:none; pointer-events:auto;
  transition:opacity var(--ah-dur-entrada) var(--ah-sale-suave),
             transform var(--ah-dur-entrada) var(--ah-sale-suave);
}
/* Sin JS manda la primera. */
html:not(.ah-js) .ah-test-citas > .ah-test-cita:first-child{ opacity:1; transform:none }
/* El pie va DEBAJO de la cita mas alta, no encima de ella: como todas
   comparten la celda 1, el pie se saca a la fila 2. */
.ah-test-citas > .ah-test-pie{ grid-area:2/1 }
.ah-test-indice{ font-variant-numeric:tabular-nums }

/* ---------------------------------------------------------------------
   E.6 - EL CIERRE: el cuadrado que crece
   Sergio, 10/09/2026, con la web delante — TERCERA revision de esta
   seccion: (1) el cuadrado DEJA DE CRECER, se queda quieto y solo releva
   la frase de dentro (eso ya estaba escrito, pero WordPress seguia con
   la version vieja del cuadrado creciendo — nunca se habia actualizado);
   (2) el VIDEO se queda entero hasta el FINAL de la seccion, y solo
   entonces, si se sigue bajando, la foto de interior barre por encima;
   (3) el segundo claim («Ayudamos a las personas…») aparece EN EL MISMO
   INSTANTE en que empieza ese barrido — no antes, no en un tramo aparte.

   ⭐ Hizo falta anadir un contenedor nuevo (`.ah-fin-mirador`, sticky
   nativo de Elementor con `sticky_parent:#cierre`) porque `.ah-sec-cierre`
   era un solo bloque de 100vh sin margen de scroll: no habia POR DONDE
   hacer la transicion. Ahora `.ah-sec-cierre` mide 240vh (control nativo
   `min_height`) y el mirador se queda clavado esos 140vh de mas.

   El cuadrado es FIJO por CSS (`min(28vw,550px)`, tope pedido por Sergio),
   no por los campos nativos de Elementor: es geometria de un mecanismo
   atado al scroll, la misma excepcion que ya cubre el resto de la web. */
.ah-fin-video, .ah-fin-foto-b, .ah-fin-franja{ pointer-events:none }
.ah-fin-foto-b{ clip-path:inset(0 0 0 100%); will-change:clip-path }

/* El cuadrado: mismo sitio, mismo tamano, SIEMPRE — nunca crece. Ancho
   tope 550px en los dos estados, porque es el mismo elemento para los
   dos (marca y eslogan ocupan exactamente esta misma caja).

   ⚠️ Elementor escribe el `left:0px` de estos tres contenedores (vienen de
   `_offset_x`) con el selector `body:not(.rtl) .elementor-20
   .elementor-element.elementor-element-<id>`, que es (0,4,1) — un `body`
   mas CUATRO clases (el `:not()` cuenta como una). Con solo tres clases
   pierde: `left:0` gana y, al haber tambien `right` y `width`, el
   navegador ignora `right` por completo (LTR: si left+width+right estan
   los tres fijados, manda left+width). Se dobla `body` + dos clases para
   quedar en (0,5,1) — la misma receta ya usada con el boton negro del kit
   y con el `position` de `.ah-foto`. */
body .ah-sec-cierre.ah-sec-cierre .ah-fin-mirador.ah-fin-mirador .ah-fin-franja,
body .ah-sec-cierre.ah-sec-cierre .ah-fin-mirador.ah-fin-mirador .ah-fin-marca,
body .ah-sec-cierre.ah-sec-cierre .ah-fin-mirador.ah-fin-mirador .ah-fin-slogan{
  position:absolute; z-index:2;
  top:50%; transform:translateY(-50%);
  right:clamp(20px,4vw,48px); left:auto; bottom:auto;
  width:min(28vw,550px);
}
body .ah-sec-cierre.ah-sec-cierre .ah-fin-mirador.ah-fin-mirador .ah-fin-franja{
  min-height:min(28vw,550px); aspect-ratio:1/1;
}
body .ah-sec-cierre.ah-sec-cierre .ah-fin-mirador.ah-fin-mirador .ah-fin-marca,
body .ah-sec-cierre.ah-sec-cierre .ah-fin-mirador.ah-fin-mirador .ah-fin-slogan{
  z-index:3; box-sizing:border-box;
  padding:clamp(20px,2.1vw,30px);
}
@media(max-width:860px){
  /* el cuadrado fijo a 28vw en movil son ~110px: centrado y mas ancho en
     proporcion, igual que hace el resto de la web con este mismo cuadro. */
  body .ah-sec-cierre.ah-sec-cierre .ah-fin-mirador.ah-fin-mirador .ah-fin-franja,
  body .ah-sec-cierre.ah-sec-cierre .ah-fin-mirador.ah-fin-mirador .ah-fin-marca,
  body .ah-sec-cierre.ah-sec-cierre .ah-fin-mirador.ah-fin-mirador .ah-fin-slogan{
    right:auto; left:50%; transform:translate(-50%,-50%);
    width:min(78vw,340px);
  }
  body .ah-sec-cierre.ah-sec-cierre .ah-fin-mirador.ah-fin-mirador .ah-fin-franja{ min-height:min(78vw,340px) }
}

/* Las dos frases viven en la MISMA caja, apiladas: asi ninguna empuja a
   la otra y el cuadrado no respira al relevar. La opacidad la escribe
   motion.js en linea, atada al mismo progreso que el barrido de la foto —
   por eso ninguna de las dos lleva transicion de opacidad por CSS: una
   transicion encima del valor en linea solo anade retardo y va a rastras
   del dedo (decision 03/09, que se mantiene). Las PALABRAS del eslogan si
   llevan transicion, que esas son un revelado normal, una vez y se acabo. */
.ah-fin-marca, .ah-fin-slogan{ transition:none }
.ah-fin-slogan .ah-pal{
  display:inline-block;
  opacity:0; transform:translateY(.34em);
  transition:opacity .5s var(--ah-sale-suave), transform .5s var(--ah-sale-suave);
}
.ah-fin-slogan .ah-pal.ah-visto{ opacity:1; transform:none }

/* El velo beige tambien aqui. `.ah-fin-video` y `.ah-fin-foto-b` no pueden
   llevar `ah-foto` —son contenedores `absolute` con fondo, y el velo de la
   clase se apoya en la caja del widget de imagen, que aqui no existe—, asi
   que se les da directamente. Es el MISMO token: cambiar el tono de todas
   las fotos de la web sigue siendo cambiar un numero. */
.ah-fin-video, .ah-fin-foto-b{ filter:var(--ah-foto-filtro) }
.ah-fin-video::after, .ah-fin-foto-b::after{
  content:""; position:absolute; inset:0;
  background:var(--ah-velo-color);
  mix-blend-mode:multiply; opacity:var(--ah-velo-opacidad);
  pointer-events:none;
}
/* El video de fondo tiene que llenar la caja, como las fotos. */
.ah-fin-video video{ object-fit:cover }

/* ---------------------------------------------------------------------
   E.7 - EL BLOG EN MOVIL: una sola entrada
   Tres articulos apilados son tres pantallas de scroll para un bloque que
   en la home solo es un adelanto. El enlace "Ver todos" sigue ahi.
   --------------------------------------------------------------------- */
@media (max-width:560px){
  /* ⚠️ NO vale `> *:not(:first-child)`: Elementor mete un `<style>` como
     PRIMER hijo del contenedor del bucle, asi que el primer articulo es el
     segundo hijo y se ocultaban los TRES. Se cuenta por `.e-loop-item`:
     un item que tenga otro item por delante se oculta; el primero no lo
     tiene y sobrevive. Verificado el 10/09 con las tres entradas ya
     publicadas — antes salian 0 de 3. */
  .ah-blog-solo-una .elementor-loop-container > .e-loop-item ~ .e-loop-item{ display:none }
}

/* ---------------------------------------------------------------------
   E.8 - EL VISOR DE GALERIA A PANTALLA COMPLETA
   Lo construye motion.js. Sobre negro solido —no un gris translucido—,
   la foto centrada, sin marco y sin radio.
   --------------------------------------------------------------------- */
.ah-visor{
  position:fixed; inset:0; z-index:99980;
  background:var(--ah-negro);
  display:grid; grid-template-rows:1fr auto;
  opacity:0; transition:opacity var(--ah-dur-inter) var(--ah-sale-suave);
}
.ah-visor[hidden]{ display:none }
.ah-visor.ah-abierto-v{ opacity:1 }
.ah-visor__lienzo{
  position:relative; display:grid; place-items:center; min-height:0;
  padding:clamp(44px,6vh,72px) clamp(16px,5vw,84px) 8px;
}
.ah-visor__img{
  max-width:100%; max-height:100%; object-fit:contain; display:block;
  opacity:0; transform:scale(.985);
  transition:opacity var(--ah-dur-inter) var(--ah-sale-suave),
             transform var(--ah-dur-inter) var(--ah-sale-suave);
}
.ah-visor__img.ah-puesta{ opacity:1; transform:none }
.ah-visor__pie{
  display:flex; align-items:center; justify-content:center;
  gap:24px; padding:0 20px clamp(18px,4vh,34px);
}
.ah-visor__n{                       /* `03 / 24`, tabular, sin que baile */
  font-variant-numeric:tabular-nums;
  font-size:11px; letter-spacing:.28em;
  color:var(--ah-lino); opacity:.7;
}
.ah-visor__x, .ah-visor__f{
  position:relative; padding:0; cursor:pointer;
  width:44px; height:44px; display:grid; place-content:center;
  background:none; border:1px solid rgba(244,244,237,.35); border-radius:0;
  transition:border-color var(--ah-dur-inter) var(--ah-sale-suave);
}
.ah-visor__x:hover, .ah-visor__f:hover{ border-color:var(--ah-lino) }
.ah-visor__x{ position:absolute; top:14px; right:14px; z-index:2 }
.ah-visor__x::before, .ah-visor__x::after{
  content:""; position:absolute; left:50%; top:50%;
  width:15px; height:1px; margin:-1px 0 0 -7px; background:var(--ah-lino);
}
.ah-visor__x::before{ transform:rotate(45deg) }
.ah-visor__x::after{ transform:rotate(-45deg) }
.ah-visor__f::before{
  content:""; width:9px; height:9px;
  border-top:1px solid var(--ah-lino); border-left:1px solid var(--ah-lino);
}
.ah-visor__f--ant::before{ transform:translateX(2px) rotate(-45deg) }
.ah-visor__f--sig::before{ transform:translateX(-2px) rotate(135deg) }

/* 17/09/2026: la ✕ del visor no se veía. El kit de Elementor pinta cualquier botón con foco o
   ratón encima con fondo lino (`.elementor-kit-7 button:focus`, 0,2,1) y las aspas son lino:
   al abrir, el foco va a la ✕ y desaparece. Clase doblada + estados para ganarle sin
   `!important`, también en las flechas y en la ✕ del pop-up de vídeo. */
button.ah-visor__x.ah-visor__x, button.ah-visor__x.ah-visor__x:hover, button.ah-visor__x.ah-visor__x:focus,
button.ah-visor__f.ah-visor__f, button.ah-visor__f.ah-visor__f:hover, button.ah-visor__f.ah-visor__f:focus,
button.ah-vpop__x.ah-vpop__x, button.ah-vpop__x.ah-vpop__x:hover, button.ah-vpop__x.ah-vpop__x:focus{
  background:rgba(10,10,10,.55); color:var(--ah-lino); box-shadow:none;
  border:1px solid rgba(244,244,237,.45); border-radius:0;
}
button.ah-visor__x.ah-visor__x:focus-visible, button.ah-visor__f.ah-visor__f:focus-visible{
  outline:1px solid var(--ah-lino); outline-offset:3px;
}
/* Con sesión iniciada la barra de WordPress (32 px; 46 en móvil) tapaba la ✕. */
body.admin-bar .ah-visor__x{ top:46px }
@media (max-width:782px){ body.admin-bar .ah-visor__x{ top:60px } }

/* Mientras el visor esta abierto la pagina no se mueve. Sin esto, al
   cerrar apareces cien pixeles mas abajo de donde estabas. */
html.ah-visor-puesto, html.ah-visor-puesto body{ overflow:hidden }

/* La foto pulsable se anuncia como pulsable. */
[data-ah-visor] img, .ah-galeria img{ cursor:zoom-in }

/* ---------------------------------------------------------------------
   E.9 - EL POP-UP DEL VIDEO
   Se adapta al VERTICAL, que es como graban para redes: un vertical
   dentro de un marco 16:9 deja dos franjas negras enormes.
   Nada de terceros se carga hasta que se pulsa: aqui solo esta la ropa.
   --------------------------------------------------------------------- */
.ah-vpop{
  position:fixed; inset:0; z-index:99981;
  background:var(--ah-negro);
  display:grid; place-items:center; padding:clamp(16px,4vh,48px);
  opacity:0; transition:opacity var(--ah-dur-inter) var(--ah-sale-suave);
}
.ah-vpop[hidden]{ display:none }
.ah-vpop.ah-abierto-v{ opacity:1 }
.ah-vpop__marco{
  position:relative;
  width:min(92vw, calc((100vh - 120px) * var(--ah-vpop-ratio,1.7778)));
  aspect-ratio:var(--ah-vpop-ratio,1.7778);
  max-height:calc(100vh - 120px);
  background:#000;
}
.ah-vpop__marco iframe{ position:absolute; inset:0; width:100%; height:100%; border:0 }
.ah-vpop__x{
  position:absolute; top:-46px; right:0;
  width:38px; height:38px; padding:0; cursor:pointer;
  background:none; border:1px solid rgba(244,244,237,.35); border-radius:0;
}
.ah-vpop__x::before, .ah-vpop__x::after{
  content:""; position:absolute; left:50%; top:50%;
  width:14px; height:1px; margin:-1px 0 0 -7px; background:var(--ah-lino);
}
.ah-vpop__x::before{ transform:rotate(45deg) }
.ah-vpop__x::after{ transform:rotate(-45deg) }
/* La salida honesta: si Instagram no deja incrustar, el boton LLEVA a
   Instagram en vez de romperse. */
.ah-vpop__fuera{
  position:absolute; left:50%; bottom:-44px; transform:translateX(-50%);
  font-size:11px; letter-spacing:.24em; text-transform:uppercase;
  color:var(--ah-lino); opacity:.72; text-decoration:none; white-space:nowrap;
}
.ah-vpop__fuera[hidden]{ display:none }

/* ---------------------------------------------------------------------
   E.10 - LA GALERIA EN BUCLE DE LA FICHA
   La foto activa centrada y las vecinas asomando por los dos lados. El
   bucle lo hace motion.js clonando las dos ultimas delante y las dos
   primeras detras; al aterrizar en un clon salta sin animacion a la real,
   y por eso el salto necesita poder apagar la transicion (`.ah-sin-t`).
   --------------------------------------------------------------------- */
.ah-galeria{ position:relative; overflow:hidden }
.ah-galeria-pista{
  display:flex; align-items:center; gap:clamp(20px,3.5vw,68px);
  will-change:transform;
  transition:transform var(--ah-dur-entrada) var(--ah-sale-suave);
}
.ah-galeria-pista.ah-sin-t{ transition:none }
.ah-galeria-pista > *{ flex:0 0 auto }

/* La medida de la foto activa, medida en Domus Nova a 1.904 px de ventana:
   58 % del ancho y proporcion 1,7:1. Sin ella cada `figure` toma el tamano
   natural de su imagen y la banda se descuadra —lo ensena la captura del
   10/09: fotos gigantes, alturas distintas y la pista fuera de sitio—.
   Es maqueta de markup que imprime un shortcode del plugin: no hay widget
   ni Style tab que la alcance. */
.ah-galeria-foto{
  margin:0; overflow:hidden;
  width:min(58vw,1107px); aspect-ratio:1.7/1;
}
.ah-galeria-pista img{ display:block; width:100%; height:100%; object-fit:cover }
@media (max-width:860px){
  .ah-galeria-foto{ width:82vw }
}
.ah-galeria__f{
  position:absolute; top:50%; transform:translateY(-50%);
  width:46px; height:46px; z-index:3; padding:0; cursor:pointer;
  display:grid; place-content:center;
  background:rgba(10,10,10,.42);
  border-radius:0;
  transition:background-color var(--ah-dur-inter) var(--ah-sale-suave);
}
/* El kit pinta CUALQUIER <button> con borde: `.elementor-kit-7
   button{border:1px #0A0A0A}`, especificidad (0,1,1) — le gana a una sola
   clase. Se dobla, la misma receta ya usada con el fondo negro del mismo
   selector (ver errores-conocidos.md). */
.ah-galeria__f.ah-galeria__f{ border:0 }
.ah-galeria__f:hover{ background:rgba(10,10,10,.72) }
.ah-galeria__f--ant{ left:clamp(10px,2vw,26px) }
.ah-galeria__f--sig{ right:clamp(10px,2vw,26px) }
.ah-galeria__f::before{
  content:""; width:9px; height:9px;
  border-top:1px solid var(--ah-lino); border-left:1px solid var(--ah-lino);
}
.ah-galeria__f--ant::before{ transform:translateX(2px) rotate(-45deg) }
.ah-galeria__f--sig::before{ transform:translateX(-2px) rotate(135deg) }
.ah-galeria-conteo{ font-variant-numeric:tabular-nums }

/* ---------------------------------------------------------------------
   E.11 - LA MAQUETA DE LO QUE SALE DE UN SHORTCODE
   Estas cuatro piezas las imprime el plugin, no un widget: no hay Style
   tab que las alcance, asi que su esqueleto vive aqui. SOLO esqueleto —
   display, columnas, huecos y reglas de 1 px—: ni un color de marca, ni
   una tipografia, ni un tamano de letra. Eso sigue siendo del Site
   Settings. Las reglas usan `currentColor`, asi que heredan el color que
   Elementor le haya dado a la seccion.
   --------------------------------------------------------------------- */
.ah-filtros{ display:flex; flex-wrap:wrap; align-items:end; gap:0 }
.ah-filtros .ah-filtro{ flex:1 1 140px; min-width:0; padding:12px 18px }
.ah-filtros .ah-filtro + .ah-filtro{ border-left:1px solid currentColor }
.ah-filtros .ah-filtro > label{ display:block }
.ah-filtros .ah-filtro select,
.ah-filtros .ah-filtro input{
  width:100%; padding:0; border:0; border-radius:0;
  background:none; color:inherit; font:inherit;
}
.ah-filtros-abrir{ display:none }
.ah-filtros-abrir, .ah-filtros-buscar{ border-radius:0; cursor:pointer }

/* El desplegable de movil (punto 4 de la lista del cliente, min 25:39):
   "Comprar/Alquilar" se queda FUERA, a la vista, y el resto se pliega
   detras del boton "Filtros". Nunca cinco desplegables apilados.

   ⚠️ El ESTADO se cuelga de `[data-ah-filtros]`, NO de la clase. En la home
   hay un contenedor de Elementor que tambien lleva la clase `ah-filtros`
   por fuera del formulario del shortcode: con la regla escrita por clase,
   ese contenedor de fuera —que nunca recibe `ah-desplegado`— seguia
   ocultando los campos plegables y el boton no abria nada. El atributo lo
   pone solo el shortcode, y su valor (`home` / `listado`) da igual: se
   selecciona por presencia, no por valor. Verificado el 10/09 a 416 px. */
@media (max-width:640px){
  [data-ah-filtros]{ display:grid; grid-template-columns:1fr auto }
  [data-ah-filtros] .ah-filtro-fijo{ grid-column:1 }
  .ah-filtros-abrir{ display:block; grid-column:2 }
  [data-ah-filtros] .ah-filtro-plegable{ grid-column:1/-1 }
  [data-ah-filtros]:not(.ah-desplegado) .ah-filtro-plegable{ display:none }
  [data-ah-filtros] .ah-filtro + .ah-filtro{ border-left:0; border-top:1px solid currentColor }
  .ah-filtros-buscar{ grid-column:1/-1 }
}

/* Las caracteristicas, a dos columnas, y la vinuela como un aro de 6 px:
   ni un icono en toda la ficha (prohibicion explicita del cliente). */
.ah-extras{ columns:2; column-gap:clamp(24px,4vw,64px); list-style:none; padding:0 }
.ah-extras li{ break-inside:avoid; position:relative; padding-left:18px }
.ah-extras li::before{
  content:""; position:absolute; left:0; top:.62em;
  width:6px; height:6px; border:1px solid currentColor; border-radius:50%;
}
@media (max-width:640px){ .ah-extras{ columns:1 } }

.ah-orden{ display:flex; align-items:center; gap:10px }
.ah-orden select{ background:none; border:0; border-radius:0; color:inherit; font:inherit }

/* Compartir en TEXTO, no los cinco logotipos de siempre: meter WhatsApp,
   LinkedIn y X aqui seria meter tres verdes, un azul y un negro ajenos en
   una web de negro, blanco y lino, y tres scripts de terceros que
   rastrean al lector aunque no pulse nada. El subrayado que crece de
   izquierda a derecha es el motivo 1 de la casa. */
.ah-compartir{ display:flex; flex-wrap:wrap; align-items:center; gap:clamp(14px,2vw,28px) }
.ah-compartir a, .ah-compartir button{
  position:relative; padding:0; border:0; border-radius:0;
  background:none; color:inherit; font:inherit;
  cursor:pointer; text-decoration:none;
}
.ah-compartir a::after, .ah-compartir button::after{
  content:""; position:absolute; left:0; right:0; bottom:-3px; height:1px;
  background:currentColor;
  transform:scaleX(0); transform-origin:left;
  transition:transform var(--ah-dur-inter) var(--ah-sale-suave);
}
.ah-compartir a:hover::after, .ah-compartir button:hover::after{ transform:scaleX(1) }

/* ---------------------------------------------------------------------
   E.12 - EL CANDADO DE OFF-MARKET
   Se abre al pasar el raton. El candado dice lo que el boton hace mejor
   que una flecha, y abrirse al acercarte es la metafora exacta del
   off-market: el acceso existe, hay que pedirlo.
   Se le levanta y se le inclina el arco desde su base, que es el gesto de
   un cierre soltandose. No hace falta un segundo icono ni un SVG partido
   en dos: con un solo activo y un `transform-origin` bien puesto se lee.
   --------------------------------------------------------------------- */
.ah-candado .elementor-button-icon{
  display:inline-block;
  transform-origin:20% 100%;
  transition:transform var(--ah-dur-inter) var(--ah-sale-suave);
}
.ah-candado:hover .elementor-button-icon,
.ah-candado:focus-within .elementor-button-icon{
  transform:translateY(-2px) rotate(-14deg);
}

/* ---------------------------------------------------------------------
   E.13 - REDUCCION DE MOVIMIENTO: todo al estado final, sin excepciones
   Quien la tenga activada ve la web completa y quieta. Es accesibilidad,
   y en un publico que incluye a gente mayor comprando casa es sentido
   comun (guion §7, regla 5).
   --------------------------------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  .ah-recorrido > .ah-sec-hero{ position:static }
  /* La cabecera cambia de color IGUAL —si no, el logo se pierde—, pero
     sin transicion: el estado, no el trayecto. */
  .ah-cab{ transition:none }
  .ah-hero-capa, .ah-hero-tit, .ah-hero-sub, .ah-test-cita,
  .ah-serv-casilla, .ah-serv-tit, .ah-serv-texto, .ah-serv-cta,
  .ah-fin-marca, .ah-galeria-pista,
  .ah-visor, .ah-visor__img, .ah-vpop{ transition:none }
  .ah-fin-slogan .ah-pal{ opacity:1; transform:none; transition:none }
  /* El `!important` del bloque C sobre `[data-rev]` encendia tambien el
     primer titular, y con la reduccion activada el hero mostraba dos
     frases a la vez. Aqui manda el relevo. */
  .ah-hero-tit:not(.ah-tit-activo){ opacity:0 !important }
  .ah-raton{ display:none }               /* el unico bucle de la web */
  .ah-val-cita{ filter:none !important; opacity:1 !important }
  .ah-visor__img{ opacity:1; transform:none }
}

/* ---------------------------------------------------------------------
   E.14 - CONTENIDO DE LECTURA (legales y articulo del blog)
   Excepcion razonada, y la unica de este tipo: el marcado de dentro lo
   escribe el EDITOR (widget Editor de texto ahora, the_content() en el
   articulo), no un widget. Elementor no tiene control de tipografia por
   etiqueta dentro de un editor de texto, y partir cada ley en dieciseis
   widgets seria peor remedio que la enfermedad. Por eso se estiliza POR
   ETIQUETA dentro del contenedor de lectura: el dia que Maria o Laura
   escriban un h2, una lista o un enlace, sale con formato sin poner una
   sola clase.
   Valores literales de prototipo/_articulo.tpl.html (bloque .cuerpo).
   ⚠️ Acotado a .cuerpo: los h2 del resto de la web son titulares de
   seccion y NO se tocan.
   --------------------------------------------------------------------- */
.cuerpo > *:first-child{ margin-top:0 }

.cuerpo h2{
  margin:2.4em 0 .7em;
  font:400 clamp(24px,2.6vw,36px)/1.15 "Instrument Serif",Georgia,serif;
  letter-spacing:-.02em;
}
.cuerpo h3{
  margin:2em 0 .5em;
  font:400 clamp(19px,1.8vw,24px)/1.25 "Instrument Serif",Georgia,serif;
}

.cuerpo a{
  color:inherit; text-decoration:none;
  border-bottom:1px solid rgba(10,10,10,.35); padding-bottom:1px;
}
.cuerpo a:hover{ border-bottom-color:#0A0A0A }
.cuerpo strong{ font-weight:600 }

.cuerpo ul, .cuerpo ol{ margin:0 0 1.5em; padding-left:1.2em }
.cuerpo li{ margin:0 0 .55em; padding-left:.3em }
/* la vineta es el aro de 6 px de la ficha de propiedad, no un disco */
.cuerpo ul{ list-style:none; padding-left:0 }
.cuerpo ul li{ position:relative; padding-left:26px }
.cuerpo ul li::before{
  content:''; position:absolute; left:2px; top:.62em;
  width:6px; height:6px; border:1px solid currentColor; opacity:.55;
}

.cuerpo blockquote{
  margin:2.2em 0; padding:0 0 0 clamp(20px,3vw,34px);
  border-left:1px solid rgba(10,10,10,.22);
  font:400 clamp(20px,2.1vw,30px)/1.4 "Instrument Serif",Georgia,serif;
  letter-spacing:-.01em;
}
.cuerpo blockquote p{ margin:0 }
.cuerpo hr{ border:0; height:1px; background:rgba(10,10,10,.14); margin:2.6em 0 }

/* ---------------------------------------------------------------------
   E.15 - EL RESIDUAL DE 1,8 px DEL LOGO DEL PIE
   El enlace que envuelve el logotipo del pie es en linea, asi que su caja
   de linea deja un hueco bajo la imagen que a 500 px se leia como 1,8 px
   de relleno superior de mas. Se cierra convirtiendo el enlace en bloque
   y anulando su caja de linea. No es espaciado: es la caja del enlace.
   --------------------------------------------------------------------- */
.elementor-widget-theme-site-logo a{ display:block; line-height:0 }

/* ---------------------------------------------------------------------
   E.16 - LA PROPORCION 4:5 DE LA FOTO DE LA TARJETA DE PROPIEDAD
   Encargo de ah-home. La foto de la tarjeta llevaba alto fijo en pixeles;
   ahora la caja la define la PROPORCION, no una altura. Sin esto la
   rejilla solo cuadra por casualidad, porque las fotos de demostracion
   son 800x1000: el dia que suban una apaisada, las filas se descuadran.
   Es geometria de mecanismo, no espaciado.
   --------------------------------------------------------------------- */
.ah-ratio-45 img{ aspect-ratio:4/5; height:auto; object-fit:cover }

/* =====================================================================
   E.17 - EL REVELADO: la seccion 2 sube por delante del hero
   Punto 1 de la lista del 10/09; decision del 03/09 (patron de Paola
   Masera). El hero ya es `sticky` dentro de `.ah-recorrido`; lo unico que
   falta es que la seccion siguiente EMPIECE antes, con margen negativo.

   ⚠️ ESTO NO ES ESPACIADO, es la geometria del mecanismo. Un margen
   negativo que hace que un bloque se monte sobre otro no es un valor que
   el cliente vaya a querer cambiar un martes por la tarde: es lo que
   produce el efecto, y va atado al alto del tramo que mide motion.js. Por
   eso ni puede ni debe ir en Avanzado -> Margen.

   La distancia la escribe motion.js en `--ah-revelado` (en PIXELES, no en
   vh, para que coincida exactamente con el alto que se ha sumado al
   recorrido). Sin JS no hay clase, no hay margen y la pagina se apila
   normal: la home se lee igual.

   El fondo de la seccion 2 tiene que ser opaco, o se veria el hero por
   debajo — lo pone ah-home con el control nativo de fondo.
   --------------------------------------------------------------------- */
.ah-revelado{ margin-top:calc(-1 * var(--ah-revelado, 0px)) }

/* Ver tambien `[data-bg]{position:relative;z-index:2}` en E.1: sin esa
   regla el hero pegajoso se pinta por delante de Servicios y las
   siguientes, porque el margen negativo sube TODA la pagina y entran en
   la zona donde el hero aun esta clavado. Darles fondo NO basta. */

/* =====================================================================
   E.18 - EL CARRIL LATERAL: el porcentaje de pagina
   Punto 2 de la lista del 10/09. Sergio autoriza CSS y JS externos para
   este componente, y con razon: no es contenido que el cliente edite, es
   cromo fijo que vive fuera de cualquier seccion. No hay widget de
   Elementor que lo exprese.
   Clonado al pixel de `.carril` de `prototipo/_loader.tpl.html`.
   --------------------------------------------------------------------- */
.ah-carril{
  position:fixed; z-index:50; left:0; bottom:0; width:96px;
  display:flex; flex-direction:column; align-items:center;
  gap:14px; padding-bottom:64px;
  color:var(--ah-lino);
  transition:color var(--ah-dur-salida) var(--ah-sale-suave),
             opacity var(--ah-dur-inter) var(--ah-sale-suave);
  opacity:0;                       /* lo enciende el JS tras la apertura */
  pointer-events:none;
}
.ah-carril.ah-on{ opacity:1; pointer-events:auto }
/* La inversion automatica de tema de ERA: sobre lino, en negro. Todo el
   componente usa `currentColor` justamente para esto. */
.ah-carril--claro{ color:var(--ah-negro) }

.ah-carril__pct{
  font-family:"Inter",-apple-system,"Segoe UI",sans-serif;
  font-size:11px; letter-spacing:.2em; opacity:.6; line-height:1;
  /* NO NEGOCIABLE: sin cifras tabulares, al pasar de 11 a 48 el numero
     cambia de anchura y BAILA. */
  font-variant-numeric:tabular-nums;
}
.ah-carril__linea{
  position:relative; width:1px; height:64px;
  background:currentColor; opacity:.22;
}
.ah-carril__linea i{
  position:absolute; inset:0 0 auto 0; height:100%; background:currentColor;
  transform:scaleY(0); transform-origin:top; will-change:transform;
}
/* El cue se queda toda la pagina —es la senal de que aqui se hace scroll,
   no un aviso que caduca— y es PULSABLE: salta a la seccion siguiente. */
.ah-carril__cue{
  -webkit-appearance:none; appearance:none; background:none; border:0; padding:0;
  color:inherit; font-family:inherit; cursor:pointer;
  display:flex; flex-direction:column; align-items:center; gap:14px;
  transition:opacity var(--ah-dur-inter) var(--ah-sale-suave);
}
.ah-carril__cue:hover{ opacity:.62 }
.ah-carril__cue:focus-visible{ outline:1px solid currentColor; outline-offset:6px }
/* Al final de la pagina la flecha se da la vuelta: «volver arriba». */
.ah-carril--fin .ah-carril__flecha svg{ transform:translate(-50%,-50%) rotate(90deg) }
/* ⚠️ Acotado a la palabra: si no, la flecha hereda el rotate(180deg) y
   apunta hacia arriba. Ya paso en el prototipo. */
.ah-carril__cue > span:not(.ah-carril__flecha){
  font-family:"Inter",-apple-system,"Segoe UI",sans-serif;
  font-size:9px; letter-spacing:.32em; text-transform:uppercase; opacity:.55;
  writing-mode:vertical-rl; transform:rotate(180deg); transform-origin:center;
  /* line-height 1 y el mismo ancho que la flecha: si no, el eje de la
     palabra y el de la flecha no coinciden y se ve desalineado. */
  line-height:1; width:12px; text-align:center;
}
/* OJO al centrado: el SVG mide 48 px de ancho dentro de una caja de 12.
   Con `place-items:center` el navegador lo coloca al inicio, su centro de
   giro cae 18 px a la derecha y la flecha se desalinea de la palabra. Se
   posiciona a mano. Y la punta del SVG original esta a la IZQUIERDA: hay
   que girar -90 grados para que apunte abajo. */
.ah-carril__flecha{
  position:relative; display:block; width:12px; height:48px;
  margin:10px 0; opacity:.8;
}
.ah-carril__flecha svg{
  position:absolute; top:50%; left:50%; width:48px; height:12px; display:block;
  transform:translate(-50%,-50%) rotate(-90deg);
}
@media (max-width:860px){ .ah-carril{ width:56px; padding-bottom:48px } }
/* NO NEGOCIABLE: por debajo de 640 px el carril entero se apaga. Con solo
   esconder la cifra, la palabra SCROLL se queda encima del parrafo del
   hero; y el porcentaje de pagina es un detalle de escritorio: en un
   telefono ese carril se come el margen y compite con el contenido. */
@media (max-width:640px){ .ah-carril{ display:none } }
@media (prefers-reduced-motion:reduce){ .ah-carril{ transition:none } }

/* =====================================================================
   E.19 - LA TARJETA DE PROPIEDAD: zoom al pasar el raton y chapa «Nueva»
   Punto 7 de la lista del 10/09.

   ⚠️ HAY TRES IMPLEMENTACIONES GEMELAS de esta tarjeta (bucle 629 de la
   home, bucle 179 de off-market y `ah_p_tarjeta()` en PHP). Las reglas de
   aqui cubren LAS TRES a la vez, que es justo lo que evita que queden dos
   disenos distintos en la misma web.

   Va por clase y no por control nativo porque ni el zoom en hover ni una
   chapa posicionada sobre la foto existen como control de Elementor: el
   widget imagen tiene «efectos al pasar el raton», pero son filtros CSS,
   no un transform con origen, curva y duracion propios.
   --------------------------------------------------------------------- */
/* --- el zoom suave: 1,03 en 1,2 s con la curva de la casa. Nada se eleva
   y nada proyecta sombra — regla 6 del guion.
   ⚠️ `position:var(--position,relative)`: es como lo declara Elementor,
   asi que un contenedor absoluto conserva su absoluto (errores-conocidos). */
.ah-rejilla-props .elementor-widget-image,
.ah-rejilla-privada .elementor-widget-image,
.ah-p .ficha__foto{ overflow:hidden; position:var(--position,relative) }
.ah-rejilla-props .elementor-widget-image img,
.ah-rejilla-privada .elementor-widget-image img,
.ah-p .ficha__foto img{ transition:transform 1.2s var(--ah-sale-suave) }
.ah-rejilla-props .e-loop-item:hover .elementor-widget-image img,
.ah-rejilla-privada .e-loop-item:hover .elementor-widget-image img,
.ah-p .ficha:hover .ficha__foto img{ transform:scale(1.03) }
@media (prefers-reduced-motion:reduce){
  .ah-rejilla-props .elementor-widget-image img,
  .ah-rejilla-privada .elementor-widget-image img,
  .ah-p .ficha__foto img{ transition:none }
  .ah-rejilla-props .e-loop-item:hover .elementor-widget-image img,
  .ah-rejilla-privada .e-loop-item:hover .elementor-widget-image img,
  .ah-p .ficha:hover .ficha__foto img{ transform:none }
}

/* --- la etiqueta de la tarjeta en los Loop de Elementor (home, zonas, similares, rejilla
   privada). Se ELIGE en el panel (15/10/2026); la clase `ah-etq-<etiqueta>` la pone el plugin
   con `post_class()` en el propio elemento del Loop, asi que no hace falta JavaScript ni pedir
   nada a la API. La tarjeta PHP del listado pinta la suya con un <span> (`.ficha__etiqueta`).
   Mismos valores que `.ficha__estado` del prototipo. --- */
.e-loop-item.ah-etq-nueva .elementor-widget-image::after,
.e-loop-item.ah-etq-exclusiva .elementor-widget-image::after,
.e-loop-item.ah-etq-reservada .elementor-widget-image::after{
  position:absolute; top:14px; left:14px; z-index:2;
  font-family:"Inter",-apple-system,"Segoe UI",sans-serif;
  font-size:10px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--ah-lino);
  background:rgba(10,10,10,.62); padding:6px 10px;
  pointer-events:none;
}
.e-loop-item.ah-etq-nueva .elementor-widget-image::after{ content:"Nueva" }
.e-loop-item.ah-etq-exclusiva .elementor-widget-image::after{ content:"Exclusiva" }
.e-loop-item.ah-etq-reservada .elementor-widget-image::after{ content:"Reservada" }

/* =====================================================================
   E.20 - LOS BOTONES «VER TODAS LAS PROPIEDADES»
   Punto 8 de la lista del 10/09. CSS externo autorizado.

   El hover de la casa es un BARRIDO de izquierda a derecha que invierte
   el color (motivo 2 del guion), no un cambio de fondo. Elementor solo
   tiene «color de fondo al pasar el raton»: un fundido plano. El barrido
   no sale de ningun control nativo — hace falta un pseudo-elemento con
   `transform-origin:left`.

   Se acota a la seccion de propiedades y se EXCLUYE la cabecera del
   bloque (`.ah-props-cab`), donde el prototipo pone un enlace de texto con
   subrayado que crece, no un boton relleno. Sin contar posiciones: dentro
   de un constructor nunca se cuentan posiciones.
   --------------------------------------------------------------------- */
.ah-sec-propiedades .elementor-widget-button .elementor-button{
  position:relative; overflow:hidden; z-index:0;
  transition:color var(--ah-dur-inter) var(--ah-sale-suave);
}
.ah-sec-propiedades .elementor-widget-button .elementor-button::before{
  content:""; position:absolute; inset:0; z-index:-1;
  background:var(--e-global-color-primary,#0A0A0A);
  transform:scaleX(0); transform-origin:left;
  transition:transform var(--ah-dur-inter) var(--ah-sale-suave);
}
.ah-sec-propiedades .elementor-widget-button .elementor-button:hover::before{ transform:scaleX(1) }
.ah-sec-propiedades .elementor-widget-button .elementor-button:hover{
  color:var(--e-global-color-secondary,#F4F4ED);
}
/* La cabecera del bloque no lleva barrido: alli es un enlace de texto con
   el subrayado que crece (motivo 1). */
.ah-props-cab .elementor-widget-button .elementor-button::before{ content:none }
.ah-props-cab .elementor-widget-button .elementor-button{ overflow:visible }
.ah-props-cab .elementor-widget-button .elementor-button::after{
  content:""; position:absolute; left:0; right:0; bottom:0; height:1px;
  background:currentColor; transform:scaleX(0); transform-origin:left;
  transition:transform var(--ah-dur-inter) var(--ah-sale-suave);
}
.ah-props-cab .elementor-widget-button .elementor-button:hover::after{ transform:scaleX(1) }
.ah-props-cab .elementor-widget-button .elementor-button:hover{ color:inherit }

/* =====================================================================
   E.21 - EL POP-UP DE OFF-MARKET
   Punto 9 de la lista del 10/09 = punto 5 de la lista del cliente.

   ⚠️ EL FORMULARIO NO ES MIO: lo monta un widget NATIVO de Elementor —lo
   unico que entrega el correo de verdad— dentro de un contenedor marcado
   `ah-off-form`. Aqui va solo el mecanismo del modal, que es lo que
   ningun control nativo expresa cuando el disparador es un boton que ya
   existe en la pagina.
   --------------------------------------------------------------------- */
.ah-off-form{ display:none }                 /* oculto hasta que el JS lo mueve */
.ah-modal .ah-off-form{ display:block }

.ah-modal{
  position:fixed; inset:0; z-index:120;
  display:grid; place-items:center;
  padding:clamp(16px,4vw,48px);
  background:rgba(5,5,5,.88);
  opacity:0; transition:opacity var(--ah-dur-inter) var(--ah-sale-suave);
}
/* ⚠ Sin esto, `display:grid` gana al `[hidden]{display:none}` del navegador
   (una regla de autor siempre pisa a la del agente de usuario) y el overlay
   se queda cubriendo la pantalla entera a z-index 120, invisible pero
   presente: se traga TODOS los clics de la pagina, el del propio boton que
   deberia abrirlo incluido. */
.ah-modal[hidden]{ display:none }
.ah-modal.ah-modal--on{ opacity:1 }
.ah-modal__caja{
  position:relative;
  width:min(560px,100%); max-height:88vh; overflow:auto;
  background:var(--e-global-color-secondary,#F4F4ED);
  color:var(--e-global-color-primary,#0A0A0A);
  border-radius:0;                            /* radio 0: regla de la casa */
  padding:clamp(28px,4vw,52px);
  transform:translateY(12px);
  transition:transform var(--ah-dur-entrada) var(--ah-sale-suave);
}
.ah-modal--on .ah-modal__caja{ transform:none }
.ah-modal__x{
  position:absolute; top:10px; right:12px;
  -webkit-appearance:none; appearance:none;
  background:none; border:0; cursor:pointer;
  font:400 26px/1 "Inter",sans-serif; color:inherit; opacity:.55;
  width:40px; height:40px;                    /* zona pulsable, no el glifo */
  transition:opacity var(--ah-dur-inter) var(--ah-sale-suave);
}
.ah-modal__x:hover{ opacity:1 }
/* Bloqueo del scroll con la posicion conservada: sin `position:fixed` en
   el cuerpo, iOS sigue haciendo scroll por detras del modal, y al cerrar
   apareces cien pixeles mas abajo de donde estabas. */
body.ah-bloqueado{ position:fixed; left:0; right:0; width:100%; overflow:hidden }
@media (prefers-reduced-motion:reduce){
  .ah-modal,.ah-modal__caja{ transition:none }
  .ah-modal__caja{ transform:none }
}

/* =====================================================================
   E.22 - LAS FLECHAS Y EL CONTADOR DE LOS TESTIMONIOS
   Punto 12 de la lista del 10/09. `ah-home` pone el widget NATIVO de
   testimonios; aqui solo se afinan colores y tamanos, que es lo que el
   widget no deja fijar: las flechas de Swiper tienen «tamano» y «color»
   pero no caja cuadrada con borde compartido entre las dos, y la
   paginacion de fraccion no tiene cifras tabulares.
   Valores clonados de `.test__flechas` y `.test__indice` del prototipo.
   🔎 Solo el widget nativo: la version a mano se retiro el 10/09.
   --------------------------------------------------------------------- */
/* ⚠️ Acotado el 10/09 a `.ah-test-carrusel`, el widget nativo
   (`testimonial-carousel`, `data-id="ahtestc1"`). Los selectores de la
   version a mano —`.ah-test-ant`, `.ah-test-sig`, `.ah-test-indice`— se
   retiran: esa version ya no se monta en ninguna pagina y mantener dos
   juegos de reglas para la misma pieza es la via rapida a que un dia se
   toque uno y no el otro. */
.ah-sec-testimonios .swiper-pagination-fraction{
  font-family:"Inter",-apple-system,"Segoe UI",sans-serif;
  font-size:11px; letter-spacing:.2em; opacity:.5; color:var(--ah-negro);
  font-variant-numeric:tabular-nums;   /* sin esto el 01 / 03 baila */
}

/* Sergio, 10/09/2026: indice y flechas MAL SITUADOS — Elementor pinta las
   flechas `position:absolute` a los lados del carrusel (encima de la
   cita) y la paginacion suelta y centrada abajo. El original las pone
   las tres en la MISMA FILA — indice a la izquierda, las dos flechas
   juntas a la derecha — con un separador de 1px encima. Se hace con CSS
   Grid en vez de flex porque el ORDEN REAL en el HTML de Swiper es
   pista-de-slides -> flecha-prev -> flecha-next -> paginacion, y con
   grid-row/grid-column explicitos el orden de origen deja de importar.

   ⚠️ La especificidad es la trampa: el core de Swiper pone
   `.swiper-pagination{position:absolute}` (0,1,0) y el propio Elementor
   pone `.elementor-element .swiper .elementor-swiper-button{position:
   absolute; ...; transform:translateY(-50%)}` a (0,3,0). Hacen falta
   CUATRO clases en el selector para ganarle sin `!important` — la misma
   regla de siempre (ya fichada con el boton negro del kit y con el
   `position` de `.ah-foto`): mirar la especificidad antes de subir el
   peso. */
.ah-sec-testimonios .ah-test-carrusel .elementor-main-swiper{
  display:grid;
  grid-template-columns:auto 1fr auto auto;
  grid-template-rows:auto auto auto;
  align-items:center;
}
.ah-sec-testimonios .ah-test-carrusel .swiper-wrapper{ grid-area:1/1/2/-1 }
/* el separador: una fila propia, para que la linea cruce TODO el ancho y
   no solo lo que ocupa el indice o las flechas por separado */
.ah-sec-testimonios .ah-test-carrusel .elementor-main-swiper::before{
  content:''; grid-area:2/1/3/-1;
  margin:clamp(34px,4.4vw,58px) 0 22px;
  border-top:1px solid rgba(10,10,10,.18);
}
/* la paginacion empata a (0,3,0) con la propia regla de Elementor
   (`.elementor-element .swiper .swiper-pagination-fraction`), y un empate
   lo gana quien cargue despues — no hay garantia de orden entre el CSS
   del plugin y el del child theme. Se dobla `.ah-sec-testimonios` para
   no depender de eso. */
.ah-sec-testimonios.ah-sec-testimonios .ah-test-carrusel .swiper-pagination,
.ah-sec-testimonios.ah-sec-testimonios .ah-test-carrusel .swiper-pagination-fraction{
  position:static; grid-area:3/1/4/2;
  text-align:left; width:auto; bottom:auto; left:auto;
}
.ah-sec-testimonios .ah-test-carrusel .swiper .elementor-swiper-button{
  position:static; grid-row:3; transform:none; top:auto; left:auto; right:auto;
  margin:0;
  width:52px; height:46px;
  display:grid; place-items:center;
  background:none; color:var(--ah-negro);
  border:1px solid rgba(10,10,10,.22); border-left-width:0;
  border-radius:0; cursor:pointer;
  transition:background var(--ah-dur-inter) var(--ah-sale-suave),
             color var(--ah-dur-inter) var(--ah-sale-suave);
}
.ah-sec-testimonios .ah-test-carrusel .swiper .elementor-swiper-button-prev{
  grid-column:3; border-left-width:1px;
}
.ah-sec-testimonios .ah-test-carrusel .swiper .elementor-swiper-button-next{
  grid-column:4;
}
.ah-sec-testimonios .elementor-swiper-button:hover{ background:var(--ah-negro); color:var(--ah-lino) }
.ah-sec-testimonios .elementor-swiper-button svg{ width:15px; height:15px; display:block }
/* Swiper dibuja ademas su propia flecha con una fuente de iconos y un
   `content`: se anula para que no compita con el SVG. */
.ah-sec-testimonios .swiper-button-next::after,
.ah-sec-testimonios .swiper-button-prev::after{ content:none }
/* La cita ocupa todo el ancho disponible (punto 11). */
.ah-sec-testimonios .elementor-testimonial__text{ max-width:none }

/* =====================================================================
   E.23 - LAS FOTOS DEL BLOG: zoom al pasar el raton
   Punto 14 de la lista del 10/09. Mismos valores que `.blog__foto img`
   del prototipo: 1,03 en 1,2 s. Mismo motivo que E.19 para que vaya por
   clase — el control nativo del widget imagen no hace transform.
   --------------------------------------------------------------------- */
.ah-rejilla-blog .elementor-widget-image{ overflow:hidden; position:var(--position,relative) }
.ah-rejilla-blog .elementor-widget-image img{ transition:transform 1.2s var(--ah-sale-suave) }
.ah-rejilla-blog .e-loop-item:hover .elementor-widget-image img{ transform:scale(1.03) }
@media (prefers-reduced-motion:reduce){
  .ah-rejilla-blog .elementor-widget-image img{ transition:none }
  .ah-rejilla-blog .e-loop-item:hover .elementor-widget-image img{ transform:none }
}

/* =====================================================================
   E.24 - TRES CLASES QUE PIDE `ah-paginas`
   Las tres son controles que el widget de formulario de Elementor
   sencillamente NO TIENE. No son espaciado de widget —que iria en
   Avanzado -> Relleno— sino el relleno INTERIOR de la caja del campo y
   del boton de envio, y el reparto de bordes del acordeon: cosas que
   viven dentro del widget y a las que su Style tab no llega.
   --------------------------------------------------------------------- */
/* 1) El campo. El control de relleno del widget formulario se aplica al
   grupo, no a la caja del control, y no alcanza al <select>, que en
   Elementor tiene caja propia. */
.ah-form-campo .elementor-field-textual,
.ah-form-campo input.elementor-field,
/* El kit imprime `.elementor-kit-7 input:not([type="button"]):not([type="submit"])`,
   que es (0,3,1) —los :not() cuentan— y gana a `.ah-form-campo input.elementor-field`
   (0,2,1). Se repite la forma del rival para subir a (0,4,1), sin !important.
   El textarea no lo necesita: alli el kit solo llega a (0,1,1). */
.ah-form-campo input.elementor-field:not([type="button"]):not([type="submit"]),
.ah-form-campo textarea.elementor-field,
.ah-form-campo select.elementor-field,
.ah-form-campo .elementor-field-type-select select{
  padding:9px;
}
/* 2) El boton de envio. El widget tiene tamanos predefinidos (xs..xl), no
   un relleno propio; y su control de margen mueve el formulario entero,
   no el boton dentro de el. */
.ah-form-boton .elementor-button[type="submit"],
.ah-form-boton button.elementor-button,
.ah-form-boton .elementor-field-type-submit .elementor-button{
  padding:17px clamp(24px,2.6vw,40px);
  margin-top:clamp(8px,1.2vw,14px);
}
/* 3) El acordeon de preguntas frecuentes. El control nativo de borde es
   UN grosor y dibuja los cuatro lados; aqui hace falta solo arriba y
   abajo, y sin doblar la regla entre dos items consecutivos. */
.ah-faq .e-n-accordion-item,
.ah-faq .elementor-accordion-item{
  border-width:1px 0 0 0; border-style:solid;
}
.ah-faq .e-n-accordion-item:last-child,
.ah-faq .elementor-accordion-item:last-child{
  border-bottom-width:1px;
}
/* Al retirar el borde nativo gana
   `.elementor-accordion .elementor-accordion-item + .elementor-accordion-item{border-block-start:none}`,
   que tiene la MISMA especificidad (0,2,0) y va despues. Se sube a (0,3,0) y se
   declara el lado explicito: la regla de 1 px entre preguntas es del prototipo. */
.ah-faq .elementor-accordion .elementor-accordion-item{
  border-block-start-width:1px; border-block-start-style:solid;
}

/* =====================================================================
   E.24 - EL LISTADO POR AJAX
   Punto 18 de la lista del 10/09. Aqui solo va la GEOMETRIA DEL
   MECANISMO: la aparicion del boton «cargar mas» y el estado de espera.
   Ni un espaciado, ni un color, ni una tipografia — todo eso es del
   Style tab y de `plantillas.css`.
   ===================================================================== */
/* El boton entra al asomar por el borde inferior. Aparece con el scroll
   pero NO carga solo: cargar al llegar roba el control del pie. */
.ah-p--listado .mas .boton{
  opacity:0; transform:translateY(10px);
  transition:opacity var(--ah-dur-entrada) var(--ah-sale-suave),
             transform var(--ah-dur-entrada) var(--ah-sale-suave);
}
.ah-p--listado .mas.ah-mas-on .boton{ opacity:1; transform:none }
/* ⚠️ Sin JavaScript no hay clase `ah-mas-on` y el boton se quedaria
   invisible: es el mismo principio del bloque C — el movimiento es una
   capa encima, nunca la condicion para poder usar la pagina. */
html:not(.ah-js) .ah-p--listado .mas .boton{ opacity:1; transform:none }
/* Mientras llega la tanda, la rejilla se apaga un poco: es la unica
   senal de espera y no mueve nada de sitio. */
.ah-p--listado[aria-busy="true"] .rejilla{
  opacity:.45; transition:opacity var(--ah-dur-salida) var(--ah-sale-suave);
}
@media (prefers-reduced-motion:reduce){
  .ah-p--listado .mas .boton{ opacity:1; transform:none; transition:none }
}
/* ⛔ HALLAZGO 10/09: `.ah-p .boton{display:inline-flex}` de `plantillas.css`
   tiene especificidad (0,2,0) y GANA al `[hidden]{display:none}` del
   navegador (0,1,0) porque va despues en la cascada. El atributo `hidden`
   se escribia bien —`archive-propiedad.php` y el JS del listado lo ponen y
   lo quitan correctamente— pero el boton se quedaba VISIBLE en pantalla y
   pulsable aunque no quedara nada que cargar: es el "boton espurio" del
   barrido R4. La cura, sin `!important`: subir la especificidad por encima
   de (0,2,0) repitiendo el atributo, la misma receta que ya se uso con el
   kit pintando los `<button>` de negro. */
.ah-p--listado .mas .boton[hidden]{ display:none }

/* =====================================================================
   E.25 - CONTACTO: UNA FOTO POR OFICINA
   Sergio, 11/09/2026: en vez de la foto unica que llevaba el bloque
   "Tres oficinas propias", una foto por columna — misma proporcion
   editorial 4:5 que las fichas de propiedad y el blog, para que la web
   siga teniendo una sola forma. El recorte va por clase (excepcion ya
   nombrada de "geometria del mecanismo"): el widget nativo de imagen no
   tiene control de `aspect-ratio`.
   --------------------------------------------------------------------- */
.ah-ofi-foto{ overflow:hidden; display:block; aspect-ratio:4/5 }
.ah-ofi-foto img{ width:100%; height:100%; object-fit:cover; display:block }
