feat: public site landing page with header, footer, styles

- Header with fixed navbar, responsive mobile menu, services dropdown
- Landing page with hero, services grid, value propositions, testimonials, contact
- Comprehensive CSS (1300+ lines): navy/gold brand colors, custom properties,
  responsive breakpoints, card hover effects, form styles, print & a11y
- Footer with 3-column layout, contact info, social links
- JS: hamburger toggle, smooth scroll, navbar scroll effect, scroll animations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Gestoría LP
2026-03-01 23:59:13 +00:00
parent 0adb418252
commit 8280d59d84
5 changed files with 1926 additions and 0 deletions

1342
assets/css/style.css Normal file

File diff suppressed because it is too large Load Diff

169
assets/js/main.js Normal file
View File

@@ -0,0 +1,169 @@
/**
* Gestoría LP — Main JavaScript
* Handles: mobile menu, smooth scroll, navbar scroll effect, scroll animations
*/
document.addEventListener('DOMContentLoaded', function () {
// ---- DOM References ----
const navbar = document.getElementById('navbar');
const navToggle = document.getElementById('navToggle');
const navMenu = document.getElementById('navMenu');
const body = document.body;
// Create overlay element for mobile menu backdrop
const overlay = document.createElement('div');
overlay.classList.add('navbar__overlay');
document.body.appendChild(overlay);
// ================================================================
// 1. Mobile Hamburger Menu Toggle
// ================================================================
function openMenu() {
navToggle.classList.add('active');
navMenu.classList.add('active');
overlay.classList.add('active');
navToggle.setAttribute('aria-expanded', 'true');
body.style.overflow = 'hidden';
}
function closeMenu() {
navToggle.classList.remove('active');
navMenu.classList.remove('active');
overlay.classList.remove('active');
navToggle.setAttribute('aria-expanded', 'false');
body.style.overflow = '';
}
if (navToggle) {
navToggle.addEventListener('click', function () {
if (navMenu.classList.contains('active')) {
closeMenu();
} else {
openMenu();
}
});
}
// Close menu when clicking overlay
overlay.addEventListener('click', closeMenu);
// Close menu when pressing Escape
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape' && navMenu.classList.contains('active')) {
closeMenu();
}
});
// ================================================================
// 2. Mobile Dropdown Toggle
// ================================================================
var dropdownItems = document.querySelectorAll('.navbar__item--dropdown');
dropdownItems.forEach(function (item) {
var link = item.querySelector('.navbar__link--dropdown');
if (link) {
link.addEventListener('click', function (e) {
// Only toggle on mobile
if (window.innerWidth <= 768) {
e.preventDefault();
item.classList.toggle('active');
}
});
}
});
// ================================================================
// 3. Smooth Scroll for Anchor Links
// ================================================================
var anchorLinks = document.querySelectorAll('a[href^="#"]');
anchorLinks.forEach(function (link) {
link.addEventListener('click', function (e) {
var targetId = this.getAttribute('href');
if (targetId === '#') return;
var target = document.querySelector(targetId);
if (target) {
e.preventDefault();
closeMenu();
var navHeight = navbar ? navbar.offsetHeight : 0;
var targetPos = target.getBoundingClientRect().top + window.pageYOffset - navHeight;
window.scrollTo({
top: targetPos,
behavior: 'smooth'
});
}
});
});
// ================================================================
// 4. Navbar Background/Shadow on Scroll
// ================================================================
var lastScrollY = 0;
function handleNavbarScroll() {
var scrollY = window.pageYOffset || document.documentElement.scrollTop;
if (scrollY > 20) {
navbar.classList.add('navbar--scrolled');
} else {
navbar.classList.remove('navbar--scrolled');
}
lastScrollY = scrollY;
}
if (navbar) {
window.addEventListener('scroll', handleNavbarScroll, { passive: true });
// Run once on load
handleNavbarScroll();
}
// ================================================================
// 5. Scroll Animations (Testimonials & fade-up elements)
// ================================================================
function animateOnScroll() {
// Testimonial cards
var testimonialCards = document.querySelectorAll('.testimonial-card:not(.animate-in)');
testimonialCards.forEach(function (card, index) {
var rect = card.getBoundingClientRect();
var windowHeight = window.innerHeight;
if (rect.top < windowHeight * 0.88) {
// Stagger the animation
setTimeout(function () {
card.classList.add('animate-in');
}, index * 120);
}
});
// Generic fade-up elements
var fadeElements = document.querySelectorAll('.fade-up:not(.visible)');
fadeElements.forEach(function (el) {
var rect = el.getBoundingClientRect();
var windowHeight = window.innerHeight;
if (rect.top < windowHeight * 0.88) {
el.classList.add('visible');
}
});
}
window.addEventListener('scroll', animateOnScroll, { passive: true });
// Run once on load to catch elements already in viewport
animateOnScroll();
// ================================================================
// 6. Close mobile dropdown on window resize to desktop
// ================================================================
window.addEventListener('resize', function () {
if (window.innerWidth > 768) {
closeMenu();
dropdownItems.forEach(function (item) {
item.classList.remove('active');
});
}
});
});

