Concebimos lugares donde la técnica, la sostenibilidad y la emoción, encuentran su equilibrio para crear una mejor manera de habitar.

SIMPLE

HÁBITAT

Arquitectura

sostenible


Diseñamos para transformar

la manera de habitar.

/* ================================================== 01. ESTADO SEGURO PREDETERMINADO Antes de que JavaScript confirme que todo funciona, el índice y el CXF permanecen visibles. De esta manera, si JavaScript falla, ninguno queda oculto permanentemente. ================================================== */ #po-guia { opacity: 1; visibility: visible; pointer-events: auto; translate: 0 0; } #po-corte-fachada { opacity: 1; visibility: visible; pointer-events: none; translate: 0 0; } /* ================================================== 02. ESTADO INICIAL CONTROLADO POR JAVASCRIPT JavaScript agrega la clase po-sistema-listo únicamente después de comprobar que existen todos los elementos indispensables. ================================================== */ #po-hero.po-sistema-listo #po-guia { opacity: 0; visibility: hidden; pointer-events: none; translate: -42px 0; transition: opacity 450ms ease, translate 500ms cubic-bezier(0.22, 1, 0.36, 1), visibility 0s linear 500ms; } #po-hero.po-sistema-listo #po-corte-fachada { opacity: 0; visibility: hidden; pointer-events: none; translate: -110px 0; transition: opacity 560ms ease 50ms, translate 720ms cubic-bezier(0.22, 1, 0.36, 1) 50ms, visibility 0s linear 770ms; } /* ================================================== 03. APERTURA DEL ÍNDICE Conserva el nombre de clase po-abierto usado en las versiones anteriores. ================================================== */ #po-hero.po-sistema-listo #po-guia.po-abierto { opacity: 1; visibility: visible; pointer-events: auto; translate: 0 0; transition: opacity 450ms ease, translate 500ms cubic-bezier(0.22, 1, 0.36, 1), visibility 0s linear 0s; } /* ================================================== 04. APARICIÓN LATERAL DEL CXF Entra junto con el índice, con un retraso pequeño para producir una ligera profundidad. ================================================== */ #po-hero.po-sistema-listo #po-corte-fachada.po-cxf-visible { opacity: 1; visibility: visible; pointer-events: none; translate: 0 0; transition: opacity 560ms ease 60ms, translate 720ms cubic-bezier(0.22, 1, 0.36, 1) 60ms, visibility 0s linear 0s; } /* ================================================== 05. BOTÓN INICIAL: RECORRER EL LUGAR ================================================== */ #po-acceso { cursor: pointer; opacity: 1; visibility: visible; transition: opacity 300ms ease, translate 300ms ease, visibility 0s linear 0s; } #po-acceso.po-oculto { opacity: 0; visibility: hidden; pointer-events: none; translate: 0 -6px; transition: opacity 300ms ease, translate 300ms ease, visibility 0s linear 300ms; } /* ================================================== 06. PIO DINÁMICO ================================================== */ #po-panel { position: absolute; /* * Distancia horizontal respecto al índice. * Un valor menor acerca todos los PO. */ left: 145px; opacity: 0; visibility: hidden; pointer-events: none; translate: -12px 0; transition: opacity 280ms ease, translate 280ms ease, visibility 0s linear 280ms, top 320ms ease; } /* Línea corta de conexión con cada PO */ #po-panel::before { content: ""; position: absolute; top: 50%; right: 100%; width: 14px; height: 1px; background: rgba(255, 255, 255, 0.55); transform: translateY(-50%) scaleX(0); transform-origin: right center; transition: transform 280ms ease; pointer-events: none; } /* Estado visible del PO */ #po-panel.po-visible { opacity: 1; visibility: visible; pointer-events: auto; translate: 0 0; transition: opacity 280ms ease, translate 280ms ease, visibility 0s linear 0s, top 320ms ease; } #po-panel.po-visible::before { transform: translateY(-50%) scaleX(1); } /* ================================================== 07. NIVELES DEL ÍNDICE ================================================== */ [id^="po-nivel-"] { cursor: pointer; transition: opacity 200ms ease; } [id^="po-nivel-"].po-activo { opacity: 1; } [id^="po-nivel-"].po-activo * { color: #B7D533 !important; } /* ================================================== 08. CONTADOR 00 / 08 ================================================== */ #po-etiqueta { color: rgba(255, 255, 255, 0.62); } #po-etiqueta .po-numero, #po-etiqueta .po-total { color: rgba(255, 255, 255, 0.62); } #po-etiqueta .po-diagonal { color: #B7D533; opacity: 1; } /* ================================================== 09. NOMBRE Y FRASE DE CADA PO ================================================== */ #po-nombre { color: #FFFFFF !important; } #po-frase { color: rgba(255, 255, 255, 0.78) !important; } /* ================================================== 10. ACCESIBILIDAD ================================================== */ @media (prefers-reduced-motion: reduce) { #po-guia, #po-acceso, #po-panel, #po-panel::before, #po-corte-fachada { transition-duration: 1ms !important; transition-delay: 0ms !important; } } (function () { function iniciarSistemaPO() { /* ============================================== 01. ELEMENTOS PRINCIPALES ============================================== */ const hero = document.getElementById('po-hero'); const indice = document.getElementById('po-indice'); const acceso = document.getElementById('po-acceso'); const guia = document.getElementById('po-guia'); const panel = document.getElementById('po-panel'); const etiqueta = document.getElementById('po-etiqueta'); const nombre = document.getElementById('po-nombre'); const frase = document.getElementById('po-frase'); const corte = document.getElementById('po-corte-fachada'); /* ============================================== 02. CONTENIDO DE LOS NUEVE PO ============================================== */ const datos = { '00': { nombre: 'VESTÍBULO', frase: 'Todo comienza cuando alguien imagina una vida distinta.' }, '01': { nombre: 'SALA', frase: 'La arquitectura comienza mucho antes del primer plano.' }, '02': { nombre: 'JARDÍN', frase: 'Materia, tiempo, contexto y habitantes son los componentes de la arquitectura.' }, '03': { nombre: 'BIBLIOTECA', frase: 'La convivencia da forma al habitar y, por lo tanto, a la arquitectura.' }, '04': { nombre: 'GALERÍA', frase: 'Muestra de nuestro enfoque y visión de lo que el habitar debe ser.' }, '05': { nombre: 'ESTUDIO', frase: 'El espacio donde una nueva conversación da inicio.' }, '06': { nombre: 'COCINA', frase: 'Lo que estamos “cocinando” en este momento.' }, '07': { nombre: 'COMEDOR', frase: 'La mesa puesta para nuestros socios, clientes y amigos.' }, '08': { nombre: 'MIRADOR', frase: 'Un vistazo a la ubicación de nuestros proyectos.' } }; /* ============================================== 03. VERIFICACIÓN DE ELEMENTOS Si falta algo, no se agrega po-sistema-listo. Por lo tanto, índice y CXF permanecen visibles. ============================================== */ if ( !hero || !indice || !acceso || !guia || !panel || !etiqueta || !nombre || !frase || !corte ) { console.warn( 'PO: falta uno o más elementos indispensables.' ); /* * Limpieza preventiva de clases antiguas. */ if (hero) { hero.classList.remove( 'po-sistema-listo' ); } if (guia) { guia.classList.remove( 'po-abierto' ); } if (corte) { corte.classList.remove( 'po-cxf-preparado', 'po-cxf-animar', 'po-cxf-visible' ); } return; } /* ============================================== 04. EVITAR EVENTOS DUPLICADOS ============================================== */ if ( indice.dataset.poInicializado === 'true' ) { return; } indice.dataset.poInicializado = 'true'; /* ============================================== 05. LIMPIAR CLASES DE VERSIONES ANTERIORES ============================================== */ hero.classList.remove( 'po-sistema-listo' ); guia.classList.remove( 'po-abierto' ); acceso.classList.remove( 'po-oculto' ); corte.classList.remove( 'po-cxf-preparado', 'po-cxf-animar', 'po-cxf-visible' ); /* * Eliminar estilos en línea relacionados con * pruebas anteriores de animación. */ corte.style.removeProperty( 'clip-path' ); corte.style.removeProperty( 'opacity' ); corte.style.removeProperty( 'visibility' ); corte.style.removeProperty( 'translate' ); /* ============================================== 06. OBTENER LOS NUEVE NIVELES ============================================== */ const niveles = guia.querySelectorAll( '[id^="po-nivel-"]' ); if (!niveles.length) { console.warn( 'PO: no se encontraron los niveles del índice.' ); return; } let temporizadorSalida; /* ============================================== 07. LIMPIAR NIVEL ACTIVO ============================================== */ function limpiarActivos() { niveles.forEach( function (nivel) { nivel.classList.remove( 'po-activo' ); } ); } /* ============================================== 08. MOSTRAR EL PO CORRESPONDIENTE ============================================== */ function mostrarPIO(nivel) { clearTimeout( temporizadorSalida ); const numero = nivel.id.replace( 'po-nivel-', '' ); const contenido = datos[numero]; if (!contenido) { return; } /* Contador */ etiqueta.innerHTML = '' + numero + '' + '' + ' / ' + '' + '' + '08' + ''; /* Nombre */ nombre.textContent = contenido.nombre; /* Frase específica */ frase.textContent = contenido.frase; /* ============================================ RECORRIDO VERTICAL EN TODO EL HERO ============================================ */ const heroRect = hero.getBoundingClientRect(); const indiceRect = indice.getBoundingClientRect(); const altoPanel = panel.offsetHeight || 135; /* * Márgenes superior e inferior del recorrido. */ const margenSuperior = 24; const margenInferior = 24; /* * Niv. 08 queda arriba. * Niv. 00 queda abajo. */ const numeroNivel = parseInt(numero, 10); const progreso = (8 - numeroNivel) / 8; /* * Recorrido disponible. */ const recorridoDisponible = Math.max( 0, heroRect.height - margenSuperior - margenInferior - altoPanel ); /* * Posición respecto al Hero. */ const posicionRespectoHero = margenSuperior + progreso * recorridoDisponible; /* * Conversión a coordenadas de FB PO Índice. */ const posicionPanel = heroRect.top - indiceRect.top + posicionRespectoHero; panel.style.top = posicionPanel + 'px'; /* Activar y mostrar */ limpiarActivos(); nivel.classList.add( 'po-activo' ); panel.classList.add( 'po-visible' ); } /* ============================================== 09. OCULTAR EL PO ============================================== */ function ocultarPIO() { temporizadorSalida = setTimeout( function () { panel.classList.remove( 'po-visible' ); limpiarActivos(); }, 180 ); } /* ============================================== 10. INTERACCIONES DE LOS NIVELES ============================================== */ niveles.forEach( function (nivel) { nivel.addEventListener( 'mouseenter', function () { mostrarPIO(nivel); } ); nivel.addEventListener( 'mouseleave', ocultarPIO ); nivel.addEventListener( 'click', function (evento) { evento.preventDefault(); mostrarPIO(nivel); } ); nivel.addEventListener( 'focusin', function () { mostrarPIO(nivel); } ); } ); /* ============================================== 11. MANTENER VISIBLE AL PASAR SOBRE EL PO ============================================== */ panel.addEventListener( 'mouseenter', function () { clearTimeout( temporizadorSalida ); } ); panel.addEventListener( 'mouseleave', ocultarPIO ); /* ============================================== 12. ABRIR ÍNDICE Y CXF SIMULTÁNEAMENTE ============================================== */ acceso.addEventListener( 'click', function (evento) { evento.preventDefault(); /* * Entrada lateral del índice. */ guia.classList.add( 'po-abierto' ); /* * Entrada lateral del CXF. */ corte.classList.add( 'po-cxf-visible' ); /* * Desaparición del botón. */ acceso.classList.add( 'po-oculto' ); } ); /* ============================================== 13. ACTIVAR EL ESTADO INICIAL OCULTO Solo se hace después de: - comprobar todos los elementos; - encontrar los niveles; - registrar las interacciones; - registrar el clic del botón. ============================================== */ window.requestAnimationFrame( function () { window.requestAnimationFrame( function () { hero.classList.add( 'po-sistema-listo' ); } ); } ); } /* ============================================== 14. INICIAR EL SISTEMA ============================================== */ if ( document.readyState === 'loading' ) { document.addEventListener( 'DOMContentLoaded', iniciarSistemaPO ); } else { iniciarSistemaPO(); } })();