67
includes/footer.php Normal file
View File

@@ -0,0 +1,67 @@
</main>
<!-- Footer -->
<footer class="footer">
<div class="container">
<div class="footer__grid">
<!-- About Column -->
<div class="footer__col">
<h3 class="footer__heading">
<i class="fa-solid fa-scale-balanced"></i> Gestoría LP
</h3>
<p class="footer__text">
Somos una gestoría profesional especializada en trámites migratorios.
Te acompañamos en cada paso de tu proceso para que obtengas tus documentos
de manera segura, rápida y sin complicaciones.
</p>
</div>
<!-- Contact Column -->
<div class="footer__col">
<h3 class="footer__heading">Contacto</h3>
<ul class="footer__contact-list">
<li>
<i class="fa-solid fa-phone"></i>
<a href="tel:+521XXXXXXXXXX">(+52) 1 XXX XXX XXXX</a>
</li>
<li>
<i class="fa-solid fa-envelope"></i>
<a href="mailto:contacto@gestorialp.com">contacto@gestorialp.com</a>
</li>
<li>
<i class="fa-solid fa-location-dot"></i>
<span>La Paz, Baja California Sur, México</span>
</li>
<li>
<i class="fa-brands fa-whatsapp"></i>
<a href="https://wa.me/521XXXXXXXXXX" target="_blank" rel="noopener">WhatsApp</a>
</li>
</ul>
</div>
<!-- Social & Links Column -->
<div class="footer__col">
<h3 class="footer__heading">Síguenos</h3>
<div class="footer__social">
<a href="https://facebook.com/" target="_blank" rel="noopener" class="footer__social-link" aria-label="Facebook">
<i class="fa-brands fa-facebook-f"></i>
</a>
</div>
<h3 class="footer__heading footer__heading--mt">Horario</h3>
<p class="footer__text">
Lunes a Viernes: 9:00 AM 6:00 PM<br>
Sábado: 9:00 AM 2:00 PM
</p>
</div>
</div>
<div class="footer__bottom">
<p>&copy; 2026 Gestoría LP. Todos los derechos reservados.</p>
</div>
</div>
</footer>
<!-- Main JS -->
<script src="assets/js/main.js"></script>
</body>
</html>

66
includes/header.php Normal file
View File

@@ -0,0 +1,66 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Gestoría LP — Expertos en trámites migratorios: visa americana, SENTRI, pasaporte, doble nacionalidad y más.">
<title><?= isset($pageTitle) ? htmlspecialchars($pageTitle) . ' | Gestoría LP' : 'Gestoría LP — Trámites Migratorios Profesionales' ?></title>
<!-- Google Fonts -->
<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=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<!-- Font Awesome 6 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA==" crossorigin="anonymous" referrerpolicy="no-referrer">
<!-- Site Stylesheet -->
<link rel="stylesheet" href="assets/css/style.css">
</head>
<body>
<!-- Navigation -->
<header class="navbar" id="navbar">
<div class="container navbar__inner">
<a href="index.php" class="navbar__brand">
<i class="fa-solid fa-scale-balanced"></i>
<span>Gestoría <strong>LP</strong></span>
</a>
<nav class="navbar__menu" id="navMenu">
<ul class="navbar__list">
<li class="navbar__item">
<a href="index.php" class="navbar__link">Inicio</a>
</li>
<li class="navbar__item navbar__item--dropdown">
<a href="#servicios" class="navbar__link navbar__link--dropdown">
Servicios <i class="fa-solid fa-chevron-down"></i>
</a>
<ul class="navbar__dropdown">
<?php
require_once __DIR__ . '/servicios-data.php';
foreach ($SERVICIOS as $slug => $servicio): ?>
<li>
<a href="servicio.php?s=<?= htmlspecialchars($slug) ?>" class="navbar__dropdown-link">
<i class="fa-solid <?= htmlspecialchars($servicio['icono']) ?>"></i>
<?= htmlspecialchars($servicio['nombre']) ?>
</a>
</li>
<?php endforeach; ?>
</ul>
</li>
<li class="navbar__item">
<a href="#contacto" class="navbar__link">Contacto</a>
</li>
</ul>
</nav>
<button class="navbar__toggle" id="navToggle" aria-label="Abrir menú" aria-expanded="false">
<span class="navbar__toggle-bar"></span>
<span class="navbar__toggle-bar"></span>
<span class="navbar__toggle-bar"></span>
</button>
</div>
</header>
<main>

282
index.php Normal file
View File