ESPACIO

00 / 08

VESTÍBULO →

⟶

La arquitectura comienza mucho antes del primer plano.

Niv.

08

Niv.

07

Niv.

06

Niv.

05

Niv.

04

Niv.

03

Niv.

02

Niv.

01

Niv.

00

/* ================================================== ESCRITURA HERO SIN DESPLAZAMIENTO Las letras ocupan desde el inicio su lugar final. Solo van apareciendo una por una. ================================================== */ .tw-palabra { display: inline-block; white-space: nowrap; } .tw-letra { display: inline; opacity: 0; visibility: hidden; } .tw-letra.tw-visible { opacity: 1; visibility: visible; } /* ================================================== ICONOS ================================================== */ #hero-icono-escuadra, #hero-icono-recorrer { opacity: 0; visibility: hidden; transition: opacity 280ms ease, visibility 0s linear 280ms; } #hero-icono-escuadra.tw-icono-visible, #hero-icono-recorrer.tw-icono-visible { opacity: 1; visibility: visible; transition: opacity 280ms ease, visibility 0s linear 0s; } /* ================================================== EVITAR DESTELLO DEL TEXTO ANTES DE PREPARARLO ================================================== */ html.tw-preparando #hero-texto-horizontal, html.tw-preparando #hero-texto-vertical, html.tw-preparando #hero-texto-recorrer { opacity: 0; } html.tw-listo #hero-texto-horizontal, html.tw-listo #hero-texto-vertical, html.tw-listo #hero-texto-recorrer { opacity: 1; } /* ================================================== ACCESIBILIDAD ================================================== */ @media (prefers-reduced-motion: reduce) { .tw-letra { opacity: 1 !important; visibility: visible !important; } #hero-icono-escuadra, #hero-icono-recorrer { opacity: 1 !important; visibility: visible !important; } } (function () { document.documentElement.classList.add( 'tw-preparando' ); function esperar(milisegundos) { return new Promise( function (resolver) { window.setTimeout( resolver, milisegundos ); } ); } /* * Localiza el elemento real que contiene el texto. * Elementor puede colocar el ID en un envolvente. */ function encontrarNodoTexto(id) { const contenedor = document.getElementById(id); if (!contenedor) { return null; } const interior = contenedor.querySelector( [ '.elementor-heading-title', '.elementor-button-text', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'a', 'button' ].join(',') ); return interior || contenedor; } /* * Convierte cada palabra en letras individuales. * Todas conservan su espacio desde el inicio. */ function prepararTexto(elemento) { if (!elemento) { return []; } const textoOriginal = (elemento.textContent || '') .replace(/\s+/g, ' ') .trim(); if (!textoOriginal) { return []; } elemento.textContent = ''; const letras = []; const partes = textoOriginal.split(/(\s+)/); partes.forEach( function (parte) { if (/^\s+$/.test(parte)) { elemento.appendChild( document.createTextNode(' ') ); return; } const palabra = document.createElement('span'); palabra.className = 'tw-palabra'; Array.from(parte).forEach( function (caracter) { const letra = document.createElement('span'); letra.className = 'tw-letra'; letra.textContent = caracter; palabra.appendChild( letra ); letras.push( letra ); } ); elemento.appendChild( palabra ); } ); return letras; } /* * Revela las letras una por una. */ async function escribirLetras( letras, velocidad ) { for ( let indice = 0; indice < letras.length; indice++ ) { letras[indice].classList.add( 'tw-visible' ); await esperar( velocidad ); } } function mostrarIcono(icono) { if (!icono) { return; } icono.classList.add( 'tw-icono-visible' ); } async function iniciarEscrituraHero() { const horizontal = encontrarNodoTexto( 'hero-texto-horizontal' ); const vertical = encontrarNodoTexto( 'hero-texto-vertical' ); const recorrer = encontrarNodoTexto( 'hero-texto-recorrer' ); const iconoEscuadra = document.getElementById( 'hero-icono-escuadra' ); const iconoRecorrer = document.getElementById( 'hero-icono-recorrer' ); /* * Si falta un texto, se deja todo visible * para no dañar el Hero. */ if ( !horizontal || !vertical || !recorrer ) { console.warn( 'Escritura Hero: falta uno o más ID.' ); document.documentElement.classList.remove( 'tw-preparando' ); document.documentElement.classList.add( 'tw-listo' ); mostrarIcono( iconoEscuadra ); mostrarIcono( iconoRecorrer ); return; } /* * Preparar todos los textos antes de animarlos. */ const letrasHorizontal = prepararTexto( horizontal ); const letrasVertical = prepararTexto( vertical ); const letrasRecorrer = prepararTexto( recorrer ); document.documentElement.classList.remove( 'tw-preparando' ); document.documentElement.classList.add( 'tw-listo' ); /* * Secuencia */ await esperar(500); /* 1. Diseñamos para transformar */ await escribirLetras( letrasHorizontal, 48 ); await esperar(180); /* 2. La manera de habitar */ await escribirLetras( letrasVertical, 48 ); await esperar(120); /* 3. Icono de la escuadra */ mostrarIcono( iconoEscuadra ); await esperar(320); /* 4. Recorrer el lugar */ await escribirLetras( letrasRecorrer, 44 ); await esperar(100); /* 5. Icono del botón */ mostrarIcono( iconoRecorrer ); } if ( document.readyState === 'loading' ) { document.addEventListener( 'DOMContentLoaded', iniciarEscrituraHero ); } else { iniciarEscrituraHero(); } })();

Niv.

01

SALA

No diseñamos edificios.
Diseñamos la manera en que las personas habitan el mundo.

Creemos que la arquitectura no comienza con un plano. Comienza cuando alguien imagina una vida distinta. Concebimos lugares donde la técnica, la sostenibilidad y la emoción encuentran su equilibrio para crear una mejor manera de habitar.

01 / 08

La arquitectura comienza
mucho antes del primer plano.