@@ -0,0 +1,282 @@
<?php
require_once __DIR__ . '/includes/servicios-data.php';
require_once __DIR__ . '/includes/db.php';
$pageTitle = 'Inicio';
include __DIR__ . '/includes/header.php';
// Fetch active testimonials
$testimonios = [];
try {
$pdo = getDB();
$stmt = $pdo->query("SELECT nombre_cliente, texto, calificacion FROM testimonios WHERE activo = 1 ORDER BY created_at DESC LIMIT 6");
$testimonios = $stmt->fetchAll();
} catch (Exception $e) {
// Database may not be available; we'll show placeholders
}
?>
<!-- ===== HERO SECTION ===== -->
<section class="hero" id="inicio">
<div class="hero__overlay"></div>
<div class="container hero__content">
<h1 class="hero__title">Tu trámite migratorio, sin complicaciones</h1>
<p class="hero__subtitle">
Somos expertos en visa americana, SENTRI, pasaporte y doble nacionalidad.
Te guiamos paso a paso para que obtengas tus documentos con confianza y tranquilidad.
</p>
<div class="hero__actions">
<a href="#servicios" class="btn btn--primary btn--lg">
<i class="fa-solid fa-arrow-right"></i> Ver servicios
</a>
<a href="https://wa.me/521XXXXXXXXXX" target="_blank" rel="noopener" class="btn btn--outline btn--lg">
<i class="fa-brands fa-whatsapp"></i> Escríbenos
</a>
</div>
</div>
</section>
<!-- ===== SERVICES SECTION ===== -->
<section class="section services" id="servicios">
<div class="container">
<div class="section__header">
<span class="section__badge">Nuestros Servicios</span>
<h2 class="section__title">Trámites que realizamos</h2>
<p class="section__subtitle">Ofrecemos un acompañamiento completo en cada proceso migratorio y documental.</p>
</div>
<div class="services__grid">
<?php foreach ($SERVICIOS as $slug => $servicio): ?>
<article class="card card--service">
<div class="card__icon">
<i class="fa-solid <?= htmlspecialchars($servicio['icono']) ?>"></i>
</div>
<h3 class="card__title"><?= htmlspecialchars($servicio['nombre']) ?></h3>
<p class="card__text">
<?= htmlspecialchars(mb_strimwidth($servicio['descripcion'], 0, 120, '...')) ?>
</p>
<a href="servicio.php?s=<?= htmlspecialchars($slug) ?>" class="card__link">
Más información <i class="fa-solid fa-arrow-right"></i>
</a>
</article>
<?php endforeach; ?>
</div>
</div>
</section>
<!-- ===== WHY CHOOSE US ===== -->
<section class="section values" id="por-que">
<div class="container">
<div class="section__header">
<span class="section__badge">Por qué elegirnos</span>
<h2 class="section__title">Tu tranquilidad es nuestra prioridad</h2>
<p class="section__subtitle">Más que una gestoría, somos tu aliado en cada trámite.</p>
</div>
<div class="values__grid">
<div class="value-card">
<div class="value-card__icon">
<i class="fa-solid fa-award"></i>
</div>
<h3 class="value-card__title">Experiencia comprobada</h3>
<p class="value-card__text">
Años de experiencia resolviendo trámites migratorios con altos índices de éxito.
</p>
</div>
<div class="value-card">
<div class="value-card__icon">
<i class="fa-solid fa-handshake"></i>
</div>
<h3 class="value-card__title">Atención personalizada</h3>
<p class="value-card__text">
Cada caso es único. Te brindamos asesoría individual adaptada a tu situación.
</p>
</div>
<div class="value-card">
<div class="value-card__icon">
<i class="fa-solid fa-eye"></i>
</div>
<h3 class="value-card__title">Proceso transparente</h3>
<p class="value-card__text">
Sabrás en todo momento el estado de tu trámite. Sin sorpresas ni costos ocultos.
</p>
</div>
<div class="value-card">
<div class="value-card__icon">
<i class="fa-solid fa-shield-halved"></i>
</div>
<h3 class="value-card__title">Resultados garantizados</h3>
<p class="value-card__text">
Nos comprometemos con tu trámite hasta obtener un resultado favorable.
</p>
</div>
</div>
</div>
</section>
<!-- ===== TESTIMONIALS SECTION ===== -->
<section class="section testimonials" id="testimonios">
<div class="container">
<div class="section__header">
<span class="section__badge">Testimonios</span>
<h2 class="section__title">Lo que dicen nuestros clientes</h2>
<p class="section__subtitle">La satisfacción de quienes confían en nosotros es nuestro mejor aval.</p>
</div>
<div class="testimonials__grid">
<?php if (!empty($testimonios)): ?>
<?php foreach ($testimonios as $testimonio): ?>
<div class="testimonial-card">
<div class="testimonial-card__stars">
<?php for ($i = 1; $i <= 5; $i++): ?>
<i class="fa-solid fa-star <?= $i <= (int)$testimonio['calificacion'] ? 'testimonial-card__star--active' : 'testimonial-card__star--inactive' ?>"></i>
<?php endfor; ?>
</div>
<blockquote class="testimonial-card__text">
"<?= htmlspecialchars($testimonio['texto']) ?>"
</blockquote>
<div class="testimonial-card__author">
<div class="testimonial-card__avatar">
<i class="fa-solid fa-user"></i>
</div>
<span class="testimonial-card__name"><?= htmlspecialchars($testimonio['nombre_cliente']) ?></span>
</div>
</div>
<?php endforeach; ?>
<?php else: ?>
<!-- Placeholder testimonials when database is empty -->
<div class="testimonial-card">
<div class="testimonial-card__stars">
<i class="fa-solid fa-star testimonial-card__star--active"></i>
<i class="fa-solid fa-star testimonial-card__star--active"></i>
<i class="fa-solid fa-star testimonial-card__star--active"></i>
<i class="fa-solid fa-star testimonial-card__star--active"></i>
<i class="fa-solid fa-star testimonial-card__star--active"></i>
</div>
<blockquote class="testimonial-card__text">
"Excelente servicio. Me ayudaron con mi visa americana desde el formulario hasta la entrevista. Todo salió perfecto."
</blockquote>
<div class="testimonial-card__author">
<div class="testimonial-card__avatar">
<i class="fa-solid fa-user"></i>
</div>
<span class="testimonial-card__name">María G.</span>
</div>
</div>
<div class="testimonial-card">
<div class="testimonial-card__stars">
<i class="fa-solid fa-star testimonial-card__star--active"></i>
<i class="fa-solid fa-star testimonial-card__star--active"></i>
<i class="fa-solid fa-star testimonial-card__star--active"></i>
<i class="fa-solid fa-star testimonial-card__star--active"></i>
<i class="fa-solid fa-star testimonial-card__star--active"></i>
</div>
<blockquote class="testimonial-card__text">
"Gracias a Gestoría LP obtuve mi SENTRI en tiempo récord. Muy profesionales y atentos en todo momento."
</blockquote>
<div class="testimonial-card__author">
<div class="testimonial-card__avatar">
<i class="fa-solid fa-user"></i>
</div>
<span class="testimonial-card__name">Carlos R.</span>
</div>
</div>
<div class="testimonial-card">
<div class="testimonial-card__stars">
<i class="fa-solid fa-star testimonial-card__star--active"></i>
<i class="fa-solid fa-star testimonial-card__star--active"></i>
<i class="fa-solid fa-star testimonial-card__star--active"></i>
<i class="fa-solid fa-star testimonial-card__star--active"></i>
<i class="fa-solid fa-star testimonial-card__star--active"></i>
</div>
<blockquote class="testimonial-card__text">
"Renové mi pasaporte sin contratiempos. El equipo fue muy amable y me guió en cada paso del proceso."
</blockquote>
<div class="testimonial-card__author">
<div class="testimonial-card__avatar">
<i class="fa-solid fa-user"></i>
</div>
<span class="testimonial-card__name">Ana L.</span>
</div>
</div>
<?php endif; ?>
</div>
</div>
</section>
<!-- ===== CONTACT SECTION ===== -->
<section class="section contact" id="contacto">
<div class="container">
<div class="section__header">
<span class="section__badge">Contacto</span>
<h2 class="section__title">Estamos para ayudarte</h2>
<p class="section__subtitle">Contáctanos hoy y comienza tu trámite con expertos de tu lado.</p>
</div>
<div class="contact__grid">
<!-- Contact Info -->
<div class="contact__info">
<div class="contact__info-card">
<div class="contact__info-icon">
<i class="fa-solid fa-phone"></i>
</div>
<div>
<h4>Teléfono</h4>
<a href="tel:+521XXXXXXXXXX">(+52) 1 XXX XXX XXXX</a>
</div>
</div>
<div class="contact__info-card">
<div class="contact__info-icon">
<i class="fa-solid fa-envelope"></i>
</div>
<div>
<h4>Correo electrónico</h4>
<a href="mailto:contacto@gestorialp.com">contacto@gestorialp.com</a>
</div>
</div>
<div class="contact__info-card">
<div class="contact__info-icon">
<i class="fa-brands fa-whatsapp"></i>
</div>
<div>
<h4>WhatsApp</h4>
<a href="https://wa.me/521XXXXXXXXXX" target="_blank" rel="noopener">Enviar mensaje</a>
</div>
</div>
<div class="contact__info-card">
<div class="contact__info-icon">
<i class="fa-solid fa-location-dot"></i>
</div>
<div>
<h4>Dirección</h4>
<p>La Paz, Baja California Sur, México</p>
</div>
</div>
</div>
<!-- Map Placeholder -->
<div class="contact__map">
<iframe
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d57995.19084224498!2d-110.35059565!3d24.14437165!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x86afd3455e7c12dd%3A0x3fc89a52f2d77d16!2sLa%20Paz%2C%20B.C.S.!5e0!3m2!1ses!2smx!4v1700000000000!5m2!1ses!2smx"
width="100%"
height="100%"
style="border:0; min-height: 350px;"
allowfullscreen=""
loading="lazy"
referrerpolicy="no-referrer-when-downgrade"
title="Ubicación de Gestoría LP">
</iframe>
</div>
</div>
</div>
</section>
<?php include __DIR__ . '/includes/footer.php'; ?>