Compare commits

...
8 Commits
Author SHA1 Message Date
fanfuso 28cce9a68c mejoras en el blog 2026-09-22 21:21:19 -03:00
fanfuso 0a88f4df20 v1 lista 2026-09-21 17:00:09 -03:00
fanfuso 3b38b9b760 cambios postproduccion 2026-09-21 11:08:17 -03:00
fanfuso e36ec1e8ca cambios php 2026-09-21 02:57:06 -03:00
fanfuso 82816cb680 efecto fluid 2026-09-20 16:01:31 -03:00
fanfuso cfb97b486e blog+contacto php listo 2026-09-20 13:28:57 -03:00
ppugliese cd67fca3dc nosotros + blog en curso 2026-09-20 11:18:14 -03:00
ppugliese 2a0cfbde0e estructura de nosotros y contacto 2026-09-20 08:28:34 -03:00
47 changed files with 15559 additions and 2199 deletions
+132
View File
@@ -0,0 +1,132 @@
<!DOCTYPE html>
<html lang="es" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Responder el mismo mensaje 50 veces al día no es escalable. Las automatizaciones bien hechas te permiten captar prospectos calificados mientras dormís.">
<meta name="keywords" content="automatizaciones, Instagram, chatbots, leads, ManyChat, Amor y Roma">
<meta property="og:title" content="Automatizaciones en Instagram: de 0 a 100 leads/mes">
<meta property="og:description" content="Responder el mismo mensaje 50 veces al día no es escalable. Las automatizaciones bien hechas te permiten captar prospectos.">
<meta property="og:image" content="../assets/blog/automatizacion.jpg">
<title>Automatizaciones en Instagram | Blog Amor y Roma</title>
<link rel="icon" href="/assets/img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="../style/main.css">
<link rel="stylesheet" href="../style/blog.css">
</head>
<body>
<div id="menu-container"></div>
<main>
<article class="articulo-completo">
<div class="articulo-header">
<a href="../blog.html" class="volver-link">← Volver al blog</a>
<span class="badge-filosofia">Automatizaciones</span>
<h1>Automatizaciones en Instagram: de 0 a 100 leads/mes sin volverte loco</h1>
<div class="articulo-meta">
<span>📅 12 de Agosto de 2026</span>
<span>⏱ 9 min de lectura</span>
<span>✍️ Amor y Roma</span>
</div>
<img src="../assets/blog/automatizacion.jpg" alt="Automatizaciones en Instagram" class="articulo-imagen">
</div>
<div class="articulo-contenido">
<p>Si tenés un negocio y usás Instagram para vender, probablemente vivís esto:</p>
<ul>
<li>Te escriben por DM preguntando lo mismo una y otra vez</li>
<li>Se te escapan mensajes entre medio de otras tareas</li>
<li>Perdé ventas por no responder a tiempo</li>
<li>Pasás horas al día pegado al celular</li>
</ul>
<p><strong>Hay una forma mejor.</strong></p>
<h2>¿Qué son las automatizaciones (y qué no son)?</h2>
<p>No son robots fríos que responden "Hola, en breve te atendemos". Eso es lo que la gente ODIA.</p>
<p>Las automatizaciones bien hechas son flujos conversacionales inteligentes que:</p>
<ul>
<li>Responden al instante, 24/7</li>
<li>Hacen preguntas para entender qué necesita la persona</li>
<li>Filtran y cualifican leads automáticamente</li>
<li>Derivan a WhatsApp o agendan llamadas solo cuando corresponde</li>
<li>Recopilan datos (nombre, email, teléfono) sin que vos pidas nada</li>
</ul>
<h2>El sistema de 0 a 100 leads/mes</h2>
<h3>Paso 1: Identificá las preguntas repetitivas</h3>
<p>¿Qué te preguntan siempre?</p>
<ul>
<li>"¿Cuál es el precio?"</li>
<li>"¿Hacés envíos a...?"</li>
<li>"¿Tienen disponibilidad para...?"</li>
</ul>
<p>Esas son tus primeras automatizaciones.</p>
<h3>Paso 2: Creá flujos por palabras clave</h3>
<p>En Instagram podés configurar que cuando alguien comente con cierta palabra en una publicación o historia, se dispare un mensaje automático por DM.</p>
<p><strong>Ejemplo:</strong></p>
<ul>
<li>Publicás: "¿Querés saber más sobre nuestro servicio? Comentá INFO"</li>
<li>La persona comenta "INFO"</li>
<li>Automáticamente recibe un DM con información y preguntas de cualificación</li>
</ul>
<h3>Paso 3: Cualificá antes de derivar</h3>
<p>No todos los que escriben son clientes ideales. Tu flujo debería preguntar:</p>
<ul>
<li>¿Qué necesitás específicamente?</li>
<li>¿Cuándo lo necesitás?</li>
<li>¿Tenés presupuesto definido?</li>
</ul>
<p>Así solo recibís notificaciones de leads calificados.</p>
<h3>Paso 4: Integrá con tu CRM o base de datos</h3>
<p>Los datos que recopilás deberían ir a algún lado útil:</p>
<ul>
<li>Google Sheets</li>
<li>Tu CRM</li>
<li>Tu plataforma de email marketing</li>
</ul>
<p>Así no perdés ningún prospecto y podés hacer seguimiento.</p>
<h2>Errores que matan tus automatizaciones</h2>
<ul>
<li><strong>Ser demasiado robótico:</strong> Usá un tono conversacional, como si hablaras vos.</li>
<li><strong>Pedir demasiada información de una:</strong> Pedí solo lo esencial al principio.</li>
<li><strong>No dar opción a hablar con humano:</strong> Siempre dejá una salida: "Si preferís hablar con alguien, escribinos 'AGENTE'".</li>
<li><strong>Configurar y olvidar:</strong> Revisá cada tanto si los flujos funcionan y ajustá según feedback.</li>
</ul>
<h2>Herramientas que usamos en Amor y Roma</h2>
<p>Trabajamos principalmente con:</p>
<ul>
<li><strong>ManyChat:</strong> El más completo para Instagram y Facebook</li>
<li><strong>Zapier:</strong> Para conectar todo entre sí</li>
<li><strong>Google Sheets/Airtable:</strong> Para almacenar leads</li>
</ul>
<h2>El resultado: tiempo + conversión</h2>
<p>Cuando implementamos automatizaciones para un cliente, normalmente vemos:</p>
<ul>
<li>⏰ <strong>8-12 horas/semana</strong> ahorradas en respuestas manuales</li>
<li>📈 <strong>40-60% más de leads</strong> cualificados (porque no se escapa nadie)</li>
<li> <strong>Cero estrés</strong> por "no respondí a tiempo"</li>
</ul>
<blockquote>Las automatizaciones bien hechas no reemplazan la atención humana: la potencian, liberándote de lo repetitivo para que te enfoques en lo que realmente importa.</blockquote>
<h2>¿Listo para dejar de vivir pegado al celular?</h2>
<p>Si sentís que Instagram te consume más tiempo del que debería, o sabés que se te escapan oportunidades por no responder rápido, hablemos. En Amor y Roma diseñamos flujos de automatización que suenan humanos, cualifican solos y te avisan solo cuando hay un lead de verdad.</p>
<div style="text-align: center; margin-top: 3rem;">
<a href="../contacto.html" class="btn btn-primary">Automatizá tu Instagram</a>
</div>
</div>
</article>
</main>
<div id="footer-container"></div>
<script src="../scripts/main.js"></script>
</body>
</html>
+110
View File
@@ -0,0 +1,110 @@
<!DOCTYPE html>
<html lang="es" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="No es magia, es método. Una landing page efectiva no depende de la suerte. Acá te contamos los 7 principios que aplicamos en cada proyecto.">
<meta name="keywords" content="landing page, conversión, desarrollo web, diseño web, Amor y Roma">
<meta property="og:title" content="Landing pages que convierten: 7 principios probados">
<meta property="og:description" content="No es magia, es método. Una landing page efectiva no depende de la suerte ni de tendencias pasajeras.">
<meta property="og:image" content="../assets/blog/landing-page.jpg">
<title>Landing pages que convierten | Blog Amor y Roma</title>
<link rel="icon" href="/assets/img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="../style/main.css">
<link rel="stylesheet" href="../style/blog.css">
</head>
<body>
<div id="menu-container"></div>
<main>
<article class="articulo-completo">
<div class="articulo-header">
<a href="../blog.html" class="volver-link">← Volver al blog</a>
<span class="badge-filosofia">Web</span>
<h1>Landing pages que convierten: 7 principios probados</h1>
<div class="articulo-meta">
<span> 15 de Julio de 2026</span>
<span>⏱ 8 min de lectura</span>
<span>✍️ Amor y Roma</span>
</div>
<img src="../assets/blog/landing-page.jpg" alt="Landing page que convierte" class="articulo-imagen">
</div>
<div class="articulo-contenido">
<p>Si estás invirtiendo en publicidad o generando contenido en redes, pero tu sitio web no convierte, estás tirando plata. Literal.</p>
<p>Una landing page (página de aterrizaje) no es un lugar bonito para mostrar información. Es una herramienta estratégica diseñada con un único objetivo: conseguir que el visitante tome una acción específica.</p>
<h2>Los 7 principios que usamos en Amor y Roma</h2>
<h3>1. Claridad antes que creatividad</h3>
<p>Tu visitante tiene 3 segundos para entender:</p>
<ul>
<li>Qué ofrecés</li>
<li>Para quién es</li>
<li>Qué tiene que hacer</li>
</ul>
<p>Si necesita más tiempo, perdiste. Por eso, evitamos lenguaje rebuscado y vamos directo al grano.</p>
<h3>2. Un solo objetivo, un solo llamado a la acción</h3>
<p>¿Querés que agenden una llamada? ¿Que descarguen algo? ¿Que compren? Elegí UNA cosa y eliminá toda distracción. <strong>Menos es más.</strong></p>
<h3>3. Beneficios, no características</h3>
<p>A nadie le importa que tu sitio tenga "diseño responsive" o "SEO optimizado". Lo que importa es:</p>
<ul>
<li>"Podés contactarnos desde el celular en cualquier momento"</li>
<li>"Te van a encontrar cuando te busquen en Google"</li>
</ul>
<p>Traducí cada característica en un beneficio tangible.</p>
<h3>4. Prueba social real</h3>
<p>Testimonios genéricos ("Excelente servicio, muy recomendado") no sirven. Necesitás:</p>
<ul>
<li>Nombres reales (o al menos iniciales y cargo)</li>
<li>Resultados específicos ("Aumentamos un 40% las consultas en 2 meses")</li>
<li>Fotos o logos que den credibilidad</li>
</ul>
<h3>5. Diseño que guía la mirada</h3>
<p>Usamos patrones visuales probados:</p>
<ul>
<li><strong>F-Pattern:</strong> La gente escanea en forma de F</li>
<li><strong>Z-Pattern:</strong> Para páginas con menos contenido</li>
</ul>
<p>Colocamos la información clave en esos puntos calientes.</p>
<h3>6. Velocidad = Conversiones</h3>
<p>Cada segundo de carga reduce tus conversiones un 7%. Por eso:</p>
<ul>
<li>Optimizamos cada imagen</li>
<li>Minimizamos código</li>
<li>Usamos hosting de calidad</li>
<li>Evitamos plugins innecesarios</li>
</ul>
<h3>7. Mobile-first, no mobile-also</h3>
<p>El 70%+ de tu tráfico viene del celular. Si tu sitio se ve "más o menos" en móvil, no alcanza. Tiene que ser impecable.</p>
<h2>El método Amor y Roma: Estrategia + Ejecución</h2>
<p>No usamos plantillas de WordPress pesadas ni constructores visuales que ralentizan todo. Desarrollamos cada landing desde cero, pensando en:</p>
<ul>
<li>Tu audiencia específica</li>
<li>Tu propuesta de valor única</li>
<li>Tus objetivos comerciales reales</li>
</ul>
<blockquote>Una landing page efectiva no es un lugar bonito. Es una herramienta estratégica diseñada con un único objetivo: conseguir que el visitante tome una acción específica.</blockquote>
<h2>¿Tu web convierte o solo existe?</h2>
<p>Si sentís que tu sitio actual no está generando los resultados que esperás, o estás por lanzar algo nuevo y querés hacerlo bien, conversemos. Desarrollamos landing pages y sitios web a medida que no solo se ven bien, sino que trabajan para vos 24/7.</p>
<div style="text-align: center; margin-top: 3rem;">
<a href="../contacto.html" class="btn btn-primary">Desarrollá tu landing page</a>
</div>
</div>
</article>
</main>
<div id="footer-container"></div>
<script src="../scripts/main.js"></script>
</body>
</html>
+88
View File
@@ -0,0 +1,88 @@
<!DOCTYPE html>
<html lang="es" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Muchos emprendedores confunden el símbolo con la sustancia. Tener un logo bonito no es tener una marca. Acá te explicamos la diferencia.">
<meta name="keywords" content="branding, logo, identidad de marca, diseño estratégico, Amor y Roma">
<meta property="og:title" content="Tu logo no es tu marca (y por qué importa)">
<meta property="og:description" content="Muchos emprendedores confunden el símbolo con la sustancia. Tener un logo bonito no es tener una marca.">
<meta property="og:image" content="../assets/blog/logo-marca.jpg">
<title>Tu logo no es tu marca | Blog Amor y Roma</title>
<link rel="icon" href="/assets/img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="../style/main.css">
<link rel="stylesheet" href="../style/blog.css">
</head>
<body>
<div id="menu-container"></div>
<main>
<article class="articulo-completo">
<div class="articulo-header">
<a href="../blog.html" class="volver-link">← Volver al blog</a>
<span class="badge-filosofia">Branding</span>
<h1>Tu logo no es tu marca (y por qué importa)</h1>
<div class="articulo-meta">
<span>📅 10 de Junio de 2026</span>
<span>⏱ 6 min de lectura</span>
<span>✍️ Amor y Roma</span>
</div>
<img src="../assets/blog/logo-marca.jpg" alt="Logo vs Marca" class="articulo-imagen">
</div>
<div class="articulo-contenido">
<p>Cuando nos dicen "necesito un logo", en realidad escuchamos "necesito que mi marca exista". Y ahí está el primer error conceptual que puede costarte caro.</p>
<h2>Logo vs. Marca: la diferencia fundamental</h2>
<p>El logo es solo la punta del iceberg. Es el símbolo visual que representa algo mucho más grande: tu promesa de valor, tu personalidad, tu forma de operar en el mundo. La marca, en cambio, es la experiencia completa que las personas tienen con tu negocio.</p>
<p><strong>Pensalo así: el logo es tu firma. La marca es tu reputación.</strong></p>
<h2>¿Por qué las plantillas de branding no funcionan?</h2>
<p>En un mundo saturado de Canva y logos pre-fabricados, la tentación de "resolver rápido" es enorme. Pero cuando usás una plantilla:</p>
<ul>
<li><strong>Perdés diferenciación:</strong> Si tu logo se parece al de otros 50 negocios, ¿por qué te elegirían a vos?</li>
<li><strong>No comunicás tu esencia:</strong> Un símbolo genérico no transmite tu historia, tus valores ni tu forma única de operar.</li>
<li><strong>Limitás tu crecimiento:</strong> Lo que funciona hoy para un emprendimiento incipiente, mañana puede quedar chico para una empresa consolidada.</li>
</ul>
<h2>El branding estratégico: Amor + Roma en acción</h2>
<p>En Amor y Roma, no empezamos dibujando. Empezamos preguntando:</p>
<ul>
<li>¿Qué problema resolvés?</li>
<li>¿A quién le hablás?</li>
<li>¿Qué te hace diferente?</li>
<li>¿Cómo querés que se sienta la gente al interactuar con vos?</li>
</ul>
<p>Recién después de entender eso, construimos:</p>
<ul>
<li><strong>Arquetipo de marca:</strong> ¿Sos el héroe, el sabio, el creador? Esto define tu personalidad.</li>
<li><strong>Sistema visual completo:</strong> No solo un logo, sino colores, tipografías, estilos de imagen que funcionen juntos.</li>
<li><strong>Manual de aplicación:</strong> Para que tu marca se vea coherente en cada punto de contacto.</li>
<li><strong>Personajes o elementos distintivos:</strong> Si aplica, creamos activos que humanicen tu comunicación.</li>
</ul>
<h2>El resultado: una marca que resuena</h2>
<p>Cuando invertís en branding estratégico, no estás comprando "un dibujo lindo". Estás construyendo:</p>
<ul>
<li><strong>Reconocimiento:</strong> La gente te identifica al instante.</li>
<li><strong>Confianza:</strong> Transmitís profesionalismo y solidez.</li>
<li><strong>Conexión emocional:</strong> Tu audiencia se siente representada por vos.</li>
<li><strong>Base para crecer:</strong> Tenés los cimientos para escalar sin perder identidad.</li>
</ul>
<blockquote>Una marca bien construida no solo se ve profesional: genera confianza, atrae clientes ideales y permite cobrar lo que realmente valés.</blockquote>
<h2>¿Estás listo para construir una marca, no solo un logo?</h2>
<p>Si sentís que tu identidad actual no te representa, o estás empezando y querés hacerlo bien desde el inicio, hablemos. En Amor y Roma diseñamos identidades con esencia y estrategia, sin plantillas ni fórmulas repetidas.</p>
<div style="text-align: center; margin-top: 3rem;">
<a href="../contacto.html" class="btn btn-primary">Hablemos sobre tu marca</a>
</div>
</div>
</article>
</main>
<div id="footer-container"></div>
<script src="../scripts/main.js"></script>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

+15
View File
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Creator: CorelDRAW -->
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="64px" height="64px" version="1.1" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd"
viewBox="0 0 5.34 5.31"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xodm="http://www.corel.com/coreldraw/odm/2003">
<g id="Capa_x0020_1">
<metadata id="CorelCorpID_0Corel-Layer"/>
<g id="_2347189464160">
<path fill="#221728" fill-opacity="0.250980" d="M2.67 0c1.47,0 2.67,1.19 2.67,2.65 0,1.47 -1.2,2.66 -2.67,2.66 -1.47,0 -2.67,-1.19 -2.67,-2.66 0,-1.46 1.2,-2.65 2.67,-2.65z"/>
<path fill="#221728" d="M0.24 3.79c0.29,0.65 0.98,1.28 1.78,1.46l0 -1.77 -0.55 0 -0.01 -0.83 0.55 0.01c0.06,-0.62 -0.02,-1.13 0.4,-1.44 0.39,-0.27 0.98,-0.27 1.5,-0.18l-0.01 0.75c-0.78,-0.05 -0.96,0.06 -0.9,0.87l0.86 -0.01 -0.16 0.83 -0.71 0.01 0 1.82c0.92,-0.08 1.72,-0.74 2.08,-1.47 0.29,-0.61 0.35,-1.32 0.15,-1.96 -0.14,-0.43 -0.36,-0.82 -0.66,-1.11 -1.06,-1.03 -2.83,-1.04 -3.86,0.05 -0.73,0.78 -0.9,2 -0.46,2.97z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+17
View File
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Creator: CorelDRAW -->
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="64px" height="64px" version="1.1" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd"
viewBox="0 0 7.24 7.24"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xodm="http://www.corel.com/coreldraw/odm/2003">
<g id="Capa_x0020_1">
<metadata id="CorelCorpID_0Corel-Layer"/>
<g id="_2346936265280">
<path fill="#221728" d="M2.1 0.58c0.23,-0.02 0.51,0 0.75,0 0.51,0 1.01,0 1.52,0 0.25,0 0.52,-0.01 0.76,0 0.83,0.04 1.48,0.69 1.53,1.51 0.01,0.24 0,0.52 0,0.76l0 1.52c0,0.25 0.01,0.52 0,0.76 -0.04,0.83 -0.69,1.48 -1.52,1.53 -0.23,0.01 -0.51,0 -0.75,0l-1.52 0c-0.25,0 -0.52,0.01 -0.76,0 -0.83,-0.04 -1.48,-0.69 -1.53,-1.52 -0.02,-0.23 0,-0.51 0,-0.75l0 -1.52c0,-0.53 -0.06,-0.91 0.15,-1.37 0.23,-0.51 0.75,-0.88 1.37,-0.92zm-0.02 -0.57c-1.02,0.06 -1.77,0.77 -2,1.62 -0.08,0.28 -0.08,0.51 -0.08,0.82l0 1.81c0,0.29 -0.01,0.61 0.01,0.9 0.05,1.01 0.78,1.78 1.61,2 0.29,0.07 0.52,0.07 0.83,0.07 0.6,0 1.2,0 1.81,0 0.29,0 0.61,0.02 0.9,0 1.01,-0.05 1.77,-0.77 2,-1.62 0.07,-0.28 0.07,-0.51 0.07,-0.82l0 -1.81c0,-0.29 0.01,-0.61 0,-0.9 -0.06,-1.01 -0.78,-1.78 -1.62,-2 -0.28,-0.08 -0.51,-0.07 -0.82,-0.07l-1.81 0c-0.29,0 -0.62,-0.02 -0.9,0z"/>
<path fill="#221728" d="M3.53 2.29c0.27,-0.02 0.58,0.06 0.8,0.2 0.1,0.07 0.1,0.07 0.18,0.14 0.11,0.09 0.22,0.23 0.29,0.38 0.21,0.41 0.2,0.93 -0.05,1.32 -0.07,0.11 -0.07,0.09 -0.14,0.18 -0.1,0.11 -0.25,0.23 -0.38,0.3 -0.16,0.07 -0.32,0.12 -0.52,0.14 -0.77,0.05 -1.37,-0.54 -1.42,-1.24 -0.01,-0.21 0.02,-0.41 0.09,-0.58 0.07,-0.18 0.14,-0.27 0.25,-0.41 0.21,-0.25 0.56,-0.4 0.9,-0.43zm-0.01 -0.57c-1.02,0.06 -1.86,0.92 -1.8,2 0.05,1.01 0.92,1.86 2,1.8 1.01,-0.06 1.86,-0.92 1.8,-2.01 -0.06,-1 -0.92,-1.85 -2,-1.79z"/>
<path fill="#221728" fill-opacity="0.250980" d="M3.53 2.29c-0.34,0.03 -0.69,0.18 -0.9,0.43 -0.11,0.14 -0.18,0.23 -0.25,0.41 -0.07,0.17 -0.1,0.37 -0.09,0.58 0.05,0.7 0.65,1.29 1.42,1.24 0.2,-0.02 0.36,-0.07 0.52,-0.14 0.13,-0.07 0.28,-0.19 0.38,-0.3 0.07,-0.09 0.07,-0.07 0.14,-0.18 0.25,-0.39 0.26,-0.91 0.05,-1.32 -0.07,-0.15 -0.18,-0.29 -0.29,-0.38 -0.08,-0.07 -0.08,-0.07 -0.18,-0.14 -0.22,-0.14 -0.53,-0.22 -0.8,-0.2zm-0.01 -0.57c1.08,-0.06 1.94,0.79 2,1.79 0.06,1.09 -0.79,1.95 -1.8,2.01 -1.08,0.06 -1.95,-0.79 -2,-1.8 -0.06,-1.08 0.78,-1.94 1.8,-2zm1.95 -0.38c0.22,-0.03 0.4,0.13 0.43,0.32 0.03,0.22 -0.13,0.41 -0.32,0.43 -0.23,0.04 -0.41,-0.13 -0.44,-0.32 -0.03,-0.23 0.14,-0.4 0.33,-0.43zm-3.37 -0.76c-0.62,0.04 -1.14,0.41 -1.37,0.92 -0.21,0.46 -0.15,0.84 -0.15,1.37l0 1.52c0,0.24 -0.02,0.52 0,0.75 0.05,0.83 0.7,1.48 1.53,1.52 0.24,0.01 0.51,0 0.76,0l1.52 0c0.24,0 0.52,0.01 0.75,0 0.83,-0.05 1.48,-0.7 1.52,-1.53 0.01,-0.24 0,-0.51 0,-0.76l0 -1.52c0,-0.24 0.01,-0.52 0,-0.76 -0.05,-0.82 -0.7,-1.47 -1.53,-1.51 -0.24,-0.01 -0.51,0 -0.76,0 -0.51,0 -1.01,0 -1.52,0 -0.24,0 -0.52,-0.02 -0.75,0z"/>
<path fill="#221728" d="M5.47 1.34c-0.19,0.03 -0.36,0.2 -0.33,0.43 0.03,0.19 0.21,0.36 0.44,0.32 0.19,-0.02 0.35,-0.21 0.32,-0.43 -0.03,-0.19 -0.21,-0.35 -0.43,-0.32z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

+15
View File
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Creator: CorelDRAW -->
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="64px" height="64px" version="1.1" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd"
viewBox="0 0 4.52 4.52"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xodm="http://www.corel.com/coreldraw/odm/2003">
<g id="Capa_x0020_1">
<metadata id="CorelCorpID_0Corel-Layer"/>
<g id="_2346933204656">
<polygon fill="#221728" fill-opacity="0.250980" stroke="#373435" stroke-width="0.02" stroke-miterlimit="22.9256" stroke-opacity="0.250980" points="0.28,0.35 4.19,0.35 4.19,4.2 0.28,4.2 "/>
<path fill="#221728" d="M0.7 1.72l0.67 0c0.01,0.16 0,0.37 0,0.54l0 1.49c0,0.02 0,0.05 0,0.07 0,0.03 0.01,0.03 -0.01,0.05l-0.66 0 0 -2.15zm1.73 0.29c0.05,-0.03 0.06,-0.14 0.26,-0.25 0.31,-0.18 0.87,-0.13 1.06,0.24 0.13,0.26 0.12,0.55 0.12,0.87 0,0.33 0,0.67 0,1l-0.67 0c0,-0.33 0,-0.67 0,-1 0,-0.32 0,-0.63 -0.37,-0.62 -0.35,0.02 -0.38,0.31 -0.38,0.63 0,0.33 0,0.66 0,0.99l-0.66 0 0 -2.15 0.64 0 0 0.29zm-1.45 -1.36c0.22,-0.03 0.41,0.13 0.44,0.33 0.07,0.51 -0.69,0.61 -0.77,0.12 -0.04,-0.24 0.13,-0.42 0.33,-0.45zm-0.4 -0.64c-0.3,0.04 -0.54,0.26 -0.57,0.56 -0.02,0.15 -0.01,2.5 -0.01,2.82 0,0.16 -0.01,0.4 0.01,0.55 0.03,0.3 0.27,0.53 0.56,0.57 0.15,0.01 2.49,0 2.82,0 0.16,0 0.4,0.02 0.55,0 0.3,-0.04 0.53,-0.27 0.57,-0.57 0.01,-0.14 0,-2.49 0,-2.81 0,-0.16 0.02,-0.4 0,-0.56 -0.04,-0.29 -0.27,-0.53 -0.57,-0.56 -0.14,-0.02 -2.49,-0.01 -2.81,-0.01 -0.16,0 -0.4,-0.01 -0.55,0.01z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

+16
View File
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Creator: CorelDRAW -->
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="40px" height="40px" version="1.1" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd"
viewBox="0 0 10.64 10.63"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xodm="http://www.corel.com/coreldraw/odm/2003">
<g id="Capa_x0020_1">
<metadata id="CorelCorpID_0Corel-Layer"/>
<g id="_2348118537696">
<path fill="#221728" d="M3.3 2.99c-0.45,0.32 -0.61,0.87 -0.5,1.4 0.19,1 1.46,2.29 2.19,2.7 0.09,0.05 0.24,0.11 0.32,0.17l0.63 0.27c0.2,0 0.52,0.22 0.99,0.11 0.21,-0.04 0.44,-0.14 0.6,-0.27 0.17,-0.16 0.34,-0.37 0.37,-0.61 0.02,-0.14 0,-0.23 -0.04,-0.29 -0.1,-0.18 -0.78,-0.61 -1.09,-0.63 -0.2,-0.01 -0.25,-0.01 -0.36,0.12 -0.02,0.05 -0.14,0.2 -0.21,0.31 -0.06,0.1 -0.12,0.24 -0.28,0.23 -0.6,-0.11 -1.43,-0.9 -1.76,-1.42 -0.09,-0.15 -0.1,-0.24 0,-0.37 0.11,-0.15 0.25,-0.26 0.31,-0.5 0.02,-0.3 -0.22,-0.88 -0.41,-1.12 -0.06,-0.07 -0.11,-0.12 -0.21,-0.16 -0.04,-0.02 -0.08,-0.03 -0.12,-0.03 -0.14,-0.02 -0.16,-0.03 -0.27,0.02l-0.16 0.07z"/>
<path fill="#221728" fill-opacity="0.250980" stroke="#373435" stroke-width="0.03" stroke-miterlimit="22.9256" stroke-opacity="0.250980" d="M1.2 4.14c0.04,-0.15 0.15,-0.53 0.2,-0.58 0.11,-0.44 0.86,-1.29 1.14,-1.53 0.48,-0.39 1.09,-0.71 1.75,-0.89 1.46,-0.42 3.02,0.07 4.09,1.13 0.17,0.17 0.33,0.36 0.48,0.58 0.25,0.35 0.54,0.9 0.62,1.33 0.1,0.22 0.15,0.85 0.15,1.14 0,0.17 -0.02,0.44 -0.07,0.73 -0.09,0.61 -0.25,0.99 -0.56,1.51 -0.05,0.09 -0.16,0.25 -0.23,0.34 -1.27,1.7 -3.59,2.24 -5.52,1.17 -0.06,-0.03 -0.19,-0.09 -0.22,-0.14 -0.18,-0.06 -0.53,0.1 -0.73,0.14 -0.06,0.03 -0.45,0.13 -0.51,0.12 -0.06,0.06 -0.38,0.12 -0.45,0.13 0.02,-0.14 0.1,-0.37 0.11,-0.4l0.02 -0.03c-0.01,-0.08 0.24,-1 0.28,-1.1 0.01,-0.1 -0.01,-0.09 -0.04,-0.17 -0.05,-0.04 -0.24,-0.4 -0.28,-0.5 -0.41,-0.58 -0.46,-1.92 -0.33,-2.61 0.01,-0.07 0.07,-0.28 0.1,-0.37zm2.1 -1.15c-0.45,0.32 -0.61,0.87 -0.5,1.4 0.19,1 1.46,2.29 2.19,2.7 0.09,0.05 0.24,0.11 0.32,0.17l0.63 0.27c0.2,0 0.52,0.22 0.99,0.11 0.21,-0.04 0.44,-0.14 0.6,-0.27 0.17,-0.16 0.34,-0.37 0.37,-0.61 0.02,-0.14 0,-0.23 -0.04,-0.29 -0.1,-0.18 -0.78,-0.61 -1.09,-0.63 -0.2,-0.01 -0.25,-0.01 -0.36,0.12 -0.02,0.05 -0.14,0.2 -0.21,0.31 -0.06,0.1 -0.12,0.24 -0.28,0.23 -0.6,-0.11 -1.43,-0.9 -1.76,-1.42 -0.09,-0.15 -0.1,-0.24 0,-0.37 0.11,-0.15 0.25,-0.26 0.31,-0.5 0.02,-0.3 -0.22,-0.88 -0.41,-1.12 -0.06,-0.07 -0.11,-0.12 -0.21,-0.16 -0.04,-0.02 -0.08,-0.03 -0.12,-0.03 -0.14,-0.02 -0.16,-0.03 -0.27,0.02l-0.16 0.07z"/>
<path fill="#221728" d="M1.2 4.14c0.04,-0.15 0.15,-0.53 0.2,-0.58 0.11,-0.44 0.86,-1.29 1.14,-1.53 0.48,-0.39 1.09,-0.71 1.75,-0.89 1.46,-0.42 3.02,0.07 4.09,1.13 0.17,0.17 0.33,0.36 0.48,0.58 0.25,0.35 0.54,0.9 0.62,1.33 0.1,0.22 0.15,0.85 0.15,1.14 0,0.17 -0.02,0.44 -0.07,0.73 -0.09,0.61 -0.25,0.99 -0.56,1.51 -0.05,0.09 -0.16,0.25 -0.23,0.34 -1.27,1.7 -3.59,2.24 -5.52,1.17 -0.06,-0.03 -0.19,-0.09 -0.22,-0.14 -0.18,-0.06 -0.53,0.1 -0.73,0.14 -0.06,0.03 -0.45,0.13 -0.51,0.12 -0.06,0.06 -0.38,0.12 -0.45,0.13 0.02,-0.14 0.1,-0.37 0.11,-0.4l0.02 -0.03c-0.01,-0.08 0.24,-1 0.28,-1.1 0.01,-0.1 -0.01,-0.09 -0.04,-0.17 -0.05,-0.04 -0.24,-0.4 -0.28,-0.5 -0.41,-0.58 -0.46,-1.92 -0.33,-2.61 0.01,-0.07 0.07,-0.28 0.1,-0.37zm0.59 -2.77c-0.42,0.4 -0.74,0.73 -1.05,1.28 -0.06,0.1 -0.11,0.2 -0.16,0.3 -0.06,0.11 -0.1,0.2 -0.15,0.32l-0.09 0.25c-0.03,0.07 -0.01,0.04 -0.05,0.08 0,0.09 -0.13,0.49 -0.16,0.64 -0.05,0.23 -0.08,0.47 -0.09,0.71 -0.06,0.81 0.1,1.3 0.1,1.5 0.04,0.04 0.08,0.26 0.09,0.33 0.04,0.13 0.08,0.23 0.11,0.35 0.04,0.05 0.14,0.33 0.18,0.41 0.05,0.11 0.18,0.28 0.15,0.41 -0.02,0.09 -0.23,0.9 -0.25,0.92 -0.03,0.13 -0.07,0.25 -0.1,0.37 -0.01,0.07 -0.06,0.29 -0.1,0.34 -0.32,1.01 -0.35,1.14 0.35,0.99 0.03,-0.02 0.48,-0.13 0.54,-0.13l0.64 -0.18c0.04,-0.03 0.47,-0.14 0.53,-0.14 0.01,0 0.01,-0.01 0.04,-0.02 0.03,-0.01 0.04,-0.01 0.08,-0.02 0.08,-0.03 0.21,-0.05 0.31,-0.08 0.12,-0.04 0.17,0.01 0.28,0.07 0.14,0.07 0.48,0.19 0.56,0.24 0.11,0.02 0.21,0.07 0.32,0.1 0.25,0.06 0.45,0.12 0.72,0.15 0.14,0.02 0.27,0.04 0.41,0.05 0.28,0.01 0.63,0.01 0.9,-0.03 0.95,-0.15 2.17,-0.61 2.88,-1.24 0.06,-0.06 0.02,-0.03 0.09,-0.06 0.02,-0.04 0.04,-0.05 0.08,-0.09 0.04,-0.03 0.06,-0.05 0.1,-0.09 0.55,-0.56 1.28,-1.87 1.46,-2.62 0.27,-1.19 0.02,-1.89 0.04,-2.19 -0.04,-0.05 -0.03,-0.09 -0.05,-0.18 -0.05,-0.22 -0.12,-0.38 -0.16,-0.56 -0.02,-0.03 -0.21,-0.5 -0.21,-0.54 -0.05,-0.03 -0.06,-0.08 -0.08,-0.13 -0.06,-0.08 -0.09,-0.17 -0.14,-0.25 -0.05,-0.07 -0.11,-0.16 -0.14,-0.24 -0.1,-0.11 -0.19,-0.28 -0.33,-0.43 -0.07,-0.07 -0.12,-0.14 -0.18,-0.21 -0.12,-0.15 -0.45,-0.45 -0.57,-0.55 -0.54,-0.46 -1.49,-0.87 -2.19,-1.07 -0.53,-0.09 -0.99,-0.17 -1.55,-0.11 -0.27,0.02 -0.48,0.04 -0.73,0.1 -0.51,0.11 -0.91,0.26 -1.32,0.48 -0.41,0.21 -0.78,0.45 -1.11,0.77z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.9 KiB

+1 -1
View File
@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Enlaces oficiales de Estudio Creativo. Transformando ideas en experiencias visuales extraordinarias.">
<title>Estudio Creativo - Enlaces</title>
<link rel="icon" href="/assets/img/favicon.ico" type="image/x-icon">
<link rel="icon" href="images/icons/favicon.png" type="image/x-icon">
<!-- Fuentes sincronizadas con main.css -->
+94 -40
View File
@@ -3,66 +3,120 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<title>Blog - [Nombre de la agencia]</title>
<meta name="description" content="Blog de Amor y Roma. Estrategia, branding, desarrollo web y marketing digital con esencia y solidez.">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css">
<title>Blog | Amor y Roma — Recursos y Estrategias</title>
<link rel="stylesheet" href="style/main.css">
<link rel="stylesheet" href="style/blog.css">
</head>
<body>
<div id="fluid-bg" aria-hidden="true">
<canvas id="fluidCanvas"></canvas>
</div>
<div id="menu-container"></div>
<main>
<!-- Sección 1: Encabezado del blog -->
<section id="blog-section-1">
<h2>Blog</h2>
<p>Contenido pendiente de definir.</p>
</section>
<!-- Sección 2: Filtros dinámicos -->
<section id="blog-section-2">
<div class="blog-filters">
<label for="filter-category">Categoría:</label>
<select id="filter-category">
<option value="">Todas</option>
<!-- Las opciones se cargarán dinámicamente -->
</select>
<label for="filter-date-from">Desde:</label>
<input type="date" id="filter-date-from">
<label for="filter-date-to">Hasta:</label>
<input type="date" id="filter-date-to">
<button type="button" id="btn-apply-filters">Aplicar filtros</button>
<button type="button" id="btn-clear-filters">Limpiar</button>
<!-- HERO -->
<section class="blog-hero-compact">
<div class="hero-compact-content">
<span class="badge-filosofia">Ideas que construyen marcas</span>
<h1 class="hero-compact-title">Estrategia, diseño y tecnología explicados sin tecnicismos</h1>
<p class="hero-compact-subtitle">
Consejos prácticos de branding, web y marketing digital para hacer crecer tu negocio con esencia y estructura.
</p>
</div>
</section>
<!-- Sección 3: Listado de artículos -->
<section id="blog-section-3">
<div class="blog-list" id="blog-list">
<!-- Los artículos se inyectarán aquí desde PHP/DB -->
<p>Cargando artículos...</p>
<!-- FILTROS -->
<section class="blog-filters-section" id="blog-filters-header">
<div class="filters-container">
<div class="filters-top-row">
<div class="search-wrapper-compact">
<span class="search-icon">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"/>
<path d="m21 21-4.35-4.35"/>
</svg>
</span>
<input type="text" id="blog-search" placeholder="Buscá por tema: branding, web, redes..." autocomplete="off" aria-label="Buscar artículos">
<button class="search-clear" id="search-clear" type="button" aria-label="Limpiar búsqueda">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M18 6 6 18M6 6l12 12"/>
</svg>
</button>
</div>
<div class="filter-group-compact">
<button class="filter-btn active" data-filter="all">Todos</button>
<button class="filter-btn" data-filter="destacados">Destacados</button>
</div>
</div>
<div class="filters-bottom-row">
<div class="filter-categories-compact">
<button class="category-btn active" data-category="all">Todas</button>
<button class="category-btn" data-category="branding">Branding</button>
<button class="category-btn" data-category="web">Web</button>
<button class="category-btn" data-category="redes">Redes</button>
<button class="category-btn" data-category="automatizaciones">Automatizaciones</button>
<button class="category-btn" data-category="paid">Paid Media</button>
<button class="category-btn" data-category="estrategia">Estrategia</button>
<button class="category-btn" data-category="casos">Casos</button>
</div>
<div class="filter-secondary-compact">
<select id="sort-select" class="sort-select-compact">
<option value="recent">Más recientes</option>
<option value="popular">Más populares</option>
</select>
</div>
</div>
<div class="results-info-compact">
<span id="results-count">Mostrando <strong>todos</strong> los artículos</span>
<button class="reset-filters-compact" id="reset-filters">Limpiar filtros</button>
</div>
</div>
</section>
<!-- Sección 4: Paginación -->
<section id="blog-section-4">
<nav class="blog-pagination" id="blog-pagination" aria-label="Paginación del blog">
<!-- Controles de paginación -->
</nav>
<!-- DESTACADOS (Se llena dinámicamente con JS) -->
<section class="featured-posts" id="featured-posts" style="display: none;">
<div class="section-header">
<h2 class="section-title">Más leídos</h2>
<p class="section-subtitle">Los artículos que más están ayudando a marcas como la tuya.</p>
</div>
<div class="featured-grid" id="featured-grid">
<!-- JS inyecta las tarjetas aquí -->
</div>
</section>
<!-- Sección 5: CTA / Suscripción -->
<section id="blog-section-5">
<h2>Suscríbete</h2>
<p>Contenido pendiente de definir.</p>
<!-- GRID DE ARTÍCULOS (Se llena dinámicamente con JS) -->
<section class="blog-grid-section">
<div class="section-header">
<h2 class="section-title" id="grid-section-title">Ideas frescas</h2>
<p class="section-subtitle">Encontrá nuestros últimos articulos de vanguardia.</p>
</div>
<div class="blog-grid" id="blog-grid">
<!-- JS inyecta las tarjetas aquí -->
</div>
<div class="empty-state" id="empty-state" style="display: none;">
<div class="empty-icon">🔍</div>
<h3>No encontramos artículos con esos filtros</h3>
<p>Probá con otros términos o limpiá los filtros para ver todo el contenido.</p>
<button class="btn btn-primary" id="empty-reset">Ver todos los artículos</button>
</div>
<div class="load-more-container">
<button class="btn btn-secondary" id="load-more">Cargar más artículos</button>
</div>
</section>
</main>
<div id="footer-container"></div>
<script src="scripts/main.js"></script>
<script src="scripts/efecto.js"></script>
<script src="scripts/blog.js"></script>
<script src="scripts/fluid.js"></script>
</body>
</html>
+28
View File
@@ -0,0 +1,28 @@
<?php
/**
* Configuración general del formulario de contacto.
* NO subir este archivo a repos públicos.
*/
// ─── SMTP (DonWeb / Ferozo) ────────────────────────────────────────────
// Reemplazá los valores por los reales de tu casilla contacto@amoryroma.com.ar
define('SMTP_HOST', 'dtc036.ferozo.com'); // o el que te dio DonWeb
define('SMTP_PORT', 465); // 587 (TLS) o 465 (SSL)
define('SMTP_SECURE', 'ssl'); // 'tls' o 'ssl'
define('SMTP_USER', 'contacto@amoryroma.com.ar');
define('SMTP_PASS', '1J@oUz7f');
define('SMTP_FROM', 'contacto@amoryroma.com.ar');
define('SMTP_FROM_NAME', 'Amor & Roma');
// ─── Destinatarios ─────────────────────────────────────────────────────
define('MAIL_TO', 'contacto@amoryroma.com.ar');
define('MAIL_TO_NAME', 'Amor & Roma');
// ─── Redirección post-éxito ────────────────────────────────────────────
define('REDIRECT_URL', 'index.html');
define('REDIRECT_MS', 4000); // milisegundos antes de redirigir
// ─── Modo debug ────────────────────────────────────────────────────────
// true → muestra errores SMTP en la respuesta JSON (solo para probar)
// false → producción (recomendado)
define('DEBUG_MODE', false);
+252 -40
View File
@@ -3,68 +3,280 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<title>Contacto - [Nombre de la agencia]</title>
<meta name="description" content="Contactá a Amor y Roma. Contanos sobre tu proyecto y coordinemos un diagnóstico estratégico sin compromiso.">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css">
<title>Contacto | Amor y Roma — Agencia Boutique</title>
<link rel="icon" href="/assets/img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="style/main.css">
<link rel="stylesheet" href="style/contacto.css">
<link rel="stylesheet" href="style/modal.css">
</head>
<body>
<div id="fluid-bg" aria-hidden="true">
<canvas id="fluidCanvas"></canvas>
</div>
<div id="menu-container"></div>
<main>
<!-- Sección 1: Encabezado -->
<section id="contacto-section-1">
<h2>Contacto</h2>
<p>Contenido pendiente de definir.</p>
<!-- SECCIÓN 1: HERO DE CONTACTO -->
<section class="hero-section contacto-hero">
<div class="hero-content">
<span class="badge-filosofia"></span>
<h1 class="hero-title">Hablemos de tu proyecto</h1>
<p class="hero-subtitle">
Contanos dónde estás parado y hacia dónde querés ir. <br>
Te respondemos en menos de 48 horas hábiles con una lectura inicial.
</p>
<div class="hero-cta-group">
<a href="#formulario-contacto" class="btn btn-primary">Completar formulario</a>
<a href="https://wa.me/543886118304" target="_blank" rel="noopener" class="btn btn-secondary">
<span class="icono-whatsapp-btn"></span> Escribinos por WhatsApp
</a>
</div>
</div>
</section>
<!-- Sección 2: Formulario de contacto -->
<section id="contacto-section-2">
<h3>Escríbenos</h3>
<form class="contact-form" id="contact-form" novalidate>
<label for="contact-name">Nombre</label>
<input type="text" id="contact-name" name="name" required>
<!-- SECCIÓN 2: INFO + FORMULARIO -->
<section id="formulario-contacto" class="contacto-grid-section">
<div class="contacto-grid">
<!-- COLUMNA IZQUIERDA: Información directa -->
<aside class="contacto-info">
<h2 class="contacto-info-titulo">Canales directos</h2>
<p class="contacto-info-texto">
Si preferís un contacto más inmediato, elegí el canal que mejor se adapte a tu consulta.
</p>
<label for="contact-email">Email</label>
<input type="email" id="contact-email" name="email" required>
<ul class="contacto-canales">
<li class="canal-item">
<span class="canal-icono canal-email"></span>
<div class="canal-contenido">
<strong>Email</strong>
<a href="mailto:contacto@amoryroma.com">contacto@amoryroma.com</a>
</div>
</li>
<li class="canal-item">
<span class="canal-icono canal-whatsapp"></span>
<div class="canal-contenido">
<strong>WhatsApp</strong>
<a href="https://wa.me/543886118304" target="_blank" rel="noopener">+54 9 388 6118304</a>
</div>
</li>
<li class="canal-item">
<span class="canal-icono canal-instagram"></span>
<div class="canal-contenido">
<strong>Instagram</strong>
<a href="https://www.instagram.com/amoryroma.creativo" target="_blank" rel="noopener">@amoryroma.creativo</a>
</div>
</li>
<li class="canal-item">
<span class="canal-icono canal-linkedin"></span>
<div class="canal-contenido">
<strong>LinkedIn</strong>
<a href="https://www.linkedin.com/company/amoryroma-estudiocreativo/" target="_blank" rel="noopener">Amor & Roma - Estudio creativo</a>
</div>
</li>
<li class="canal-item">
<span class="canal-icono canal-facebook"></span>
<div class="canal-contenido">
<strong>Facebook</strong>
<a href="https://web.facebook.com/amoryroma.creativo/" target="_blank" rel="noopener">Amor & Roma - Estudio creativo</a>
</div>
</li>
</ul>
<label for="contact-phone">Teléfono (opcional)</label>
<input type="tel" id="contact-phone" name="phone">
<div class="contacto-horario">
<strong>Horario de atención</strong>
<p>Lunes a Viernes · 9:00 a 18:00 hs (GMT-3)</p>
</div>
</aside>
<label for="contact-subject">Asunto</label>
<input type="text" id="contact-subject" name="subject" required>
<!-- COLUMNA DERECHA: Formulario -->
<form class="contacto-form" id="form-contacto" action="#" method="POST" novalidate>
<h2 class="contacto-form-titulo">Contanos sobre tu marca</h2>
<p class="contacto-form-subtitulo">Cuanta más información nos des, más precisa será nuestra lectura inicial.</p>
<label for="contact-message">Mensaje</label>
<textarea id="contact-message" name="message" rows="5" required></textarea>
<!-- Fila 1: Nombre y Empresa -->
<div class="form-row form-row-2">
<div class="form-group">
<label for="nombre">Nombre completo <span class="form-required">*</span></label>
<input type="text" id="nombre" name="nombre" required placeholder="Tu nombre">
</div>
<div class="form-group">
<label for="empresa">Empresa / Marca</label>
<input type="text" id="empresa" name="empresa" placeholder="Nombre de tu marca">
</div>
</div>
<button type="submit">Enviar mensaje</button>
</form>
<!-- Fila 2: Email y Teléfono -->
<div class="form-row form-row-2">
<div class="form-group">
<label for="email">Email <span class="form-required">*</span></label>
<input type="email" id="email" name="email" required placeholder="tu@email.com">
</div>
<div class="form-group">
<label for="telefono">Teléfono / WhatsApp</label>
<input type="tel" id="telefono" name="telefono" placeholder="+54 9 11 ...">
</div>
</div>
<!-- Fila 3: Servicio de interés -->
<div class="form-group">
<label for="servicio">¿Qué servicio te interesa? <span class="form-required">*</span></label>
<select id="servicio" name="servicio" required>
<option value="" disabled selected>Seleccioná una opción</option>
<option value="branding">Branding & Identidad de Marca</option>
<option value="web">Desarrollo Web a Medida</option>
<option value="rrss">Gestión de Redes Sociales (Plan recurrente)</option>
<option value="automatizaciones">Automatizaciones & Flujos</option>
<option value="paid">Paid Media & Campañas</option>
<option value="ecosistema">Ecosistema Digital Completo</option>
<option value="otro">Otro / Aún no lo tengo claro</option>
</select>
</div>
<!-- Fila 4: Etapa del proyecto -->
<div class="form-group">
<label for="etapa">¿En qué etapa está tu proyecto?</label>
<select id="etapa" name="etapa">
<option value="" disabled selected>Seleccioná una opción</option>
<option value="idea">Solo tengo la idea</option>
<option value="inicio">Estoy empezando (sin marca definida)</option>
<option value="marcha">Ya está en marcha, necesito orden</option>
<option value="redisenio">Quiero rediseñar / reposicionar</option>
<option value="escalar">Quiero escalar lo que ya tengo</option>
</select>
</div>
<!-- Fila 5: Presupuesto -->
<div class="form-group">
<label for="presupuesto">Rango de inversión mensual estimado</label>
<select id="presupuesto" name="presupuesto">
<option value="" disabled selected>Seleccioná un rango</option>
<option value="esencial">Hasta $250.000 (Esencial)</option>
<option value="impulso">$250.000 – $500.000 (Impulso)</option>
<option value="premium">$500.000 – $800.000 (Premium)</option>
<option value="elite">Más de $800.000 (Élite)</option>
<option value="proyecto">Es un proyecto cerrado (one-off)</option>
<option value="no-se">Prefiero que lo evalúen ustedes</option>
</select>
</div>
<!-- Fila 6: Mensaje -->
<div class="form-group">
<label for="mensaje">Contanos sobre tu proyecto <span class="form-required">*</span></label>
<textarea id="mensaje" name="mensaje" rows="5" required placeholder="Objetivos, desafíos, referencias, lo que quieras compartir..."></textarea>
</div>
<!-- Fila 7: Cómo nos conoció -->
<div class="form-group">
<label for="origen">¿Cómo nos conociste?</label>
<select id="origen" name="origen">
<option value="" disabled selected>Seleccioná una opción</option>
<option value="instagram">Instagram</option>
<option value="linkedin">LinkedIn</option>
<option value="referido">Me recomendaron</option>
<option value="google">Búsqueda en Google</option>
<option value="otro">Otro</option>
</select>
</div>
<!-- Checkbox de consentimiento -->
<div class="form-consentimiento">
<input type="checkbox" id="consentimiento" name="consentimiento" required>
<label for="consentimiento">
Acepto que mis datos sean utilizados para contactarme respecto a mi consulta. <span class="form-required">*</span>
</label>
</div>
<!-- Honeypot anti-spam: invisible para humanos -->
<div class="form-honeypot" aria-hidden="true">
<label for="website">No completar este campo</label>
<input type="text" id="website" name="website" tabindex="-1" autocomplete="off">
</div>
<button type="submit" class="btn btn-primary btn-form-enviar">
Enviar consulta
<span class="btn-arrow">→</span>
</button>
<p class="form-nota">
<small>Te respondemos en menos de 48 horas hábiles. Sin spam, sin llamadas en frío.</small>
</p>
</form>
</div>
</section>
<!-- Sección 3: Redes sociales -->
<section id="contacto-section-3">
<h3>Síguenos</h3>
<ul class="contact-social">
<li><a href="#" target="_blank" rel="noopener">[Red 1]</a></li>
<li><a href="#" target="_blank" rel="noopener">[Red 2]</a></li>
<li><a href="#" target="_blank" rel="noopener">[Red 3]</a></li>
</ul>
<!-- SECCIÓN 3: QUÉ PASA DESPUÉS -->
<section class="proceso-section">
<div class="section-header">
<h2 class="section-title">Qué pasa después de tu mensaje</h2>
<p class="section-subtitle"></p>
</div>
<div class="proceso-grid">
<div class="proceso-paso">
<div class="proceso-numero">01</div>
<h3>Lectura inicial</h3>
<p>Analizamos tu mensaje y tu situación actual. Si vemos que podemos aportar valor real, te agendamos una llamada de diagnóstico.</p>
</div>
<div class="proceso-paso">
<div class="proceso-numero">02</div>
<h3>Diagnóstico estratégico</h3>
<p>Sesión de 30–45 minutos para entender en profundidad tu marca, objetivos y desafíos. Sin costo y sin compromiso.</p>
</div>
<div class="proceso-paso">
<div class="proceso-numero">03</div>
<h3>Propuesta a medida</h3>
<p>Te enviamos una propuesta detallada con alcance, tiempos, inversión y entregables. Solo avanzamos si hay encaje mutuo.</p>
</div>
</div>
</section>
<!-- Sección 4: WhatsApp directo -->
<section id="contacto-section-4">
<h3>¿Prefieres WhatsApp?</h3>
<a class="whatsapp-link"
href="https://wa.me/[NUMERO]?text=[MENSAJE_PREDEFINIDO]"
target="_blank"
rel="noopener">
Escríbenos por WhatsApp
</a>
<!-- SECCIÓN 4: NOTAS IMPORTANTES -->
<section class="notas-section">
<div class="notas-container">
<div class="nota-item">
<strong>Presupuesto publicitario aparte</strong>
<p>La inversión en Meta Ads, Google Ads u otras plataformas se abona directamente a cada proveedor. Nuestros honorarios cubren estrategia, creatividades y optimización.</p>
</div>
<div class="nota-item">
<strong>Capacidad controlada</strong>
<p>Trabajamos con un número limitado de cuentas por mes para garantizar la calidad boutique. Si no podemos tomar tu proyecto ahora, te lo decimos con transparencia.</p>
</div>
<div class="nota-item">
<strong>Cero plantillas</strong>
<p>Cada propuesta es única. No vendemos paquetes cerrados: diseñamos la solución que tu marca necesita en su etapa actual.</p>
</div>
</div>
</section>
<!-- SECCIÓN 5: CTA FINAL -->
<section class="cta-section">
<div class="cta-card">
<h2 class="cta-title">¿Preferís una conversación directa?</h2>
<p class="cta-subtitle">Agendá una llamada de 15 minutos sin compromiso. Ideal si tenés dudas o querés validar si somos el equipo adecuado para tu proyecto.</p>
<div class="cta-buttons">
<a href="https://wa.me/543886118304" target="_blank" rel="noopener" class="btn btn-cta-primary">Agendar llamada</a>
<a href="https://wa.me/543886118304" target="_blank" rel="noopener" class="btn btn-cta-secondary">Escribir por WhatsApp</a>
</div>
</div>
</section>
<!-- MODAL DE ÉXITO -->
<div id="modal-contacto" role="dialog" aria-modal="true" aria-hidden="true" aria-labelledby="modal-titulo">
<div class="modal-card">
<div class="modal-icono" aria-hidden="true">✓</div>
<h2 id="modal-titulo" class="modal-titulo">¡Mensaje enviado!</h2>
<p class="modal-mensaje">Gracias por escribirnos. Te contactaremos en menos de 48 horas hábiles.</p>
<button type="button" class="modal-cerrar">Volver al inicio</button>
</div>
</div>
</main>
<div id="footer-container"></div>
<script src="scripts/main.js"></script>
<script src="scripts/efecto.js"></script>
<script src="scripts/contacto.js"></script>
<script src="scripts/fluid.js"></script>
</body>
</html>
+171
View File
@@ -0,0 +1,171 @@
<?php
/**
* Endpoint AJAX del formulario de contacto.
* Recibe POST y responde JSON.
*/
// ── Silenciar salida directa, solo JSON ────────────────────────────────
if (ob_get_length() > 0) { ob_clean(); }
header('Content-Type: application/json; charset=UTF-8');
// ── Errores a log, no a pantalla ───────────────────────────────────────
ini_set('display_errors', 0);
ini_set('display_startup_errors', 0);
ini_set('log_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/config.php';
require_once __DIR__ . '/validar.php';
// ── Respuesta helper ───────────────────────────────────────────────────
function responder($status, $message, $code = 200, $extra = []) {
http_response_code($code);
echo json_encode(array_merge([
'status' => $status,
'message' => $message,
], $extra));
exit;
}
// ── Método ─────────────────────────────────────────────────────────────
if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
responder('error', 'Método no permitido.', 405);
}
// ── Honeypot ───────────────────────────────────────────────────────────
if (!empty($_POST['website'])) {
// Fingimos éxito para no darle pistas al bot
responder('success', '¡Gracias! Te contactaremos a la brevedad.');
}
// ── Validación ─────────────────────────────────────────────────────────
$resultado = validar_contacto($_POST);
if (!$resultado['ok']) {
responder('error', implode(' ', $resultado['errores']), 400);
}
$d = $resultado['datos'];
// ── PHPMailer ──────────────────────────────────────────────────────────
require_once __DIR__ . '/lib/PHPMailer.php';
require_once __DIR__ . '/lib/SMTP.php';
require_once __DIR__ . '/lib/Exception.php';
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\SMTP;
// ── Mapas para mostrar etiquetas legibles ─────────────────────────────
$etiquetas = [
'servicio' => [
'branding' => 'Branding & Identidad',
'web' => 'Desarrollo Web a Medida',
'rrss' => 'Gestión de Redes Sociales',
'automatizaciones'=> 'Automatizaciones & Flujos',
'paid' => 'Paid Media & Campañas',
'ecosistema' => 'Ecosistema Digital Completo',
'otro' => 'Otro / Aún no definido',
],
'etapa' => [
'idea' => 'Solo tengo la idea',
'inicio' => 'Estoy empezando',
'marcha' => 'En marcha, necesito orden',
'redisenio' => 'Rediseñar / reposicionar',
'escalar' => 'Escalar lo existente',
],
'presupuesto' => [
'esencial' => 'Hasta $250.000 (Esencial)',
'impulso' => '$250.000 – $500.000 (Impulso)',
'premium' => '$500.000 – $800.000 (Premium)',
'elite' => 'Más de $800.000 (Élite)',
'proyecto' => 'Proyecto cerrado (one-off)',
'no-se' => 'A evaluar por el equipo',
],
'origen' => [
'instagram' => 'Instagram',
'linkedin' => 'LinkedIn',
'referido' => 'Referido',
'google' => 'Google',
'otro' => 'Otro',
],
];
$mail = new PHPMailer(true);
try {
// SMTP
$mail->isSMTP();
$mail->Host = SMTP_HOST;
$mail->SMTPAuth = true;
$mail->Username = SMTP_USER;
$mail->Password = SMTP_PASS;
$mail->SMTPSecure = SMTP_SECURE;
$mail->Port = SMTP_PORT;
$mail->CharSet = 'UTF-8';
$mail->SMTPDebug = 0;
// De / Para
$mail->setFrom(SMTP_FROM, SMTP_FROM_NAME);
$mail->addAddress(MAIL_TO, MAIL_TO_NAME);
$mail->addReplyTo($d['email'], $d['nombre']);
// Contenido
$mail->Subject = 'Nuevo contacto: ' . $d['nombre'] . ($d['empresa'] ? ' (' . $d['empresa'] . ')' : '');
$mail->isHTML(true);
$servicio_txt = $etiquetas['servicio'][$d['servicio']] ?? '—';
$etapa_txt = $etiquetas['etapa'][$d['etapa']] ?? '—';
$presupuesto_txt = $etiquetas['presupuesto'][$d['presupuesto']] ?? '—';
$origen_txt = $etiquetas['origen'][$d['origen']] ?? '—';
$rows = [
'Nombre' => $d['nombre'],
'Empresa / Marca' => $d['empresa'] ?: '—',
'Email' => $d['email'],
'Teléfono' => $d['telefono'] ?: '—',
'Servicio' => $servicio_txt,
'Etapa' => $etapa_txt,
'Presupuesto' => $presupuesto_txt,
'Cómo nos conoció'=> $origen_txt,
];
$html = '<div style="font-family:Arial,sans-serif;font-size:14px;color:#222;max-width:640px">';
$html .= '<h2 style="margin:0 0 16px;color:#111">Nueva consulta desde el sitio</h2>';
$html .= '<table cellpadding="8" cellspacing="0" style="border-collapse:collapse;width:100%">';
foreach ($rows as $label => $valor) {
$html .= '<tr>';
$html .= '<td style="background:#f5f2ec;border:1px solid #e5e0d5;font-weight:bold;width:180px">' . htmlspecialchars($label) . '</td>';
$html .= '<td style="border:1px solid #e5e0d5">' . htmlspecialchars($valor) . '</td>';
$html .= '</tr>';
}
$html .= '</table>';
$html .= '<h3 style="margin:24px 0 8px;color:#111">Mensaje</h3>';
$html .= '<div style="white-space:pre-wrap;background:#fafafa;border:1px solid #eee;padding:12px;border-radius:6px">'
. htmlspecialchars($d['mensaje']) . '</div>';
$html .= '</div>';
$mail->Body = $html;
$mail->AltBody = "Nueva consulta\n\n"
. "Nombre: {$d['nombre']}\n"
. "Empresa: {$d['empresa']}\n"
. "Email: {$d['email']}\n"
. "Teléfono: {$d['telefono']}\n"
. "Servicio: $servicio_txt\n"
. "Etapa: $etapa_txt\n"
. "Presupuesto: $presupuesto_txt\n"
. "Origen: $origen_txt\n\n"
. "Mensaje:\n{$d['mensaje']}\n";
$mail->send();
responder('success', '¡Gracias! Te contactaremos en menos de 48 horas hábiles.', 200, [
'redirect' => REDIRECT_URL,
'delay' => REDIRECT_MS,
]);
} catch (Exception $e) {
error_log('[contacto] Falló el envío: ' . $mail->ErrorInfo);
$msg = DEBUG_MODE
? 'Error SMTP: ' . $mail->ErrorInfo
: 'No pudimos enviar tu mensaje. Probá por WhatsApp o intentá más tarde.';
responder('error', $msg, 500);
}
+4 -4
View File
@@ -3,7 +3,7 @@
<!-- SECCIÓN 1: Contenido Principal (Columnas, enlaces y CTAs) -->
<div class="footer-content">
<div class="footer-col" id="footer-brand">
<a href="inicio.html" class="logo">
<a href="index.html" class="logo">
<img src="assets/logos/logo_ciruela.png" alt="Logo" class="logo-light">
<img src="assets/logos/logo_frio.png" alt="Logo" class="logo-dark">
</a>
@@ -13,10 +13,10 @@
<div class="footer-col" id="footer-links">
<h4>Explorar</h4>
<ul>
<li><a href="inicio.html">Inicio</a></li>
<li><a href="index.html">Inicio</a></li>
<li><a href="servicios.html">Servicios</a></li>
<li><a href="planes.html">Planes</a></li>
<li><a href="portfolio.html">Portfolio</a></li>
<li><a href="index.html#portfolio">Portfolio</a></li>
<li><a href="blog.html">Blog</a></li>
</ul>
</div>
@@ -36,7 +36,7 @@
<h4></h4>
<div class="menu-buttons">
<a href="contacto.html" class="btn-menu btn-menu-primary">¿Tenés un proyecto en mente?</a>
<a href="inicio.html#diagnostico" class="btn-menu btn-menu-secondary">Empezar diagnóstico</a>
<a href="index.html#diagnostico" class="btn-menu btn-menu-secondary">Empezar diagnóstico</a>
<div class="menu-social">
<a href="https://www.instagram.com/amoryroma.creativo" target="_blank" rel="noopener"><i class="fa-brands fa-instagram"></i> Instagram</a>
<a href="https://web.facebook.com/amoryroma.creativo/" target="_blank" rel="noopener"><i class="fa-brands fa-facebook"></i> Facebook</a>
+18 -11
View File
@@ -1,6 +1,6 @@
<header class="site-header">
<nav class="main-nav">
<a href="inicio.html" class="logo">
<a href="index.html" class="logo">
<img src="assets/logos/logo_ciruela.png" alt="Logo" class="logo-light">
<img src="assets/logos/logo_frio.png" alt="Logo" class="logo-dark">
</a>
@@ -35,11 +35,12 @@
<div class="menu-column">
<h3>Amor&Roma</h3>
<ul>
<li><a href="inicio.html">Comencemos</a></li>
<li><a href="inicio.html#servicios">Qué hacemos?</a></li>
<li><a href="inicio.html#diagnostico">Diagnóstico</a></li>
<li><a href="inicio.html#planes-destacados">Destacados</a></li>
<li><a href="inicio.html#portfolio">Desafios</a></li>
<li><a href="index.html">Comencemos</a></li>
<li><a href="index.html#servicios">Qué hacemos?</a></li>
<li><a href="index.html#diagnostico">Diagnóstico</a></li>
<li><a href="index.html#metodologia">Método A&R</a></li>
<li><a href="index.html#planes-destacados">Destacados</a></li>
<li><a href="index.html#portfolio">Desafios</a></li>
</ul>
</div>
@@ -47,10 +48,10 @@
<div class="menu-column">
<h3>Navegación</h3>
<ul>
<li><a href="inicio.html">Inicio</a></li>
<li><a href="index.html">Inicio</a></li>
<li><a href="servicios.html">Servicios</a></li>
<li><a href="planes.html">Planes</a></li>
<li><a href="portfolio.html">Portfolio</a></li>
<!--<li><a href="portfolio.html">Portfolio</a></li>-->
<li><a href="nosotros.html">Nosotros</a></li>
<li><a href="blog.html">Blog</a></li>
<li><a href="contacto.html">Contacto</a></li>
@@ -68,7 +69,13 @@
<p class="contact-item">
<span class="contact-icon icon-phone" aria-hidden="true"></span>
<span><a href="https://wa.me/543886118304">Whatsapp</a></span>
<span>
<a href="https://wa.me/543886118304?text=Hola!%20Quiero%20m%C3%A1s%20informaci%C3%B3n."
target="_blank"
rel="noopener noreferrer">
Whatsapp
</a>
</span>
</p>
<div class="menu-social">
@@ -80,12 +87,12 @@
<div class="menu-buttons">
<a href="contacto.html" class="btn-menu btn-menu-primary">Hablemos</a>
<a href="trabaja.html" class="btn-menu btn-menu-secondary">Trabaja con nosotros</a>
<!--<a href="trabaja.html" class="btn-menu btn-menu-secondary">Trabaja con nosotros</a>-->
</div>
<!-- Logo de marca integrado en el menú -->
<div class="menu-brand">
<a href="inicio.html" class="logo">
<a href="index.html" class="logo">
<img src="assets/logos/logo_ciruela.png" alt="Logo" class="logo-light">
<img src="assets/logos/logo_frio.png" alt="Logo" class="logo-dark">
</a>
+83 -56
View File
@@ -4,22 +4,27 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<link rel="icon" href="/assets/img/favicon.ico" type="image/x-icon">
<title>Inicio - A&R</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css">
<link rel="stylesheet" href="style/main.css">
</head>
<body>
<div id="fluid-bg" aria-hidden="true">
<canvas id="fluidCanvas"></canvas>
</div>
<div id="menu-container"></div>
<main>
<!-- Sección Hero -->
<section id="hero" class="hero-section">
<div class="hero-content">
<h1 class="hero-title">Marcas con esencia, construidas con estrategia</h1>
<p class="hero-subtitle">Diseñamos servicios que se adaptan a tu realidad, para ayudarte a crecer sin perder lo que te hace único</p>
<span class="badge-filosofia">Agencia Boutique de Marketing Digital</span>
<h1 class="hero-title">En un mundo de ruido, solo lo auténtico resuena</h1>
<p class="hero-subtitle">Combinamos el instinto creativo con la ingeniería de procesos para desarrollar tu identidad, sitio web y automatizaciones. <br>Porque lo auténtico, cuando está bien construido, siempre deja eco.</p>
<div class="hero-cta-group">
<a href="#" class="btn btn-primary hero-cta-primary">Hablemos</a>
<a href="inicio.html#servicios" class="btn btn-secondary hero-cta-secondary">Conocé más</a>
<a href="contacto.html" class="btn btn-primary hero-cta-primary">Hablemos</a>
<a href="index.html#servicios" class="btn btn-secondary hero-cta-secondary">Conocé más</a>
</div>
</div>
</section>
@@ -30,7 +35,7 @@
<!-- Columna Izquierda: Texto introductorio -->
<div class="servicios-intro">
<h2 class="servicios-title">Soluciones digitales diseñadas para hacer crecer tu negocio</h2>
<p class="servicios-subtitle">Contamos con soluciones estratégicas para potenciar tu marca en cada etapa de su crecimiento.</p>
<p class="servicios-subtitle">Podemos potenciar tu marca en cada etapa de su crecimiento.</p>
<a href="servicios.html" class="btn btn-secondary">Ver todos los servicios</a>
</div>
@@ -133,32 +138,52 @@
<section id="diagnostico" class="diagnostico-section">
<div class="diagnostico-header">
<h2 class="diagnostico-title">¿Cuál es el siguiente paso estratégico para tu negocio?</h2>
<p class="diagnostico-subtitle">Un recorrido de orientación diseñado para entender el momento actual de tu marca,<br> y definir con precisión quirúrgica la solución que necesitas.</p>
<p class="diagnostico-subtitle">Un recorrido de orientación diseñado para entender el momento actual de tu marca, y definir con precisión quirúrgica la solución que necesitás.</p>
</div>
<div class="diagnostico-card">
<!-- Barra de Progreso -->
<div class="progreso-wrapper">
<div class="progreso-barra">
<div class="progreso-barra-completado" id="progreso-completado"></div>
<!-- PANTALLA DE BIENVENIDA (visible al inicio) -->
<div id="diagnostico-bienvenida" class="diagnostico-bienvenida">
<div class="bienvenida-icono">
<span class="icono-diagnostico" aria-hidden="true"></span>
</div>
<div class="progreso-texto" id="progreso-texto">Pregunta 1 de 4</div>
<h3 class="bienvenida-titulo">Diagnóstico Express</h3>
<p class="bienvenida-texto">
Respondé 4 preguntas rápidas y te vamos a recomendar el servicio ideal para el momento en que está tu marca.
</p>
<ul class="bienvenida-detalles">
<li><span class="detalle-icono"></span><i class="fa-regular fa-alarm-clock"></i> 2 minutos</li>
<li><span class="detalle-icono"></span><i class="fa-solid fa-bullseye"></i> Recomendación personalizada</li>
<li><span class="detalle-icono"></span><i class="fa-regular fa-comment-dots"></i> Sin compromiso</li>
</ul>
<button class="btn btn-primary btn-comenzar" id="btn-comenzar">
Comenzar diagnóstico
<span class="btn-arrow" aria-hidden="true">→</span>
</button>
</div>
<!-- Contenedor de Preguntas -->
<div id="cuestionario-contenedor">
<!-- Las preguntas se generan dinámicamente con JavaScript -->
<!-- CUESTIONARIO (oculto hasta hacer clic en comenzar) -->
<div id="diagnostico-quiz" class="diagnostico-quiz" style="display: none;">
<!-- Barra de Progreso -->
<div class="progreso-wrapper">
<div class="progreso-barra">
<div class="progreso-barra-completado" id="progreso-completado"></div>
</div>
<div class="progreso-texto" id="progreso-texto">Pregunta 1 de 4</div>
</div>
<!-- Contenedor de Preguntas -->
<div id="cuestionario-contenedor" class="cuestionario-contenedor">
<!-- Se genera dinámicamente con JavaScript -->
</div>
</div>
<!-- Botón Reiniciar -->
<button class="btn-reiniciar" id="btn-reiniciar">
Reiniciar Diagnóstico
</button>
<!-- Contenedor de Resultados (oculto inicialmente) -->
<!-- RESULTADO (oculto inicialmente) -->
<div id="resultado-contenedor" class="resultado-contenedor" style="display: none;">
<!-- El resultado se genera dinámicamente con JavaScript -->
<!-- Se genera dinámicamente con JavaScript -->
</div>
</div>
</section>
@@ -338,7 +363,7 @@
<div class="portfolio-text">
<h2 class="portfolio-title">Nuestros últimos desafíos</h2>
<p class="portfolio-subtitle">Cada proyecto es una oportunidad para crear algo único y memorable</p>
<a href="portfolio.html" class="btn btn-secondary">Ver portfolio completo</a>
<!--<a href="portfolio.html" class="btn btn-secondary">Ver portfolio completo</a>-->
</div>
<!-- Columna Derecha: Carrusel -->
@@ -346,35 +371,6 @@
<div class="carousel-container">
<!-- Slide 1 -->
<div class="carousel-slide active">
<div class="slide-tags">
<span class="slide-tag">Branding</span>
<span class="slide-tag">Identidad Visual</span>
<span class="slide-tag">Manual de Marca</span>
<span class="slide-tag">Redes Sociales</span>
<span class="slide-tag">Contenido Audiovisual</span>
<span class="slide-tag">Paid Media</span>
<span class="slide-tag">Estrategia Digital</span>
</div>
<div class="slide-image-wrapper">
<img src="assets/clientes/1_1.png" alt="Mordi" class="carousel-image">
</div>
</div>
<!-- Slide 2 -->
<div class="carousel-slide">
<div class="slide-tags">
<span class="slide-tag">Web</span>
<span class="slide-tag">UX/UI</span>
<span class="slide-tag">Apertura de Redes</span>
<span class="slide-tag">SEO</span>
</div>
<div class="slide-image-wrapper">
<img src="assets/clientes/2_1.png" alt="ArWork's" class="carousel-image">
</div>
</div>
<!-- Slide 3 -->
<div class="carousel-slide">
<div class="slide-tags">
<span class="slide-tag">Diseño Web</span>
@@ -385,7 +381,7 @@
</div>
</div>
<!-- Slide 4 -->
<!-- Slide 2 -->
<div class="carousel-slide">
<div class="slide-tags">
<span class="slide-tag">Branding</span>
@@ -401,6 +397,36 @@
</div>
</div>
<!-- Slide 3 -->
<div class="carousel-slide active">
<div class="slide-tags">
<span class="slide-tag">Branding</span>
<span class="slide-tag">Creación de personaje</span>
<span class="slide-tag">Identidad Visual</span>
<span class="slide-tag">Manual de Marca</span>
<span class="slide-tag">Redes Sociales</span>
<span class="slide-tag">Contenido Audiovisual</span>
<span class="slide-tag">Paid Media</span>
<span class="slide-tag">Estrategia Digital</span>
</div>
<div class="slide-image-wrapper">
<img src="assets/clientes/1_1.png" alt="Mordi" class="carousel-image">
</div>
</div>
<!-- Slide 4 -->
<div class="carousel-slide">
<div class="slide-tags">
<span class="slide-tag">Web</span>
<span class="slide-tag">UX/UI</span>
<span class="slide-tag">Apertura de Redes</span>
<span class="slide-tag">SEO</span>
</div>
<div class="slide-image-wrapper">
<img src="assets/clientes/2_1.png" alt="ArWork's" class="carousel-image">
</div>
</div>
<!-- Slide 5 -->
<div class="carousel-slide">
<div class="slide-tags">
@@ -510,6 +536,7 @@
<div id="footer-container"></div>
<script src="scripts/main.js"></script>
<script src="scripts/efecto.js"></script>
<script src="scripts/fluid.js"></script>
</body>
</html>
+40
View File
@@ -0,0 +1,40 @@
<?php
/**
* PHPMailer Exception class.
* PHP Version 5.5.
*
* @see https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
*
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
* @author Brent R. Matzelle (original founder)
* @copyright 2012 - 2020 Marcus Bointon
* @copyright 2010 - 2012 Jim Jagielski
* @copyright 2004 - 2009 Andy Prevost
* @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License
* @note This program is distributed in the hope that it will be useful - WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*/
namespace PHPMailer\PHPMailer;
/**
* PHPMailer exception handler.
*
* @author Marcus Bointon <phpmailer@synchromedia.co.uk>
*/
class Exception extends \Exception
{
/**
* Prettify error message output.
*
* @return string
*/
public function errorMessage()
{
return '<strong>' . htmlspecialchars($this->getMessage(), ENT_COMPAT | ENT_HTML401) . "</strong><br />\n";
}
}
+5586
View File
File diff suppressed because it is too large Load Diff
+1617
View File
File diff suppressed because it is too large Load Diff
+225 -6
View File
@@ -3,22 +3,241 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<title>Nosotros - [Nombre de la agencia]</title>
<meta name="description" content="Conoce la filosofía, metodología y principios de Amor y Roma, agencia boutique de marketing digital. Marcas con esencia, construidas con estrategia.">
<title>Nosotros | Amor y Roma — Agencia Boutique</title>
<link rel="icon" href="/assets/img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css">
<link rel="stylesheet" href="style/main.css">
<link rel="stylesheet" href="style/nosotros.css">
</head>
<body>
<div id="fluid-bg" aria-hidden="true">
<canvas id="fluidCanvas"></canvas>
</div>
<div id="menu-container"></div>
<main>
<section id="nosotros-section-1"><h2>Sección 1</h2><p>Contenido pendiente de definir.</p></section>
<section id="nosotros-section-2"><h2>Sección 2</h2><p>Contenido pendiente de definir.</p></section>
<section id="nosotros-section-3"><h2>Sección 3</h2><p>Contenido pendiente de definir.</p></section>
<!-- SECCIÓN 1: HERO / FILOSOFÍA -->
<section class="hero-section nosotros-hero">
<div class="hero-content">
<h1 class="hero-title">Amor&Roma</h1>
<p class="hero-subtitle">
No somos una agencia tradicional. <br>Combinamos el arte del marketing digital con la ciencia de los datos.
</p>
<div class="hero-cta-group">
<a href="#nosotros-dualidad" class="btn btn-primary">Descubre nuestra dualidad</a>
<a href="contacto.html" class="btn btn-secondary">Hablemos de tu proyecto</a>
</div>
</div>
</section>
<!-- SECCIÓN 2: LA DUALIDAD DE MARCA -->
<section id="nosotros-dualidad" class="dualidad-section">
<div class="section-header">
<h2 class="section-title">Nuestra Dualidad Estratégica</h2>
<p class="section-subtitle">El nombre de nuestra agencia no responde a una visión romántica tradicional, sino a dos pilares operativos inseparables.</p>
</div>
<div class="dualidad-grid">
<article class="dualidad-card card-amor">
<div class="card-icon icon-amor"></div>
<h3>Amor</h3>
<span class="card-tag">La Pasión y el Arte</span>
<p>Representa el instinto creativo, la intuición visual, la dirección de arte meticulosa, la empatía con la visión del cliente y la estética no negociable. <br>Es el alma y la identidad de cada marca.</p>
</article>
<article class="dualidad-card card-roma">
<div class="card-icon icon-roma"></div>
<h3>Roma</h3>
<span class="card-tag">La Construcción y la Estructura</span>
<p>Representa la arquitectura, el método, la ingeniería de procesos, la estrategia a largo plazo y la infraestructura digital orientada a resultados. <br>Es el imperio que sostiene esa visión.</p>
</article>
</div>
</section>
<!-- SECCIÓN: QUIÉNES SOMOS / EQUIPO -->
<section id="nosotros-equipo" class="equipo-section">
<div class="section-header">
<h2 class="section-title">Mentes creativas, con <span class="text-gradient">mucha energía.</span></h2>
<p class="section-subtitle">Combinamos el arte del Marketing con la Ciencia de los datos.</p>
</div>
<div class="equipo-grid">
<!-- PATRICIA -->
<article class="equipo-card">
<div class="equipo-firma">Patricia Pugliese</div>
<span class="equipo-rol">Estrategia & Creatividad</span>
<p class="equipo-descripcion">
Investigación, branding, identidad visual y todo lo que da forma a una marca con personalidad.
</p>
</article>
<!-- FRANCISCO -->
<article class="equipo-card">
<div class="equipo-firma">Francisco Anfuso</div>
<span class="equipo-rol">Desarrollo & Tecnología</span>
<p class="equipo-descripcion">
Diseño web, desarrollo, automatizaciones y soluciones técnicas que funcionan sin complicaciones.
</p>
</article>
</div>
<p class="equipo-colaboradores">
Trabajamos en equipo ayudando a las PyMEs a competir y crecer. </p>
</section>
<!-- SECCIÓN 3: PRINCIPIOS BOUTIQUE -->
<section id="nosotros-principios" class="principios-section">
<div class="section-header">
<h2 class="section-title">El Posicionamiento "Boutique"</h2>
<p class="section-subtitle">Ser una agencia boutique implica tres principios rectores que protegen la calidad y el resultado de tu proyecto.</p>
</div>
<div class="principios-grid">
<div class="principio-item">
<div class="principio-numero">01</div>
<h4>Cero plantillas prefabricadas</h4>
<p>Cada diseño, arquitectura web o plan de contenidos se crea a medida de la identidad, necesidades y madurez real de tu negocio.</p>
</div>
<div class="principio-item">
<div class="principio-numero">02</div>
<h4>Capacidad controlada de cuentas</h4>
<p>Priorizamos la profundidad operativa sobre el volumen desmedido de clientes, garantizando atención directa y personalización real.</p>
</div>
<div class="principio-item">
<div class="principio-numero">03</div>
<h4>Foco visual y de contenido</h4>
<p>Aunque la automatización es clave, nuestro valor diferencial perceptible está en el criterio estético, la narrativa visual y la calidad de producción.</p>
</div>
</div>
</section>
<!-- SECCIÓN 4: TRANSPARENCIA -->
<section id="nosotros-transparencia" class="transparencia-section">
<div class="section-header">
<h2 class="section-title">Transparencia antes de la primera reunión</h2>
<p class="section-subtitle">Los números, dichos de entrada, no como parte de una negociación, sino como punto de partida.</p>
</div>
<div class="transparencia-grid">
<!-- Tarjeta 1: INVERSIÓN -->
<article class="transparencia-card">
<div class="transparencia-icono">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<path d="M12 2v20M2 12h20" stroke-linecap="round"/>
<circle cx="12" cy="12" r="10" stroke-linecap="round"/>
</svg>
</div>
<p class="transparencia-titulo">INVERSIÓN</p>
<p class="transparencia-dato">Desde $250.000/mes</p>
<p class="transparencia-texto">
Planes desde <strong>$250.000</strong> (Esencia) hasta <strong>$1.000.000</strong> (Élite). El armado inicial —branding, sitio web— se presupuesta por proyecto.
</p>
</article>
<!-- Tarjeta 2: TIEMPOS -->
<article class="transparencia-card">
<div class="transparencia-icono">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<circle cx="12" cy="12" r="10" stroke-linecap="round"/>
<path d="M12 6v6l4 2" stroke-linecap="round"/>
</svg>
</div>
<p class="transparencia-titulo">TIEMPOS</p>
<p class="transparencia-dato">15-30 días</p>
<p class="transparencia-texto">
Presencia digital lista en <strong>15-30 días</strong>. Resultados de posicionamiento sostenido en <strong>3-6 meses</strong>. Sin promesas de magia inmediata.
</p>
</article>
<!-- Tarjeta 3: CONTRATO -->
<article class="transparencia-card">
<div class="transparencia-icono">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" stroke-linecap="round"/>
<path d="M14 2v6h6M16 13H8M16 17H8M10 9H8" stroke-linecap="round"/>
</svg>
</div>
<p class="transparencia-titulo">CONTRATO</p>
<p class="transparencia-dato">3 meses · luego mensual</p>
<p class="transparencia-texto">
Compromiso mínimo de <strong>3 meses</strong> para que la estrategia tome forma, luego renovación mensual. Cancelación con <strong>30 días de aviso</strong>.
</p>
</article>
</div>
</section>
<!-- SECCIÓN 5: CASOS TESTIGO / ARQUETIPOS -->
<section id="nosotros-casos" class="casos-section">
<div class="section-header">
<h2 class="section-title">Matriz de Soluciones</h2>
<p class="section-subtitle">Nuestra experiencia define arquetipos de solución que comercializamos con total solvencia operativa.</p>
</div>
<div class="casos-grid-simetrico">
<!-- ARQUETIPO 1 -->
<article class="caso-card">
<div class="caso-header">
<span class="caso-badge">Mordi - El mundo en un bocado</span>
<h3 class="caso-titulo">Identidad Integral</h3>
</div>
<p class="caso-descripcion">Desarrollo de marca completo, mascota propia y administración continua de redes.</p>
<div class="caso-leccion">
<strong>Lección:</strong> Capacidad de crear activos creativos de alto impacto y sostenerlos con pauta publicitaria.
</div>
</article>
<!-- ARQUETIPO 2 -->
<article class="caso-card">
<div class="caso-header">
<span class="caso-badge">ArWorks - higiene y seguridad</span>
<h3 class="caso-titulo">Infraestructura B2B</h3>
</div>
<p class="caso-descripcion">Consultora de Seguridad: Sitio web corporativo a medida y arquitectura sobria.</p>
<div class="caso-leccion">
<strong>Lección:</strong> Validación de desarrollo web enfocado en transmitir seriedad, confianza y soporte a procesos complejos.
</div>
</article>
<!-- ARQUETIPO 3 (INSÍGNIA) -->
<article class="caso-card caso-insignia">
<div class="caso-header">
<span class="caso-badge caso-badge-insignia">vetta io</span>
<h3 class="caso-titulo">Ecosistema Digital Completo</h3>
</div>
<p class="caso-descripcion">Empresa de Tecnología: Branding + Web a medida + RRSS activas.</p>
<div class="caso-leccion caso-leccion-insignia">
<strong>Lección:</strong> Nuestro servicio estrella. Integra identidad desde cero, presencia web sólida y canal de comunicación activo.
</div>
</article>
<!-- ARQUETIPO 4 -->
<article class="caso-card">
<div class="caso-header">
<span class="caso-badge">ide - consultores</span>
<h3 class="caso-titulo">Profesionalización de Servicios</h3>
</div>
<p class="caso-descripcion">Consultores Independientes: Web a medida + Gestión estratégica de RRSS.</p>
<div class="caso-leccion">
<strong>Lección:</strong> El modelo estándar para pequeñas firmas: plataforma para captar y validar, redes para nutrir y generar confianza.
</div>
</article>
</div>
</section>
<!-- SECCIÓN 6: CTA FINAL -->
<section class="cta-section">
<div class="cta-card">
<h2 class="cta-title">¿Listo para construir tu imperio con esencia?</h2>
<p class="cta-subtitle">Agendemos una reunión. Sin plantillas, sin compromisos, solo estrategia a medida.</p>
<div class="cta-buttons">
<a href="contacto.html" class="btn btn-cta-primary">Hablemos de tu proyecto</a>
<a href="index.html#portfolio" class="btn btn-cta-secondary">Ver Casos de Éxito</a>
</div>
</div>
</section>
</main>
<div id="footer-container"></div>
<script src="scripts/main.js"></script>
<script src="scripts/efecto.js"></script>
<script src="scripts/fluid.js"></script>
</body>
</html>
+496 -10
View File
@@ -3,26 +3,512 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<title>Planes - [Nombre de la agencia]</title>
<meta name="description" content="Planes de gestión de redes sociales de Amor y Roma. Soluciones escalables desde $250.000/mes.">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css">
<title>Planes - Amor y Roma</title>
<link rel="icon" href="/assets/img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="style/main.css">
<link rel="stylesheet" href="style/planes.css">
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
</head>
<body>
<div id="fluid-bg" aria-hidden="true">
<canvas id="fluidCanvas"></canvas>
</div>
<div id="menu-container"></div>
<main>
<section id="planes-section-1"><h2>Sección 1</h2><p>Contenido pendiente de definir.</p></section>
<section id="planes-section-2"><h2>Sección 2</h2><p>Contenido pendiente de definir.</p></section>
<section id="planes-section-3"><h2>Sección 3</h2><p>Contenido pendiente de definir.</p></section>
<section id="planes-section-4"><h2>Sección 4</h2><p>Contenido pendiente de definir.</p></section>
<section id="planes-section-5"><h2>Sección 5</h2><p>Contenido pendiente de definir.</p></section>
<section id="planes-section-6"><h2>Sección 6</h2><p>Contenido pendiente de definir.</p></section>
<section id="planes-section-7"><h2>Sección 7</h2><p>Contenido pendiente de definir.</p></section>
<!-- Sección 1: Hero -->
<section id="planes-hero" class="planes-hero">
<div class="planes-hero-content">
<span class="planes-hero-tag">Planes de Redes Sociales</span>
<h1 class="planes-hero-title">Gestión profesional de tus redes</h1>
<p class="planes-hero-subtitle">Elegí el plan que se adapte a tu etapa de crecimiento. Todos incluyen estrategia, diseño y dirección de arte personalizada.</p>
<a href="#planes-selector" class="btn btn-primary planes-hero-cta">Ver planes disponibles</a>
</div>
</section>
<!-- Sección 2: Selector de planes -->
<section id="planes-selector" class="planes-selector-section">
<div class="planes-selector-container">
<!-- Tabs desktop -->
<div class="planes-tabs" role="tablist" aria-label="Selector de planes">
<button class="plan-tab active" role="tab" aria-selected="true" aria-controls="panel-esencial" data-plan="esencial">
<span class="tab-label">Plan Esencial</span>
<span class="tab-precio">$250k</span>
</button>
<button class="plan-tab" role="tab" aria-selected="false" aria-controls="panel-impulso" data-plan="impulso">
<span class="tab-label">Plan Impulso</span>
<span class="tab-precio">$420k</span>
</button>
<button class="plan-tab" role="tab" aria-selected="false" aria-controls="panel-premium" data-plan="premium">
<span class="tab-label">Plan Premium</span>
<span class="tab-precio">$650k</span>
</button>
<button class="plan-tab" role="tab" aria-selected="false" aria-controls="panel-elite" data-plan="elite">
<span class="tab-label">Plan Élite</span>
<span class="tab-precio">$1M</span>
</button>
</div>
<!-- Pills mobile (scroll horizontal) -->
<div class="planes-pills" role="tablist" aria-label="Selector de planes mobile">
<button class="plan-pill active" role="tab" aria-selected="true" aria-controls="panel-esencial" data-plan="esencial">
<span>Esencial</span>
<span class="pill-precio">$250k</span>
</button>
<button class="plan-pill" role="tab" aria-selected="false" aria-controls="panel-impulso" data-plan="impulso">
<span>Impulso</span>
<span class="pill-precio">$420k</span>
</button>
<button class="plan-pill" role="tab" aria-selected="false" aria-controls="panel-premium" data-plan="premium">
<span>Premium</span>
<span class="pill-precio">$650k</span>
</button>
<button class="plan-pill" role="tab" aria-selected="false" aria-controls="panel-elite" data-plan="elite">
<span>Élite</span>
<span class="pill-precio">$1M</span>
</button>
</div>
</div>
</section>
<!-- Sección 3: Panel de contenido dinámico -->
<section id="planes-panel" class="planes-panel-section">
<div class="planes-panel-container">
<!-- Panel: Plan Esencial -->
<div class="plan-panel active" id="panel-esencial" role="tabpanel" data-plan="esencial">
<div class="panel-header">
<span class="panel-categoria">Para emprendedores iniciales</span>
<h2 class="panel-titulo">Plan Esencial</h2>
<p class="panel-subtitulo">Ordená y profesionalizá tu imagen digital con una presencia activa y coherente.</p>
</div>
<div class="panel-grid-dimensiones">
<!-- Dimensión 1: Contenido -->
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-images"></i> Generación de Contenido</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> 8 piezas gráficas/carruseles mensuales</li>
<li><i class="fas fa-check"></i> 4 historias estratégicas por semana</li>
<li><i class="fas fa-check"></i> Dirección de arte básica</li>
</ul>
</div>
<!-- Dimensión 2: Copywriting -->
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-pen-fancy"></i> Copywriting & Arte</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Guías de estilo básicas</li>
<li><i class="fas fa-check"></i> Redacción de copys directos</li>
<li><i class="fas fa-check"></i> Identidad visual coherente</li>
</ul>
</div>
<!-- Dimensión 3: Automatizaciones -->
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-robot"></i> Automatizaciones</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Configuración de respuestas automáticas</li>
<li><i class="fas fa-check"></i> FAQ en DM</li>
<li><i class="fas fa-times"></i> Flujos avanzados no incluidos</li>
</ul>
</div>
<!-- Dimensión 4: Paid Media -->
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-bullhorn"></i> Paid Media (Ads)</h3>
<ul class="dimension-lista">
<li><i class="fas fa-times"></i> No incluye (orgánico puro)</li>
<li><i class="fas fa-info-circle"></i> Disponible como add-on</li>
</ul>
</div>
<!-- Dimensión 5: Gestión -->
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-calendar-check"></i> Gestión y Moderación</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Programación de contenido</li>
<li><i class="fas fa-check"></i> Publicación en horarios óptimos</li>
<li><i class="fas fa-times"></i> Moderación de comunidad no incluida</li>
</ul>
</div>
<!-- Dimensión 6: Reportes -->
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-chart-bar"></i> Reportes y Feedback</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Reporte mensual cuantitativo automatizado</li>
<li><i class="fas fa-check"></i> Métricas básicas de alcance e interacción</li>
</ul>
</div>
</div>
<!-- Tarjeta de Precio -->
<div class="panel-precio-card">
<div class="precio-header">
<span class="precio-label">Inversión mensual</span>
<div class="precio-valor">
<span class="precio-moneda">$</span>
<span class="precio-monto">250.000</span>
<span class="precio-periodo">/mes</span>
</div>
</div>
<a href="contacto.html?plan=esencial" class="btn btn-primary btn-contratar">Contratar este plan</a>
</div>
</div>
<!-- Panel: Plan Impulso -->
<div class="plan-panel" id="panel-impulso" role="tabpanel" data-plan="impulso">
<div class="panel-header">
<span class="panel-categoria">Para pequeños negocios en validación</span>
<h2 class="panel-titulo">Plan Impulso</h2>
<p class="panel-subtitulo">Crecé tu comunidad y generá engagement mediante formatos dinámicos y contenido persuasivo.</p>
</div>
<div class="panel-grid-dimensiones">
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-images"> </i>Generación de Contenido</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> 8 piezas gráficas/carruseles mensuales</li>
<li><i class="fas fa-check"></i> 4 Reels/TikToks producidos</li>
<li><i class="fas fa-check"></i> 6 historias estratégicas por semana</li>
</ul>
</div>
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-pen-fancy"> </i>Copywriting & Arte</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Copywriting persuasivo</li>
<li><i class="fas fa-check"></i> Dirección de arte personalizada</li>
<li><i class="fas fa-check"></i> Guiones de video básicos</li>
</ul>
</div>
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-robot"></i> Automatizaciones</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Flujo automatizado de bienvenida</li>
<li><i class="fas fa-check"></i> Derivación a WhatsApp</li>
<li><i class="fas fa-times"></i> Cualificación avanzada no incluida</li>
</ul>
</div>
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-bullhorn"></i> Paid Media (Ads)</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Configuración de 1 campaña</li>
<li><i class="fas fa-check"></i> Tráfico o alcance local</li>
<li><i class="fas fa-check"></i> Monitoreo básico</li>
</ul>
</div>
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-calendar-check"></i> Gestión y Moderación</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Programación de contenido</li>
<li><i class="fas fa-check"></i> Moderación de comentarios y DMs</li>
<li><i class="fas fa-check"></i> Horarios comerciales</li>
</ul>
</div>
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-chart-bar"></i> Reportes y Feedback</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Reporte mensual con análisis básico</li>
<li><i class="fas fa-check"></i> Métricas clave de engagement</li>
</ul>
</div>
</div>
<div class="panel-precio-card">
<div class="precio-header">
<span class="precio-label">Inversión mensual</span>
<div class="precio-valor">
<span class="precio-moneda">$</span>
<span class="precio-monto">420.000</span>
<span class="precio-periodo">/mes</span>
</div>
</div>
<a href="contacto.html?plan=impulso" class="btn btn-primary btn-contratar">Contratar este plan</a>
</div>
</div>
<!-- Panel: Plan Premium -->
<div class="plan-panel" id="panel-premium" role="tabpanel" data-plan="premium">
<div class="panel-header">
<span class="panel-categoria">Para PyMEs con tracción comercial</span>
<h2 class="panel-titulo">Plan Premium</h2>
<p class="panel-subtitulo">Posicionate como referente en tu sector con contenido de alta producción y estrategia de conversión.</p>
</div>
<div class="panel-grid-dimensiones">
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-images"></i> Generación de Contenido</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> 10 piezas gráficas/carruseles mensuales</li>
<li><i class="fas fa-check"></i> 8 Reels/TikToks producidos</li>
<li><i class="fas fa-check"></i> Historias diarias (días hábiles)</li>
</ul>
</div>
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-pen-fancy"></i> Copywriting & Arte</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Storytelling avanzado</li>
<li><i class="fas fa-check"></i> Guiones de video profesionales</li>
<li><i class="fas fa-check"></i> Diseño editorial premium</li>
</ul>
</div>
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-robot"></i> Automatizaciones</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Flujos de cualificación de leads</li>
<li><i class="fas fa-check"></i> Integración básica a base de datos</li>
<li><i class="fas fa-check"></i> Respuestas por palabras clave</li>
</ul>
</div>
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-bullhorn"></i> Paid Media (Ads)</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Gestión y optimización de campañas</li>
<li><i class="fas fa-check"></i> Conversión y captación de prospectos</li>
<li><i class="fas fa-check"></i> A/B testing de creatividades</li>
</ul>
</div>
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-calendar-check"></i> Gestión y Moderación</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Moderación activa de comunidad</li>
<li><i class="fas fa-check"></i> Gestión de consultas comerciales</li>
<li><i class="fas fa-check"></i> Respuesta en menos de 24hs</li>
</ul>
</div>
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-chart-bar"></i> Reportes y Feedback</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Reporte mensual cualitativo</li>
<li><i class="fas fa-check"></i> Reunión de alineación estratégica (30 min)</li>
<li><i class="fas fa-check"></i> Análisis de ROI y recomendaciones</li>
</ul>
</div>
</div>
<div class="panel-precio-card">
<div class="precio-header">
<span class="precio-label">Inversión mensual</span>
<div class="precio-valor">
<span class="precio-moneda">$</span>
<span class="precio-monto">650.000</span>
<span class="precio-periodo">/mes</span>
</div>
</div>
<a href="contacto.html?plan=premium" class="btn btn-primary btn-contratar">Contratar este plan</a>
</div>
</div>
<!-- Panel: Plan Élite -->
<div class="plan-panel" id="panel-elite" role="tabpanel" data-plan="elite">
<div class="panel-header">
<span class="panel-categoria">Para empresas medianas consolidadas</span>
<h2 class="panel-titulo">Plan Élite</h2>
<p class="panel-subtitulo">Liderazgo de mercado, dirección de arte exclusiva y embudo publicitario avanzado multicanal.</p>
</div>
<div class="panel-grid-dimensiones">
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-images"></i> Generación de Contenido</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> 12 piezas gráficas/carruseles premium</li>
<li><i class="fas fa-check"></i> 12 Reels/TikToks de alta producción</li>
<li><i class="fas fa-check"></i> Cobertura diaria integral de historias</li>
</ul>
</div>
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-pen-fancy"></i> Copywriting & Arte</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Dirección creativa y de arte exclusiva</li>
<li><i class="fas fa-check"></i> Guiones con ganchos de alta retención</li>
<li><i class="fas fa-check"></i> Producción audiovisual profesional</li>
</ul>
</div>
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-robot"></i> Automatizaciones</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Automatizaciones avanzadas multi-paso</li>
<li><i class="fas fa-check"></i> Etiquetado de leads</li>
<li><i class="fas fa-check"></i> Seguimiento CRM integrado</li>
</ul>
</div>
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-bullhorn"></i> Paid Media (Ads)</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Gestión integral de embudo completo</li>
<li><i class="fas fa-check"></i> Awareness, Retargeting, Conversión</li>
<li><i class="fas fa-check"></i> Meta Ads + Google Ads + TikTok Ads</li>
</ul>
</div>
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-calendar-check"></i> Gestión y Moderación</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Protocolo prioritario de atención</li>
<li><i class="fas fa-check"></i> Gestión de reputación de marca</li>
<li><i class="fas fa-check"></i> Respuesta en menos de 4hs</li>
</ul>
</div>
<div class="dimension-card">
<h3 class="dimension-titulo"><i class="fas fa-chart-bar"></i> Reportes y Feedback</h3>
<ul class="dimension-lista">
<li><i class="fas fa-check"></i> Dashboard en tiempo real</li>
<li><i class="fas fa-check"></i> Reunión mensual ejecutiva</li>
<li><i class="fas fa-check"></i> Insights de ROI y KPIs avanzados</li>
</ul>
</div>
</div>
<div class="panel-precio-card">
<div class="precio-header">
<span class="precio-label">Inversión mensual</span>
<div class="precio-valor">
<span class="precio-moneda">$</span>
<span class="precio-monto">1.000.000</span>
<span class="precio-periodo">/mes</span>
</div>
</div>
<a href="contacto.html?plan=elite" class="btn btn-primary btn-contratar">Contratar este plan</a>
</div>
</div>
</div>
</section>
<!-- Sección 4: Tabla Comparativa -->
<section id="planes-comparativa" class="planes-comparativa-section">
<div class="comparativa-container">
<div class="comparativa-header">
<h2 class="comparativa-titulo">Compará los planes</h2>
<p class="comparativa-subtitulo">Encontrá el plan perfecto para tu negocio</p>
</div>
<div class="comparativa-table-wrapper">
<table class="comparativa-table">
<thead>
<tr>
<th class="col-caracteristica">Característica</th>
<th class="col-plan">Esencial</th>
<th class="col-plan">Impulso</th>
<th class="col-plan">Premium</th>
<th class="col-plan">Élite</th>
</tr>
</thead>
<tbody>
<tr>
<td class="caracteristica-nombre">Piezas gráficas/mes</td>
<td>8</td>
<td>8</td>
<td>10</td>
<td>12</td>
</tr>
<tr>
<td class="caracteristica-nombre">Reels/TikToks</td>
<td><i class="fas fa-times"></i></td>
<td>4</td>
<td>8</td>
<td>12</td>
</tr>
<tr>
<td class="caracteristica-nombre">Historias/semana</td>
<td>4</td>
<td>6</td>
<td>Daily</td>
<td>Daily+</td>
</tr>
<tr>
<td class="caracteristica-nombre">Copywriting</td>
<td>Básico</td>
<td>Persuasivo</td>
<td>Storytelling</td>
<td>Exclusivo</td>
</tr>
<tr>
<td class="caracteristica-nombre">Automatizaciones</td>
<td><i class="fas fa-minus"></i></td>
<td>Básicas</td>
<td>Cualificación</td>
<td>Avanzadas</td>
</tr>
<tr>
<td class="caracteristica-nombre">Paid Media (Ads)</td>
<td><i class="fas fa-times"></i></td>
<td>1 campaña</td>
<td><i class="fas fa-check"></i></td>
<td>Multicanal</td>
</tr>
<tr>
<td class="caracteristica-nombre">Moderación</td>
<td><i class="fas fa-times"></i></td>
<td>Comentarios</td>
<td>Activa</td>
<td>Prioritaria</td>
</tr>
<tr>
<td class="caracteristica-nombre">Reportes</td>
<td>Automático</td>
<td>Básico</td>
<td>Cualitativo</td>
<td>Dashboard</td>
</tr>
<tr>
<td class="caracteristica-nombre">Reuniones</td>
<td><i class="fas fa-times"></i></td>
<td><i class="fas fa-times"></i></td>
<td>Mensual 30min</td>
<td>Ejecutiva</td>
</tr>
<tr class="row-precio">
<td class="caracteristica-nombre">Inversión</td>
<td class="precio-celda">$250k</td>
<td class="precio-celda">$420k</td>
<td class="precio-celda">$650k</td>
<td class="precio-celda">$1M</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
<!-- Sección 5: CTA Final -->
<section class="planes-cta">
<div class="planes-cta-card">
<h2 class="planes-cta-titulo">¿No sabés cuál plan elegir?</h2>
<p class="planes-cta-subtitle">Contanos sobre tu negocio y te recomendamos el plan ideal según tus objetivos y presupuesto.</p>
<div class="planes-cta-buttons">
<a href="contacto.html" class="btn btn-cta-primary">Asesoramiento gratuito</a>
<a href="index.html#diagnostico" class="btn btn-cta-secondary">Hacé el diagnóstico</a>
</div>
</div>
</section>
<!-- Sección 6: Espacio de cierre -->
<section class="planes-cierre"></section>
</main>
<div id="footer-container"></div>
<script src="scripts/main.js"></script>
<script src="scripts/efecto.js"></script>
<script src="scripts/planes.js"></script>
<script src="scripts/fluid.js"></script>
</body>
</html>
+252
View File
@@ -0,0 +1,252 @@
document.addEventListener('DOMContentLoaded', async () => {
const GHOST_API_URL = 'https://blog.amoryroma.com.ar';
const GHOST_API_KEY = '82450ba91ca6b5b9628006eec4';
// Elementos del DOM
const featuredSection = document.getElementById('featured-posts');
const featuredGrid = document.getElementById('featured-grid');
const blogGrid = document.getElementById('blog-grid');
const loadMoreBtn = document.getElementById('load-more');
const resultsCount = document.getElementById('results-count');
const emptyState = document.getElementById('empty-state');
const gridSectionTitle = document.getElementById('grid-section-title');
const gridSectionSubtitle = document.getElementById('grid-section-subtitle');
// Estado de los filtros
let posts = [];
let state = {
category: 'all',
filter: 'all', // 'all' o 'destacados'
search: '',
sort: 'recent'
};
// Cargar artículos desde Ghost API
async function loadPosts() {
try {
const response = await fetch(`${GHOST_API_URL}/ghost/api/content/posts/?key=${GHOST_API_KEY}&limit=all&include=tags,authors`);
const data = await response.json();
posts = data.posts.map(post => ({
id: post.id,
slug: post.slug,
titulo: post.title,
extracto: post.excerpt,
categoria: post.primary_tag ? post.primary_tag.name.toLowerCase() : 'general',
tags: post.tags ? post.tags.map(t => t.name.toLowerCase()) : [],
imagen: post.feature_image || 'assets/blog/default.jpg',
fecha: post.published_at,
tiempo_lectura: Math.ceil(post.reading_time) || 5,
destacado: post.featured
}));
renderPosts();
setupEventListeners();
} catch (error) {
console.error('Error cargando posts de Ghost:', error);
if(emptyState) {
emptyState.style.display = 'block';
emptyState.querySelector('h3').textContent = 'Error al cargar el blog';
emptyState.querySelector('p').textContent = 'Por favor, recarga la página.';
}
}
}
function formatDate(dateString) {
const options = { day: '2-digit', month: 'short', year: 'numeric' };
return new Date(dateString).toLocaleDateString('es-AR', options);
}
function createCard(post, isFeatured = false) {
const catFormatted = post.categoria.charAt(0).toUpperCase() + post.categoria.slice(1);
const cardClass = isFeatured ? 'featured-card' : 'blog-card';
const badge = isFeatured && post.destacado ? '<span class="featured-badge">Destacado</span>' : '';
const metaClass = isFeatured ? 'featured-meta' : 'card-meta';
const titleClass = isFeatured ? 'featured-title' : 'card-title';
const excerptClass = isFeatured ? 'featured-excerpt' : 'card-excerpt';
const linkClass = isFeatured ? 'btn-read' : 'card-link';
const linkText = isFeatured ? 'Leer artículo →' : 'Leer artículo';
return `
<article class="${cardClass}" data-categories="${post.categoria}" data-featured="${post.destacado}">
<div class="${isFeatured ? 'featured-image' : 'card-image'}">
<img src="${post.imagen}" alt="${post.titulo}" loading="lazy">
${!isFeatured ? `<span class="card-category ${post.categoria}">${catFormatted}</span>` : ''}
${badge}
</div>
<div class="${isFeatured ? 'featured-content' : 'card-content'}">
<div class="${metaClass}">
<span class="category-tag ${post.categoria}">${catFormatted}</span>
<time datetime="${post.fecha}">${formatDate(post.fecha)}</time>
</div>
<h3 class="${titleClass}">${post.titulo}</h3>
<p class="${excerptClass}">${post.extracto}</p>
<div class="${isFeatured ? 'featured-footer' : ''}">
${isFeatured ? `<span class="reading-time">⏱ ${post.tiempo_lectura} min</span>` : `<span class="reading-time-mini">${post.tiempo_lectura} min</span>`}
<a href="${GHOST_API_URL}/${post.slug}/" class="${linkClass}" target="_blank">${linkText}</a>
</div>
</div>
</article>
`;
}
function renderPosts() {
// 1. FILTRAR
let filtered = posts.filter(post => {
const matchCategory = state.category === 'all' || post.categoria === state.category;
const matchFilter = state.filter === 'all' || (state.filter === 'destacados' && post.destacado);
const q = state.search.toLowerCase();
const matchSearch = !q ||
post.titulo.toLowerCase().includes(q) ||
post.extracto.toLowerCase().includes(q) ||
post.tags.some(tag => tag.includes(q));
return matchCategory && matchFilter && matchSearch;
});
// 2. ORDENAR
if (state.sort === 'recent') {
filtered.sort((a, b) => new Date(b.fecha) - new Date(a.fecha));
} else if (state.sort === 'popular') {
// Como la API pública de Ghost no expone "vistas", simulamos popularidad poniendo los destacados primero
filtered.sort((a, b) => (b.destacado === a.destacado) ? 0 : b.destacado ? 1 : -1);
}
// 3. DECIDIR VISTA: ¿Es la vista por defecto (sin filtros)?
const isDefaultView = state.category === 'all' && state.filter === 'all' && state.search === '';
if (isDefaultView) {
// VISTA POR DEFECTO: Mostrar Destacados + Últimos 3
if (featuredSection) featuredSection.style.display = 'block';
if (gridSectionTitle) gridSectionTitle.textContent = 'Últimos artículos';
if (gridSectionSubtitle) gridSectionSubtitle.textContent = 'Lo más nuevo y a la vanguardia.';
if (loadMoreBtn) {
loadMoreBtn.style.display = 'inline-block';
loadMoreBtn.textContent = 'Ver todos los artículos en el Blog';
loadMoreBtn.onclick = () => window.location.href = `${GHOST_API_URL}/`;
}
const featuredPosts = filtered.filter(p => p.destacado).slice(0, 3);
const latestPosts = filtered.slice(0, 3);
if (featuredGrid) featuredGrid.innerHTML = featuredPosts.map(p => createCard(p, true)).join('');
if (blogGrid) blogGrid.innerHTML = latestPosts.map(p => createCard(p, false)).join('');
if (resultsCount) resultsCount.innerHTML = `Mostrando los <strong>últimos 3</strong> artículos`;
if (emptyState) emptyState.style.display = 'none';
} else {
// VISTA FILTRADA: Ocultar Destacados, mostrar TODOS los resultados en la grilla principal
if (featuredSection) featuredSection.style.display = 'none';
if (loadMoreBtn) loadMoreBtn.style.display = 'none'; // Ocultamos "cargar más" porque ya mostramos todos los filtrados
// Actualizar títulos según el filtro
if (gridSectionTitle) {
if (state.search) gridSectionTitle.textContent = `Resultados de búsqueda`;
else if (state.category !== 'all') gridSectionTitle.textContent = `Artículos de ${state.category.charAt(0).toUpperCase() + state.category.slice(1)}`;
else if (state.filter === 'destacados') gridSectionTitle.textContent = `Artículos Destacados`;
}
if (gridSectionSubtitle) gridSectionSubtitle.textContent = `Se encontraron ${filtered.length} artículo${filtered.length !== 1 ? 's' : ''}`;
if (blogGrid) {
if (filtered.length === 0) {
blogGrid.innerHTML = '';
if (emptyState) {
emptyState.style.display = 'block';
emptyState.querySelector('h3').textContent = 'No encontramos artículos con esos filtros';
}
} else {
if (emptyState) emptyState.style.display = 'none';
// Mostramos TODOS los artículos que coinciden con el filtro, no solo 3
blogGrid.innerHTML = filtered.map(p => createCard(p, false)).join('');
}
}
if (resultsCount) {
resultsCount.innerHTML = `Mostrando <strong>${filtered.length}</strong> artículo${filtered.length !== 1 ? 's' : ''}`;
}
}
}
function setupEventListeners() {
// 1. Botones de Categoría
document.querySelectorAll('.category-btn').forEach(btn => {
btn.addEventListener('click', (e) => {
document.querySelectorAll('.category-btn').forEach(b => b.classList.remove('active'));
e.target.classList.add('active');
state.category = e.target.dataset.category;
renderPosts();
});
});
// 2. Botones de Filtro (Todos / Destacados)
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.addEventListener('click', (e) => {
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
e.target.classList.add('active');
state.filter = e.target.dataset.filter;
renderPosts();
});
});
// 3. Buscador
const searchInput = document.getElementById('blog-search');
const searchClear = document.getElementById('search-clear');
if (searchInput) {
searchInput.addEventListener('input', (e) => {
state.search = e.target.value;
if (searchClear) searchClear.classList.toggle('visible', state.search.length > 0);
renderPosts();
});
}
if (searchClear) {
searchClear.addEventListener('click', () => {
if (searchInput) {
searchInput.value = '';
state.search = '';
searchClear.classList.remove('visible');
searchInput.focus();
renderPosts();
}
});
}
// 4. Ordenamiento
const sortSelect = document.getElementById('sort-select');
if (sortSelect) {
sortSelect.addEventListener('change', (e) => {
state.sort = e.target.value;
renderPosts();
});
}
// 5. Botón Limpiar Filtros
const resetBtn = document.getElementById('reset-filters');
const emptyReset = document.getElementById('empty-reset');
function resetAll() {
state = { category: 'all', filter: 'all', search: '', sort: 'recent' };
// Resetear UI
document.querySelectorAll('.category-btn').forEach(b => b.classList.remove('active'));
document.querySelector('.category-btn[data-category="all"]').classList.add('active');
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
document.querySelector('.filter-btn[data-filter="all"]').classList.add('active');
if (searchInput) searchInput.value = '';
if (searchClear) searchClear.classList.remove('visible');
if (sortSelect) sortSelect.value = 'recent';
renderPosts();
}
if (resetBtn) resetBtn.addEventListener('click', resetAll);
if (emptyReset) emptyReset.addEventListener('click', resetAll);
}
// Iniciar
await loadPosts();
});
+105
View File
@@ -0,0 +1,105 @@
/**
* Envío de formulario de contacto con Formspree + modal de éxito.
*/
(function () {
'use strict';
const form = document.getElementById('form-contacto');
const modal = document.getElementById('modal-contacto');
const btnCerrar = modal ? modal.querySelector('.modal-cerrar') : null;
const btnEnviar = form ? form.querySelector('button[type="submit"]') : null;
if (!form || !modal) return;
const FORMSPREE_URL = 'https://formspree.io/f/xkjgjzpn';
let redirectTimer = null;
// ── Helpers ───────────────────────────────────────────────────────
function abrirModal(mensaje) {
const texto = modal.querySelector('.modal-mensaje');
if (texto && mensaje) texto.textContent = mensaje;
modal.classList.add('is-visible');
modal.setAttribute('aria-hidden', 'false');
document.body.style.overflow = 'hidden';
}
function cerrarModal(redirigir = false) {
modal.classList.remove('is-visible');
modal.setAttribute('aria-hidden', 'true');
document.body.style.overflow = '';
if (redirectTimer) clearTimeout(redirectTimer);
if (redirigir) window.location.href = 'index.html';
}
function mostrarError(mensaje) {
modal.classList.add('is-error');
abrirModal(mensaje);
}
// ── Cerrar modal ───────────────────────────────────────────────────
if (btnCerrar) {
btnCerrar.addEventListener('click', () => cerrarModal(true));
}
modal.addEventListener('click', (e) => {
if (e.target === modal) cerrarModal(true);
});
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && modal.classList.contains('is-visible')) {
cerrarModal(true);
}
});
// ── Submit ─────────────────────────────────────────────────────────
form.addEventListener('submit', async (e) => {
e.preventDefault();
// Validación nativa HTML5
if (!form.checkValidity()) {
form.reportValidity();
return;
}
// Estado de carga
const textoOriginal = btnEnviar ? btnEnviar.innerHTML : '';
if (btnEnviar) {
btnEnviar.disabled = true;
btnEnviar.innerHTML = 'Enviando…';
}
try {
const data = new FormData(form);
const res = await fetch(FORMSPREE_URL, {
method: 'POST',
body: data,
headers: {
'Accept': 'application/json'
}
});
if (res.ok) {
modal.classList.remove('is-error');
abrirModal('¡Mensaje enviado! Te contactaremos en menos de 48 horas hábiles.');
form.reset();
// Redirección automática después de 4 segundos
redirectTimer = setTimeout(() => {
window.location.href = 'index.html';
}, 4000);
} else {
const json = await res.json().catch(() => ({}));
mostrarError(json.error || 'No pudimos enviar tu mensaje. Intentá nuevamente.');
}
} catch (err) {
mostrarError('Hubo un problema de conexión. Probá nuevamente.');
} finally {
if (btnEnviar) {
btnEnviar.disabled = false;
btnEnviar.innerHTML = textoOriginal;
}
}
});
})();
+199 -247
View File
@@ -1,6 +1,6 @@
"use strict";
// ===== CONFIGURACIÓN DEL EFECTO =====
// ===== CONFIGURACIÓN DEL EFECTO (Parámetros calibrados de fluid - copia.js) =====
const config = {
TEXTURE_DOWNSAMPLE: 1,
DENSITY_DISSIPATION: 0.975,
@@ -11,22 +11,62 @@ const config = {
SPLAT_RADIUS: 0.003
};
// ===== COLORES DE MARCA SEGÚN EL TEMA =====
function getBrandColors() {
const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
if (isDark) {
return [
[0.850, 0.080, 0.380], // Carmesí / Fucsia vivo de marca
[0.050, 0.450, 0.550], // Teal profundo
[0.650, 0.200, 0.450] // Plum medio
];
} else {
return [
[0.729, 0.071, 0.302], // Bordo de marca (#BA124D)
[0.000, 0.247, 0.322], // Teal de marca (#003F52)
[0.550, 0.150, 0.280] // Plum suave
];
}
}
let brandColors = getBrandColors();
let currentColor = brandColors[0];
let targetColor = brandColors[1];
let transitionProgress = 0;
const transitionSpeed = 0.008;
// Observador para detectar cambios en data-theme
const themeObserver = new MutationObserver(() => {
brandColors = getBrandColors();
currentColor = brandColors[0];
targetColor = brandColors[1];
transitionProgress = 0;
});
themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] });
function lerpColor(colorA, colorB, t) {
return [
colorA[0] + (colorB[0] - colorA[0]) * t,
colorA[1] + (colorB[1] - colorA[1]) * t,
colorA[2] + (colorB[2] - colorA[2]) * t
];
}
// ===== INICIALIZAR CANVAS =====
let canvas = document.getElementById("fluidCanvas");
console.log("Canvas encontrado:", canvas);
if (!canvas) {
console.error("ERROR: No se encontró el canvas con id 'fluidCanvas'");
}
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// ===== CONTEXTO WEBGL =====
// ===== CONTEXTO WEBGL TRANSPARENTE =====
let pointers = [];
let splatStack = [];
function getWebGLContext(canvas) {
let params = {
alpha: false,
alpha: true, // Transparente para respetar el fondo CSS
premultipliedAlpha: false, // Clave para evitar bordes oscuros o quemados
depth: false,
stencil: false,
antialias: false
@@ -34,20 +74,22 @@ function getWebGLContext(canvas) {
let gl = canvas.getContext("webgl2", params);
let isWebGL2 = !!gl;
if (!isWebGL2)
gl =
canvas.getContext("webgl", params) ||
canvas.getContext("experimental-webgl", params);
gl = canvas.getContext("webgl", params) || canvas.getContext("experimental-webgl", params);
let halfFloat = gl.getExtension("OES_texture_half_float");
let support_linear_float = gl.getExtension("OES_texture_half_float_linear");
if (isWebGL2) {
gl.getExtension("EXT_color_buffer_float");
support_linear_float = gl.getExtension("OES_texture_float_linear");
}
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clearColor(0.0, 0.0, 0.0, 0.0);
let internalFormat = isWebGL2 ? gl.RGBA16F : gl.RGBA;
let internalFormatRG = isWebGL2 ? gl.RG16F : gl.RGBA;
let formatRG = isWebGL2 ? gl.RG : gl.RGBA;
let texType = isWebGL2 ? gl.HALF_FLOAT : halfFloat.HALF_FLOAT_OES;
return {
gl: gl,
ext: {
@@ -74,29 +116,24 @@ function pointerPrototype() {
this.dy = 0;
this.down = false;
this.moved = false;
this.color = [30, 0, 300];
this.color = [0.729, 0.071, 0.302];
}
pointers.push(new pointerPrototype());
// ===== SHADERS =====
let GLProgram = (function () {
function GLProgram(vertexShader, fragmentShader) {
if (!(this instanceof GLProgram))
throw new TypeError("Cannot call a class as a function");
if (!(this instanceof GLProgram)) throw new TypeError("Cannot call a class as a function");
this.uniforms = {};
this.program = gl.createProgram();
gl.attachShader(this.program, vertexShader);
gl.attachShader(this.program, fragmentShader);
gl.linkProgram(this.program);
if (!gl.getProgramParameter(this.program, gl.LINK_STATUS))
throw gl.getProgramInfoLog(this.program);
if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) throw gl.getProgramInfoLog(this.program);
let uniformCount = gl.getProgramParameter(this.program, gl.ACTIVE_UNIFORMS);
for (let i = 0; i < uniformCount; i++) {
let uniformName = gl.getActiveUniform(this.program, i).name;
this.uniforms[uniformName] = gl.getUniformLocation(
this.program,
uniformName
);
this.uniforms[uniformName] = gl.getUniformLocation(this.program, uniformName);
}
}
GLProgram.prototype.bind = function bind() {
@@ -109,66 +146,92 @@ function compileShader(type, source) {
let shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
throw gl.getShaderInfoLog(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) throw gl.getShaderInfoLog(shader);
return shader;
}
// ===== VERTEX SHADER =====
let baseVertexShader = compileShader(
gl.VERTEX_SHADER,
"precision highp float; precision mediump sampler2D; attribute vec2 aPosition; varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB; uniform vec2 texelSize; void main () { vUv = aPosition * 0.5 + 0.5; vL = vUv - vec2(texelSize.x, 0.0); vR = vUv + vec2(texelSize.x, 0.0); vT = vUv + vec2(0.0, texelSize.y); vB = vUv - vec2(0.0, texelSize.y); gl_Position = vec4(aPosition, 0.0, 1.0); }"
"precision highp float; precision mediump sampler2D; attribute vec2 aPosition; varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB; uniform vec2 texelSize; void main () { vUv = aPosition * 0.5 + 0.5; vL = vUv - vec2(texelSize.x, 0.0); vR = vUv + vec2(texelSize.x, 0.0); vT = vUv + vec2(0.0, texelSize.y); vB = vUv - vec2(0.0, texelSize.y); gl_Position = vec4(aPosition, 0.0, 1.0); }"
);
// ===== FRAGMENT SHADERS =====
let clearShader = compileShader(
gl.FRAGMENT_SHADER,
"precision highp float; precision mediump sampler2D; varying vec2 vUv; uniform sampler2D uTexture; uniform float value; void main () { gl_FragColor = value * texture2D(uTexture, vUv); }"
"precision highp float; precision mediump sampler2D; varying vec2 vUv; uniform sampler2D uTexture; uniform float value; void main () { gl_FragColor = value * texture2D(uTexture, vUv); }"
);
// SHADER DE VISUALIZACIÓN: compatible con GLSL ES 1.0 y libre de blanqueo
let displayShader = compileShader(
gl.FRAGMENT_SHADER,
"precision highp float; precision mediump sampler2D; varying vec2 vUv; uniform sampler2D uTexture; void main () { gl_FragColor = texture2D(uTexture, vUv); }"
`precision highp float;
precision mediump sampler2D;
varying vec2 vUv;
uniform sampler2D uTexture;
uniform float uIsDark;
void main () {
vec4 c = texture2D(uTexture, vUv);
float len = length(c.rgb);
// Sintaxis 100% compatible con WebGL 1 y 2 (4 componentes)
if (len < 0.001) {
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
return;
}
// Normalización cromática: conserva el matiz puro de la marca y previene el blanco
vec3 pureColor = c.rgb / len;
if (uIsDark > 0.5) {
// MODO OSCURO: color rico con presencia viva sin deslumbrar
float alpha = clamp(len * 1.8, 0.0, 0.80);
gl_FragColor = vec4(pureColor, alpha);
} else {
// MODO CLARO: tinte traslúcido tipo acuarela
float alpha = clamp(len * 1.2, 0.0, 0.38);
gl_FragColor = vec4(pureColor, alpha);
}
}`
);
let splatShader = compileShader(
gl.FRAGMENT_SHADER,
"precision highp float; precision mediump sampler2D; varying vec2 vUv; uniform sampler2D uTarget; uniform float aspectRatio; uniform vec3 color; uniform vec2 point; uniform float radius; void main () { vec2 p = vUv - point.xy; p.x *= aspectRatio; vec3 splat = exp(-dot(p, p) / radius) * color; vec3 base = texture2D(uTarget, vUv).xyz; gl_FragColor = vec4(base + splat, 1.0); }"
"precision highp float; precision mediump sampler2D; varying vec2 vUv; uniform sampler2D uTarget; uniform float aspectRatio; uniform vec3 color; uniform vec2 point; uniform float radius; void main () { vec2 p = vUv - point.xy; p.x *= aspectRatio; vec3 splat = exp(-dot(p, p) / radius) * color; vec3 base = texture2D(uTarget, vUv).xyz; gl_FragColor = vec4(base + splat, 1.0); }"
);
let advectionManualFilteringShader = compileShader(
gl.FRAGMENT_SHADER,
"precision highp float; precision mediump sampler2D; varying vec2 vUv; uniform sampler2D uVelocity; uniform sampler2D uSource; uniform vec2 texelSize; uniform float dt; uniform float dissipation; vec4 bilerp (in sampler2D sam, in vec2 p) { vec4 st; st.xy = floor(p - 0.5) + 0.5; st.zw = st.xy + 1.0; vec4 uv = st * texelSize.xyxy; vec4 a = texture2D(sam, uv.xy); vec4 b = texture2D(sam, uv.zy); vec4 c = texture2D(sam, uv.xw); vec4 d = texture2D(sam, uv.zw); vec2 f = p - st.xy; return mix(mix(a, b, f.x), mix(c, d, f.x), f.y); } void main () { vec2 coord = gl_FragCoord.xy - dt * texture2D(uVelocity, vUv).xy; gl_FragColor = dissipation * bilerp(uSource, coord); gl_FragColor.a = 1.0; }"
"precision highp float; precision mediump sampler2D; varying vec2 vUv; uniform sampler2D uVelocity; uniform sampler2D uSource; uniform vec2 texelSize; uniform float dt; uniform float dissipation; vec4 bilerp (in sampler2D sam, in vec2 p) { vec4 st; st.xy = floor(p - 0.5) + 0.5; st.zw = st.xy + 1.0; vec4 uv = st * texelSize.xyxy; vec4 a = texture2D(sam, uv.xy); vec4 b = texture2D(sam, uv.zy); vec4 c = texture2D(sam, uv.xw); vec4 d = texture2D(sam, uv.zw); vec2 f = p - st.xy; return mix(mix(a, b, f.x), mix(c, d, f.x), f.y); } void main () { vec2 coord = gl_FragCoord.xy - dt * texture2D(uVelocity, vUv).xy; gl_FragColor = dissipation * bilerp(uSource, coord); gl_FragColor.a = 1.0; }"
);
let advectionShader = compileShader(
gl.FRAGMENT_SHADER,
"precision highp float; precision mediump sampler2D; varying vec2 vUv; uniform sampler2D uVelocity; uniform sampler2D uSource; uniform vec2 texelSize; uniform float dt; uniform float dissipation; void main () { vec2 coord = vUv - dt * texture2D(uVelocity, vUv).xy * texelSize; gl_FragColor = dissipation * texture2D(uSource, coord); }"
"precision highp float; precision mediump sampler2D; varying vec2 vUv; uniform sampler2D uVelocity; uniform sampler2D uSource; uniform vec2 texelSize; uniform float dt; uniform float dissipation; void main () { vec2 coord = vUv - dt * texture2D(uVelocity, vUv).xy * texelSize; gl_FragColor = dissipation * texture2D(uSource, coord); }"
);
let divergenceShader = compileShader(
gl.FRAGMENT_SHADER,
"precision highp float; precision mediump sampler2D; varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB; uniform sampler2D uVelocity; vec2 sampleVelocity (in vec2 uv) { vec2 multiplier = vec2(1.0, 1.0); if (uv.x < 0.0) { uv.x = 0.0; multiplier.x = -1.0; } if (uv.x > 1.0) { uv.x = 1.0; multiplier.x = -1.0; } if (uv.y < 0.0) { uv.y = 0.0; multiplier.y = -1.0; } if (uv.y > 1.0) { uv.y = 1.0; multiplier.y = -1.0; } return multiplier * texture2D(uVelocity, uv).xy; } void main () { float L = sampleVelocity(vL).x; float R = sampleVelocity(vR).x; float T = sampleVelocity(vT).y; float B = sampleVelocity(vB).y; float div = 0.5 * (R - L + T - B); gl_FragColor = vec4(div, 0.0, 0.0, 1.0); }"
"precision highp float; precision mediump sampler2D; varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB; uniform sampler2D uVelocity; vec2 sampleVelocity (in vec2 uv) { vec2 multiplier = vec2(1.0, 1.0); if (uv.x < 0.0) { uv.x = 0.0; multiplier.x = -1.0; } if (uv.x > 1.0) { uv.x = 1.0; multiplier.x = -1.0; } if (uv.y < 0.0) { uv.y = 0.0; multiplier.y = -1.0; } if (uv.y > 1.0) { uv.y = 1.0; multiplier.y = -1.0; } return multiplier * texture2D(uVelocity, uv).xy; } void main () { float L = sampleVelocity(vL).x; float R = sampleVelocity(vR).x; float T = sampleVelocity(vT).y; float B = sampleVelocity(vB).y; float div = 0.5 * (R - L + T - B); gl_FragColor = vec4(div, 0.0, 0.0, 1.0); }"
);
let curlShader = compileShader(
gl.FRAGMENT_SHADER,
"precision highp float; precision mediump sampler2D; varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB; uniform sampler2D uVelocity; void main () { float L = texture2D(uVelocity, vL).y; float R = texture2D(uVelocity, vR).y; float T = texture2D(uVelocity, vT).x; float B = texture2D(uVelocity, vB).x; float vorticity = R - L - T + B; gl_FragColor = vec4(vorticity, 0.0, 0.0, 1.0); }"
"precision highp float; precision mediump sampler2D; varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB; uniform sampler2D uVelocity; void main () { float L = texture2D(uVelocity, vL).y; float R = texture2D(uVelocity, vR).y; float T = texture2D(uVelocity, vT).x; float B = texture2D(uVelocity, vB).x; float vorticity = R - L - T + B; gl_FragColor = vec4(vorticity, 0.0, 0.0, 1.0); }"
);
let vorticityShader = compileShader(
gl.FRAGMENT_SHADER,
"precision highp float; precision mediump sampler2D; varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB; uniform sampler2D uVelocity; uniform sampler2D uCurl; uniform float curl; uniform float dt; void main () { float L = texture2D(uCurl, vL).y; float R = texture2D(uCurl, vR).y; float T = texture2D(uCurl, vT).x; float B = texture2D(uCurl, vB).x; float C = texture2D(uCurl, vUv).x; vec2 force = vec2(abs(T) - abs(B), abs(R) - abs(L)); force *= 1.0 / length(force + 0.00001) * curl * C; vec2 vel = texture2D(uVelocity, vUv).xy; gl_FragColor = vec4(vel + force * dt, 0.0, 1.0); }"
"precision highp float; precision mediump sampler2D; varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB; uniform sampler2D uVelocity; uniform sampler2D uCurl; uniform float curl; uniform float dt; void main () { float L = texture2D(uCurl, vL).y; float R = texture2D(uCurl, vR).y; float T = texture2D(uCurl, vT).x; float B = texture2D(uCurl, vB).x; float C = texture2D(uCurl, vUv).x; vec2 force = vec2(abs(T) - abs(B), abs(R) - abs(L)); force *= 1.0 / length(force + 0.00001) * curl * C; vec2 vel = texture2D(uVelocity, vUv).xy; gl_FragColor = vec4(vel + force * dt, 0.0, 1.0); }"
);
let pressureShader = compileShader(
gl.FRAGMENT_SHADER,
"precision highp float; precision mediump sampler2D; varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB; uniform sampler2D uPressure; uniform sampler2D uDivergence; vec2 boundary (in vec2 uv) { uv = min(max(uv, 0.0), 1.0); return uv; } void main () { float L = texture2D(uPressure, boundary(vL)).x; float R = texture2D(uPressure, boundary(vR)).x; float T = texture2D(uPressure, boundary(vT)).x; float B = texture2D(uPressure, boundary(vB)).x; float C = texture2D(uPressure, vUv).x; float divergence = texture2D(uDivergence, vUv).x; float pressure = (L + R + B + T - divergence) * 0.25; gl_FragColor = vec4(pressure, 0.0, 0.0, 1.0); }"
"precision highp float; precision mediump sampler2D; varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB; uniform sampler2D uPressure; uniform sampler2D uDivergence; vec2 boundary (in vec2 uv) { uv = min(max(uv, 0.0), 1.0); return uv; } void main () { float L = texture2D(uPressure, boundary(vL)).x; float R = texture2D(uPressure, boundary(vR)).x; float T = texture2D(uPressure, boundary(vT)).x; float B = texture2D(uPressure, boundary(vB)).x; float C = texture2D(uPressure, vUv).x; float divergence = texture2D(uDivergence, vUv).x; float pressure = (L + R + B + T - divergence) * 0.25; gl_FragColor = vec4(pressure, 0.0, 0.0, 1.0); }"
);
let gradientSubtractShader = compileShader(
gl.FRAGMENT_SHADER,
"precision highp float; precision mediump sampler2D; varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB; uniform sampler2D uPressure; uniform sampler2D uVelocity; vec2 boundary (in vec2 uv) { uv = min(max(uv, 0.0), 1.0); return uv; } void main () { float L = texture2D(uPressure, boundary(vL)).x; float R = texture2D(uPressure, boundary(vR)).x; float T = texture2D(uPressure, boundary(vT)).x; float B = texture2D(uPressure, boundary(vB)).x; vec2 velocity = texture2D(uVelocity, vUv).xy; velocity.xy -= vec2(R - L, T - B); gl_FragColor = vec4(velocity, 0.0, 1.0); }"
"precision highp float; precision mediump sampler2D; varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB; uniform sampler2D uPressure; uniform sampler2D uVelocity; vec2 boundary (in vec2 uv) { uv = min(max(uv, 0.0), 1.0); return uv; } void main () { float L = texture2D(uPressure, boundary(vL)).x; float R = texture2D(uPressure, boundary(vR)).x; float T = texture2D(uPressure, boundary(vT)).x; float B = texture2D(uPressure, boundary(vB)).x; vec2 velocity = texture2D(uVelocity, vUv).xy; velocity.xy -= vec2(R - L, T - B); gl_FragColor = vec4(velocity, 0.0, 1.0); }"
);
// ===== FRAMEBUFFERS =====
@@ -182,51 +245,11 @@ function initFramebuffers() {
let iFormatRG = ext.internalFormatRG;
let formatRG = ext.formatRG;
let texType = ext.texType;
density = createDoubleFBO(
0,
textureWidth,
textureHeight,
iFormat,
gl.RGBA,
texType,
support_linear_float ? gl.LINEAR : gl.NEAREST
);
velocity = createDoubleFBO(
2,
textureWidth,
textureHeight,
iFormatRG,
formatRG,
texType,
support_linear_float ? gl.LINEAR : gl.NEAREST
);
divergence = createFBO(
4,
textureWidth,
textureHeight,
iFormatRG,
formatRG,
texType,
gl.NEAREST
);
curl = createFBO(
5,
textureWidth,
textureHeight,
iFormatRG,
formatRG,
texType,
gl.NEAREST
);
pressure = createDoubleFBO(
6,
textureWidth,
textureHeight,
iFormatRG,
formatRG,
texType,
gl.NEAREST
);
density = createDoubleFBO(0, textureWidth, textureHeight, iFormat, gl.RGBA, texType, support_linear_float ? gl.LINEAR : gl.NEAREST);
velocity = createDoubleFBO(2, textureWidth, textureHeight, iFormatRG, formatRG, texType, support_linear_float ? gl.LINEAR : gl.NEAREST);
divergence = createFBO(4, textureWidth, textureHeight, iFormatRG, formatRG, texType, gl.NEAREST);
curl = createFBO(5, textureWidth, textureHeight, iFormatRG, formatRG, texType, gl.NEAREST);
pressure = createDoubleFBO(6, textureWidth, textureHeight, iFormatRG, formatRG, texType, gl.NEAREST);
}
function createFBO(texId, w, h, internalFormat, format, type, param) {
@@ -240,13 +263,7 @@ function createFBO(texId, w, h, internalFormat, format, type, param) {
gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, w, h, 0, format, type, null);
let fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(
gl.FRAMEBUFFER,
gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D,
texture,
0
);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
gl.viewport(0, 0, w, h);
gl.clear(gl.COLOR_BUFFER_BIT);
return [texture, fbo, texId];
@@ -256,17 +273,9 @@ function createDoubleFBO(texId, w, h, internalFormat, format, type, param) {
let fbo1 = createFBO(texId, w, h, internalFormat, format, type, param);
let fbo2 = createFBO(texId + 1, w, h, internalFormat, format, type, param);
return {
get first() {
return fbo1;
},
get second() {
return fbo2;
},
swap: function swap() {
let temp = fbo1;
fbo1 = fbo2;
fbo2 = temp;
}
get first() { return fbo1; },
get second() { return fbo2; },
swap: function swap() { let temp = fbo1; fbo1 = fbo2; fbo2 = temp; }
};
}
@@ -276,33 +285,19 @@ initFramebuffers();
let clearProgram = new GLProgram(baseVertexShader, clearShader);
let displayProgram = new GLProgram(baseVertexShader, displayShader);
let splatProgram = new GLProgram(baseVertexShader, splatShader);
let advectionProgram = new GLProgram(
baseVertexShader,
support_linear_float ? advectionShader : advectionManualFilteringShader
);
let advectionProgram = new GLProgram(baseVertexShader, support_linear_float ? advectionShader : advectionManualFilteringShader);
let divergenceProgram = new GLProgram(baseVertexShader, divergenceShader);
let curlProgram = new GLProgram(baseVertexShader, curlShader);
let vorticityProgram = new GLProgram(baseVertexShader, vorticityShader);
let pressureProgram = new GLProgram(baseVertexShader, pressureShader);
let gradienSubtractProgram = new GLProgram(
baseVertexShader,
gradientSubtractShader
);
let gradienSubtractProgram = new GLProgram(baseVertexShader, gradientSubtractShader);
// ===== BLIT =====
let blit = (function () {
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([-1, -1, -1, 1, 1, 1, 1, -1]),
gl.STATIC_DRAW
);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, -1, 1, 1, 1, 1, -1]), gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(
gl.ELEMENT_ARRAY_BUFFER,
new Uint16Array([0, 1, 2, 0, 2, 3]),
gl.STATIC_DRAW
);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([0, 1, 2, 0, 2, 3]), gl.STATIC_DRAW);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(0);
return function (destination) {
@@ -316,53 +311,26 @@ function splat(x, y, dx, dy, color) {
splatProgram.bind();
gl.uniform1i(splatProgram.uniforms.uTarget, velocity.first[2]);
gl.uniform1f(splatProgram.uniforms.aspectRatio, canvas.width / canvas.height);
gl.uniform2f(
splatProgram.uniforms.point,
x / canvas.width,
1.0 - y / canvas.height
);
gl.uniform2f(splatProgram.uniforms.point, x / canvas.width, 1.0 - y / canvas.height);
gl.uniform3f(splatProgram.uniforms.color, dx, -dy, 1.0);
gl.uniform1f(splatProgram.uniforms.radius, config.SPLAT_RADIUS);
blit(velocity.second[1]);
velocity.swap();
gl.uniform1i(splatProgram.uniforms.uTarget, density.first[2]);
gl.uniform3f(
splatProgram.uniforms.color,
color[0] * 0.3,
color[1] * 0.3,
color[2] * 0.3
);
// Inyección equilibrada
gl.uniform3f(splatProgram.uniforms.color, color[0] * 0.28, color[1] * 0.28, color[2] * 0.28);
blit(density.second[1]);
density.swap();
}
// ===== RESIZE =====
function resizeCanvas() {
(canvas.width !== canvas.clientWidth ||
canvas.height !== canvas.clientHeight) &&
((canvas.width = canvas.clientWidth),
(canvas.height = canvas.clientHeight),
initFramebuffers());
}
// ===== COLORES DE LA MARCA CON TRANSICIÓN =====
const brandColors = [
//[0.874, 0.741, 0.725], // Rosa (#DFBDB9)
[0.729, 0.071, 0.302], // Bordo (#BA124D)
[0.000, 0.247, 0.322] // Teal (#003F52)
];
let currentColor = brandColors[0];
let targetColor = brandColors[1];
let transitionProgress = 0;
const transitionSpeed = 0.008;
function lerpColor(colorA, colorB, t) {
return [
colorA[0] + (colorB[0] - colorA[0]) * t,
colorA[1] + (colorB[1] - colorA[1]) * t,
colorA[2] + (colorB[2] - colorA[2]) * t
];
if (canvas.width !== canvas.clientWidth || canvas.height !== canvas.clientHeight) {
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
initFramebuffers();
}
}
let colorArr = currentColor;
@@ -370,27 +338,33 @@ let count = 0;
// ===== DETECTAR ELEMENTOS DE TEXTO =====
function isMouseOverTextElement(target) {
// Listado de selectores que necesitan "modo apaciguado"
const textSelectors = [
'p', '.hero-content p','h1', 'h2', 'h3', 'h4', 'h5', '.hero-content h1',
'.hero-content h2', '.eyebrow', 'a.sheet-link', '.sheet-link span',
'.menu-btn', '.sheet-link-desc', '.sheet-link-main'
'p', '.hero-content p', 'h1', 'h2', 'h3', 'h4', 'h5', '.hero-content h1',
'.hero-content h2', '.eyebrow', 'a', 'button', '.btn', '.servicio-item', '.plan-card'
];
// Verificar si el target o sus ancestros coinciden con algún selector
for (const selector of textSelectors) {
if (target.closest(selector)) {
return true;
}
if (target.closest(selector)) return true;
}
return false;
}
// ===== EVENTOS CON COLORES DE MARCA =====
// ===== CAPTURA DE MOUSE SIMÉTRICA Y CENTRADA =====
let isFirstMove = true;
document.addEventListener("mousemove", function (e) {
// Detectar si estamos sobre un elemento de texto
const rect = canvas.getBoundingClientRect();
const currentX = e.clientX - rect.left;
const currentY = e.clientY - rect.top;
if (isFirstMove) {
pointers[0].x = currentX;
pointers[0].y = currentY;
isFirstMove = false;
return;
}
const overText = isMouseOverTextElement(e.target);
count++;
if (count > 1) {
transitionProgress += transitionSpeed;
@@ -407,53 +381,55 @@ document.addEventListener("mousemove", function (e) {
pointers[0].down = true;
pointers[0].color = colorArr;
pointers[0].moved = pointers[0].down;
// Aplicar multiplicador diferente según si estamos sobre texto o no
const multiplier = overText ? 8 : 10.0; // Reducido a 4x sobre texto (vs 10x)
pointers[0].dx = (e.clientX - canvas.offsetLeft - pointers[0].x) * multiplier;
pointers[0].dy = (e.clientY - canvas.offsetTop - pointers[0].y) * multiplier;
pointers[0].x = e.clientX - canvas.offsetLeft;
pointers[0].y = e.clientY - canvas.offsetTop;
pointers[0].moved = true;
const multiplier = overText ? 8.0 : 10.0;
pointers[0].dx = (currentX - pointers[0].x) * multiplier;
pointers[0].dy = (currentY - pointers[0].y) * multiplier;
pointers[0].x = currentX;
pointers[0].y = currentY;
});
canvas.addEventListener(
"touchmove",
function (e) {
e.preventDefault();
let touches = e.targetTouches;
count++;
if (count > 20) {
transitionProgress += transitionSpeed;
if (transitionProgress >= 1) {
transitionProgress = 0;
let currentIndex = brandColors.indexOf(currentColor);
let nextIndex = (currentIndex + 1) % brandColors.length;
currentColor = targetColor;
targetColor = brandColors[nextIndex];
}
colorArr = lerpColor(currentColor, targetColor, transitionProgress);
count = 0;
window.addEventListener("mouseleave", function () {
isFirstMove = true;
pointers[0].moved = false;
});
canvas.addEventListener("touchmove", function (e) {
e.preventDefault();
let touches = e.targetTouches;
count++;
if (count > 20) {
transitionProgress += transitionSpeed;
if (transitionProgress >= 1) {
transitionProgress = 0;
let currentIndex = brandColors.indexOf(currentColor);
let nextIndex = (currentIndex + 1) % brandColors.length;
currentColor = targetColor;
targetColor = brandColors[nextIndex];
}
for (let i = 0, len = touches.length; i < len; i++) {
if (i >= pointers.length) pointers.push(new pointerPrototype());
pointers[i].id = touches[i].identifier;
pointers[i].down = true;
pointers[i].x = touches[i].pageX;
pointers[i].y = touches[i].pageY;
pointers[i].color = colorArr;
let pointer = pointers[i];
pointer.moved = pointer.down;
pointer.dx = (touches[i].pageX - pointer.x) * 10.0;
pointer.dy = (touches[i].pageY - pointer.y) * 10.0;
pointer.x = touches[i].pageX;
pointer.y = touches[i].pageY;
}
},
false
);
colorArr = lerpColor(currentColor, targetColor, transitionProgress);
count = 0;
}
const rect = canvas.getBoundingClientRect();
for (let i = 0, len = touches.length; i < len; i++) {
if (i >= pointers.length) pointers.push(new pointerPrototype());
let pointer = pointers[i];
let touchX = touches[i].clientX - rect.left;
let touchY = touches[i].clientY - rect.top;
pointer.id = touches[i].identifier;
pointer.down = true;
pointer.color = colorArr;
pointer.moved = true;
pointer.dx = (touchX - pointer.x) * 10.0;
pointer.dy = (touchY - pointer.y) * 10.0;
pointer.x = touchX;
pointer.y = touchY;
}
}, false);
// ===== LOOP PRINCIPAL =====
let lastTime = Date.now();
@@ -465,27 +441,17 @@ function update() {
gl.viewport(0, 0, textureWidth, textureHeight);
advectionProgram.bind();
gl.uniform2f(
advectionProgram.uniforms.texelSize,
1.0 / textureWidth,
1.0 / textureHeight
);
gl.uniform2f(advectionProgram.uniforms.texelSize, 1.0 / textureWidth, 1.0 / textureHeight);
gl.uniform1i(advectionProgram.uniforms.uVelocity, velocity.first[2]);
gl.uniform1i(advectionProgram.uniforms.uSource, velocity.first[2]);
gl.uniform1f(advectionProgram.uniforms.dt, dt);
gl.uniform1f(
advectionProgram.uniforms.dissipation,
config.VELOCITY_DISSIPATION
);
gl.uniform1f(advectionProgram.uniforms.dissipation, config.VELOCITY_DISSIPATION);
blit(velocity.second[1]);
velocity.swap();
gl.uniform1i(advectionProgram.uniforms.uVelocity, velocity.first[2]);
gl.uniform1i(advectionProgram.uniforms.uSource, density.first[2]);
gl.uniform1f(
advectionProgram.uniforms.dissipation,
config.DENSITY_DISSIPATION
);
gl.uniform1f(advectionProgram.uniforms.dissipation, config.DENSITY_DISSIPATION);
blit(density.second[1]);
density.swap();
@@ -498,20 +464,12 @@ function update() {
}
curlProgram.bind();
gl.uniform2f(
curlProgram.uniforms.texelSize,
1.0 / textureWidth,
1.0 / textureHeight
);
gl.uniform2f(curlProgram.uniforms.texelSize, 1.0 / textureWidth, 1.0 / textureHeight);
gl.uniform1i(curlProgram.uniforms.uVelocity, velocity.first[2]);
blit(curl[1]);
vorticityProgram.bind();
gl.uniform2f(
vorticityProgram.uniforms.texelSize,
1.0 / textureWidth,
1.0 / textureHeight
);
gl.uniform2f(vorticityProgram.uniforms.texelSize, 1.0 / textureWidth, 1.0 / textureHeight);
gl.uniform1i(vorticityProgram.uniforms.uVelocity, velocity.first[2]);
gl.uniform1i(vorticityProgram.uniforms.uCurl, curl[2]);
gl.uniform1f(vorticityProgram.uniforms.curl, config.CURL);
@@ -520,11 +478,7 @@ function update() {
velocity.swap();
divergenceProgram.bind();
gl.uniform2f(
divergenceProgram.uniforms.texelSize,
1.0 / textureWidth,
1.0 / textureHeight
);
gl.uniform2f(divergenceProgram.uniforms.texelSize, 1.0 / textureWidth, 1.0 / textureHeight);
gl.uniform1i(divergenceProgram.uniforms.uVelocity, velocity.first[2]);
blit(divergence[1]);
@@ -538,11 +492,7 @@ function update() {
pressure.swap();
pressureProgram.bind();
gl.uniform2f(
pressureProgram.uniforms.texelSize,
1.0 / textureWidth,
1.0 / textureHeight
);
gl.uniform2f(pressureProgram.uniforms.texelSize, 1.0 / textureWidth, 1.0 / textureHeight);
gl.uniform1i(pressureProgram.uniforms.uDivergence, divergence[2]);
pressureTexId = pressure.first[2];
gl.activeTexture(gl.TEXTURE0 + pressureTexId);
@@ -554,11 +504,7 @@ function update() {
}
gradienSubtractProgram.bind();
gl.uniform2f(
gradienSubtractProgram.uniforms.texelSize,
1.0 / textureWidth,
1.0 / textureHeight
);
gl.uniform2f(gradienSubtractProgram.uniforms.texelSize, 1.0 / textureWidth, 1.0 / textureHeight);
gl.uniform1i(gradienSubtractProgram.uniforms.uPressure, pressure.first[2]);
gl.uniform1i(gradienSubtractProgram.uniforms.uVelocity, velocity.first[2]);
blit(velocity.second[1]);
@@ -567,6 +513,12 @@ function update() {
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
displayProgram.bind();
gl.uniform1i(displayProgram.uniforms.uTexture, density.first[2]);
const isDarkTheme = document.documentElement.getAttribute('data-theme') === 'dark';
if (displayProgram.uniforms.uIsDark !== undefined) {
gl.uniform1f(displayProgram.uniforms.uIsDark, isDarkTheme ? 1.0 : 0.0);
}
blit(null);
requestAnimationFrame(update);
@@ -574,9 +526,9 @@ function update() {
update();
// ===== REDIMENSIONAR AL CAMBIAR TAMAÑO DE VENTANA =====
// ===== REDIMENSIONAR =====
window.addEventListener("resize", function() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
initFramebuffers();
});
+262 -210
View File
@@ -190,224 +190,282 @@ document.addEventListener('DOMContentLoaded', async () => {
});
/* ============================================
LÓGICA DEL CUESTIONARIO DE DIAGNÓSTICO
DIAGNÓSTICO INTERACTIVO
============================================ */
function initDiagnostico() {
// Elementos del DOM
const bienvenida = document.getElementById('diagnostico-bienvenida');
const quiz = document.getElementById('diagnostico-quiz');
const resultado = document.getElementById('resultado-contenedor');
const btnComenzar = document.getElementById('btn-comenzar');
const contenedorPreguntas = document.getElementById('cuestionario-contenedor');
const barraCompletado = document.getElementById('progreso-completado');
const textoProgreso = document.getElementById('progreso-texto');
// Datos del cuestionario
const preguntas = [
{
id: 1,
titulo: "¿En qué etapa se encuentra hoy tu negocio o proyecto?",
opciones: [
{ letra: "A", texto: "Creando el proyecto desde cero o formalizando una idea reciente." },
{ letra: "B", texto: "Negocio o local activo, pero con una imagen visual que no refleja la calidad de lo que vendo." },
{ letra: "C", texto: "En pleno movimiento comercial, pero desbordados para contestar consultas a tiempo." },
{ letra: "D", texto: "Establecido y con ventas, pero con un techo de crecimiento que necesitamos romper con publicidad." },
{ letra: "E", texto: "Empresa consolidada que busca liderazgo de mercado y delegar todo su marketing de punta a punta." },
{ letra: "F", texto: "Emprendimiento personal que gestiono por mi cuenta y donde necesito resolver piezas puntuales." }
]
},
{
id: 2,
titulo: "¿Cuál es tu cuello de botella más urgente hoy?",
opciones: [
{ letra: "A", texto: "No tengo logo profesional ni página web; me falta confianza frente a la competencia." },
{ letra: "B", texto: "No tengo tiempo ni equipo para sacar fotos o grabar videos de buena calidad de mis productos/servicios." },
{ letra: "C", texto: "Perdemos clientes potenciales porque tardamos horas en responder WhatsApp o mensajes de redes." },
{ letra: "D", texto: "Dependemos del boca a boca o de publicar en redes sin conseguir ventas constantes ni predecibles." },
{ letra: "E", texto: "Tenemos acciones aisladas sin una dirección estratégica clara ni medición profesional de métricas." },
{ letra: "F", texto: "Me faltan herramientas gráficas o plantillas para diseñar mis propias publicaciones sin perder horas." }
]
},
{
id: 3,
titulo: "¿Con qué infraestructura digital cuentas actualmente?",
opciones: [
{ letra: "A", texto: "Prácticamente nada formal (solo una idea, perfil personal o logo provisional)." },
{ letra: "B", texto: "Perfil comercial en redes sociales, pero con fotos caseras tomadas con el celular." },
{ letra: "C", texto: "Redes y/o tienda activa con alto volumen de mensajes directos diarios sin automatizar." },
{ letra: "D", texto: "Redes y web en marcha, pero sin campañas activas de publicidad paga (Meta Ads / Google Ads)." },
{ letra: "E", texto: "Ecosistema activo (redes, web, pauta), pero disperso entre distintos proveedores sin sinergia." },
{ letra: "F", texto: "Manejo mis propios canales y solo requiero recursos gráficos específicos para seguir operando." }
]
},
{
id: 4,
titulo: "¿Qué tipo de solución buscas contratar en Amor y Roma?",
opciones: [
{ letra: "A", texto: "Proyecto inicial integral: crear mi identidad de marca y mi sitio web para salir al mercado." },
{ letra: "B", texto: "Acompañamiento mensual con sesiones presenciales de fotos/video para no preocuparme del contenido." },
{ letra: "C", texto: "Implementación tecnológica: automatizaciones inteligentes y asistentes para WhatsApp y redes." },
{ letra: "D", texto: "Gestión de campañas de publicidad digital y páginas de venta enfocadas 100% en conversión." },
{ letra: "E", texto: "Gestión integral 360°: estrategia de marca completa, pauta multicanal, redes y dirección creativa." },
{ letra: "F", texto: "Un entregable puntual (diseño de plantilla, digitalización de logo o sesión única de fotos)." }
]
}
];
if (!bienvenida || !quiz || !resultado || !btnComenzar) return;
// Perfiles de resultado
const perfiles = {
A: {
titulo: "Mix Lanzamiento Integral",
diagnostico: "Tu proyecto necesita bases sólidas y credibilidad inmediata para competir y generar confianza.",
solucion: "Identidad visual completa (Branding) + Diseño Web institucional + Gestión de Redes Sociales (Plan Esencial, $250.000/mes).",
cta: "Cotizar Mix Lanzamiento"
},
B: {
titulo: "Mix Comercio & Presencia Visual",
diagnostico: "Tu producto o servicio tiene potencial comercial, pero la calidad visual actual en redes te resta ventas.",
solucion: "Plan Premium de Redes Sociales ($650.000/mes), que incluye sesión presencial quincenal de fotos y videos profesionales, 8 reels, asistencia con IA y dirección creativa.",
cta: "Ver Plan Premium"
},
C: {
titulo: "Solución Eficiencia & Automatización",
diagnostico: "Tu principal fuga de dinero es el tiempo de respuesta: consultas demoradas son ventas perdidas.",
solucion: "Implementación de Automatizaciones con Asistentes Inteligentes para WhatsApp, Instagram y Facebook + Plan Impulso ($420.000/mes) para ordenar el flujo de mensajes.",
cta: "Automatizar mi Atención"
},
D: {
titulo: "Mix Acelerador & Conversión",
diagnostico: "Tu marca ya está ordenada visualmente; ahora necesita tráfico calificado y un sistema predecible de atracción de clientes.",
solucion: "Servicio de Paid Media (Meta Ads + Google Ads) + Optimización de Landing Page / Catálogo + Creatividades publicitarias de alto impacto.",
cta: "Escalar mis Ventas"
},
E: {
titulo: "Servicio Corporativo 360°",
diagnostico: "Tu empresa busca liderazgo absoluto de mercado, unificación de imagen y tercerización completa del departamento de marketing.",
solucion: "Plan Élite de Redes ($1.000.000/mes) + Branding Integral (packaging, cartelería física) + Pauta multicanal (Meta, TikTok, Google) + Reportes quincenales avanzados con KPIs.",
cta: "Agendar Reunión Estratégica"
},
F: {
titulo: "Solución Autogestor / Servicios Puntuales",
diagnostico: "Buscas resolver necesidades gráficas puntuales sin comprometerte con un abono mensual recurrente.",
solucion: "Paquetes individuales a medida: Digitalización y vectorización de logo, Pack de plantillas editables personalizadas o Producción fotográfica por jornada.",
cta: "Elegir Servicios Puntuales"
}
};
// Banco de preguntas
const preguntas = [
{
id: 1,
titulo: '¿En qué etapa se encuentra hoy tu negocio o proyecto?',
opciones: [
{ texto: 'Creando el proyecto desde cero o formalizando una idea reciente.', valor: 'inicio' },
{ texto: 'Negocio activo, pero con una imagen visual que no refleja la calidad de lo que vendo.', valor: 'identidad' },
{ texto: 'En pleno movimiento comercial, pero desbordados para contestar consultas a tiempo.', valor: 'automatizacion' },
{ texto: 'Establecido y con ventas, pero con un techo de crecimiento que necesitamos romper con publicidad.', valor: 'paid' },
{ texto: 'Empresa consolidada que busca liderazgo de mercado y delegar todo su marketing.', valor: 'corporativo' },
{ texto: 'Emprendimiento personal que gestiono por mi cuenta y necesito resolver piezas puntuales.', valor: 'consultoria' }
]
},
{
id: 2,
titulo: '¿Cuál es tu mayor desafío actual en marketing?',
opciones: [
{ texto: 'No tengo una identidad clara ni coherente en mis canales.', valor: 'identidad' },
{ texto: 'Tengo redes pero no generan consultas ni ventas reales.', valor: 'redes' },
{ texto: 'Mi sitio web está desactualizado o no convierte visitantes en clientes.', valor: 'web' },
{ texto: 'No tengo tiempo ni equipo para producir contenido constante.', valor: 'contenido' },
{ texto: 'Invierto en pauta pero no sé si estoy llegando a la audiencia correcta.', valor: 'paid' },
{ texto: 'No tengo una estrategia clara y voy tomando decisiones sobre la marcha.', valor: 'consultoria' }
]
},
{
id: 3,
titulo: '¿Qué objetivo prioritario tenés para los próximos 6 meses?',
opciones: [
{ texto: 'Lanzar mi marca con una identidad sólida y profesional.', valor: 'identidad' },
{ texto: 'Construir una comunidad activa y fiel en redes sociales.', valor: 'redes' },
{ texto: 'Tener un sitio web que venda por mí las 24 horas.', valor: 'web' },
{ texto: 'Automatizar procesos para ganar tiempo y escalar.', valor: 'automatizacion' },
{ texto: 'Escalar ventas con campañas de publicidad pagada.', valor: 'paid' },
{ texto: 'Tener un partner estratégico que me acompañe en las decisiones.', valor: 'consultoria' }
]
},
{
id: 4,
titulo: '¿Cómo describirías tu inversión actual en marketing?',
opciones: [
{ texto: 'Casi nula o muy básica, recién estoy empezando.', valor: 'inicio' },
{ texto: 'Baja, hago algunas cosas por mi cuenta pero me falta estructura.', valor: 'identidad' },
{ texto: 'Media, invierto en contenido pero no veo retorno claro.', valor: 'contenido' },
{ texto: 'Media-alta, ya tengo equipo o freelancers pero falta dirección.', valor: 'consultoria' },
{ texto: 'Alta, invierto en pauta y necesito maximizar el ROI.', valor: 'paid' },
{ texto: 'Integral, busco una agencia que gestione todo 360°.', valor: 'corporativo' }
]
}
];
// Estado del cuestionario
let preguntaActual = 0;
let respuestas = [];
// Mapeo de resultados según valor más frecuente
const resultados = {
inicio: {
titulo: 'Plan Esencial',
diagnostico: 'Estás en una etapa fundacional. Tu marca necesita bases sólidas antes de escalar.',
solucion: 'Te recomendamos comenzar con un <strong>Plan Esencial</strong>: identidad visual básica, sitio web institucional y gestión inicial de redes. Es el punto de partida ideal para construir con estrategia desde el día uno.'
},
identidad: {
titulo: 'Construcción de Identidad Estratégica',
diagnostico: 'Tu negocio tiene potencial, pero la percepción visual no está a la altura de lo que ofrecés.',
solucion: 'Necesitás un trabajo de <strong>Branding integral</strong>: definir el ADN de tu marca, su posicionamiento y el camino para conectar con tu audiencia ideal de manera auténtica y memorable.'
},
redes: {
titulo: 'Comunidades que Convierten',
diagnostico: 'Tenés presencia pero no estás generando el impacto ni la conexión que buscás.',
solucion: 'Te recomendamos nuestro servicio de <strong>Gestión de Redes Sociales</strong>: creamos contenido de valor y gestionamos tus canales para construir una comunidad activa, fiel y comprometida con tu marca.'
},
web: {
titulo: 'Experiencias Digitales Impactantes',
diagnostico: 'Tu sitio web no está cumpliendo su rol como herramienta de venta y conversión.',
solucion: 'Necesitás un <strong>rediseño o desarrollo web estratégico</strong>: un sitio que no solo se vea bien, sino que genere resultados tangibles y convierta visitantes en clientes.'
},
contenido: {
titulo: 'Historias que Enamoran',
diagnostico: 'Tenés el negocio andando pero te falta el contenido que conecte emocionalmente con tu audiencia.',
solucion: 'Te recomendamos nuestro servicio de <strong>Producción de Contenido Audiovisual y Gráfico</strong>: contenido de alta calidad que cuente la historia de tu marca y cautive a tu audiencia.'
},
automatizacion: {
titulo: 'Automatización de Procesos',
diagnostico: 'El crecimiento te está desbordando. Necesitás sistemas que trabajen por vos.',
solucion: 'Necesitás <strong>automatizaciones inteligentes</strong>: flujos de WhatsApp, respuestas automáticas y sistemas que liberen tu tiempo para que te enfoques en lo estratégico.'
},
paid: {
titulo: 'Campañas que Escalan Resultados',
diagnostico: 'Tenés producto y demanda, pero necesitás acelerar el crecimiento con inversión publicitaria inteligente.',
solucion: 'Te recomendamos <strong>Paid Media en Meta, Google y LinkedIn</strong>: campañas gestionadas estratégicamente para maximizar tu ROI y alcanzar a los clientes correctos.'
},
consultoria: {
titulo: 'Asesoramiento Estratégico Integral',
diagnostico: 'Tenés recursos y voluntad, pero te falta una brújula estratégica que alinee tus esfuerzos.',
solucion: 'Necesitás una <strong>Consultoría de Marketing</strong>: te acompañamos en la toma de decisiones clave, optimizando tus recursos y alineando tu marketing con los objetivos de tu negocio.'
},
corporativo: {
titulo: 'Plan Corporativo 360°',
diagnostico: 'Tu empresa está en un nivel donde necesitás un equipo dedicado que gestione todo de forma integral.',
solucion: 'Te recomendamos el <strong>Plan Corporativo</strong>: dirección creativa y estratégica, branding integral, pauta multicanal, reportes con KPIs y un equipo dedicado exclusivamente a tu marca.'
}
};
// Función para calcular el perfil
function calcularPerfil(respuestas) {
const conteo = { A: 0, B: 0, C: 0, D: 0, E: 0, F: 0 };
respuestas.forEach(r => {
if (conteo[r] !== undefined) conteo[r]++;
// Estado
let preguntaActual = 0;
const respuestas = [];
// Iniciar cuestionario
btnComenzar.addEventListener('click', () => {
bienvenida.style.display = 'none';
quiz.style.display = 'block';
resultado.style.display = 'none';
preguntaActual = 0;
respuestas.length = 0;
renderizarPregunta();
});
// Encontrar la letra con mayor frecuencia
let maxVotos = 0;
let ganador = respuestas[1]; // Fallback por defecto: pregunta 2 (cuello de botella)
// Renderizar pregunta actual
function renderizarPregunta() {
const pregunta = preguntas[preguntaActual];
const progreso = ((preguntaActual) / preguntas.length) * 100;
for (const letra in conteo) {
if (conteo[letra] > maxVotos) {
maxVotos = conteo[letra];
ganador = letra;
} else if (conteo[letra] === maxVotos && maxVotos > 0) {
// Desempate: priorizar la respuesta de la Pregunta 2
if (respuestas[1] === letra) {
ganador = letra;
}
barraCompletado.style.width = `${progreso}%`;
textoProgreso.textContent = `Pregunta ${preguntaActual + 1} de ${preguntas.length}`;
let html = `
<div class="pregunta-contenedor">
<h3 class="pregunta-titulo">${pregunta.titulo}</h3>
<div class="opciones-contenedor">
`;
pregunta.opciones.forEach((opcion, index) => {
const seleccionada = respuestas[preguntaActual] === opcion.valor ? 'seleccionada' : '';
html += `
<button class="opcion-tarjeta ${seleccionada}" data-valor="${opcion.valor}" data-index="${index}">
<span class="opcion-numero">${index + 1}</span>
<span class="opcion-texto">${opcion.texto}</span>
</button>
`;
});
html += `</div>`;
// Navegación
html += `
<div class="pregunta-navegacion">
<button class="btn-anterior" ${preguntaActual === 0 ? 'style="visibility: hidden;"' : ''}>
← Anterior
</button>
<button class="btn-siguiente" ${!respuestas[preguntaActual] ? 'disabled' : ''}>
${preguntaActual === preguntas.length - 1 ? 'Ver resultado' : 'Siguiente →'}
</button>
</div>
`;
html += `</div>`;
contenedorPreguntas.innerHTML = html;
// Event listeners de opciones
const opciones = contenedorPreguntas.querySelectorAll('.opcion-tarjeta');
opciones.forEach(opcion => {
opcion.addEventListener('click', () => {
const valor = opcion.dataset.valor;
respuestas[preguntaActual] = valor;
// Actualizar UI
opciones.forEach(o => o.classList.remove('seleccionada'));
opcion.classList.add('seleccionada');
// Habilitar botón siguiente
const btnSiguiente = contenedorPreguntas.querySelector('.btn-siguiente');
if (btnSiguiente) btnSiguiente.disabled = false;
});
});
// Navegación
const btnAnterior = contenedorPreguntas.querySelector('.btn-anterior');
const btnSiguiente = contenedorPreguntas.querySelector('.btn-siguiente');
if (btnAnterior) {
btnAnterior.addEventListener('click', () => {
if (preguntaActual > 0) {
preguntaActual--;
renderizarPregunta();
}
});
}
if (btnSiguiente) {
btnSiguiente.addEventListener('click', () => {
if (respuestas[preguntaActual]) {
if (preguntaActual < preguntas.length - 1) {
preguntaActual++;
renderizarPregunta();
} else {
mostrarResultado();
}
}
});
}
}
return ganador;
}
// Calcular y mostrar resultado
function mostrarResultado() {
// Contar frecuencia de cada valor
const conteo = {};
respuestas.forEach(valor => {
conteo[valor] = (conteo[valor] || 0) + 1;
});
// Función para renderizar pregunta
function renderizarPregunta() {
const contenedor = document.getElementById('cuestionario-contenedor');
const pregunta = preguntas[preguntaActual];
contenedor.innerHTML = `
<div class="pregunta-contenedor">
<h3 class="pregunta-titulo">${pregunta.titulo}</h3>
<div class="opciones-contenedor">
${pregunta.opciones.map(opcion => `
<button class="opcion-tarjeta" data-letra="${opcion.letra}">
${opcion.texto}
</button>
`).join('')}
// Obtener el valor más frecuente
let valorGanador = Object.keys(conteo).reduce((a, b) =>
conteo[a] > conteo[b] ? a : b
);
const resultadoData = resultados[valorGanador] || resultados.consultoria;
// Actualizar barra al 100%
barraCompletado.style.width = '100%';
textoProgreso.textContent = `Completado`;
// Ocultar quiz y mostrar resultado
quiz.style.display = 'none';
resultado.style.display = 'block';
resultado.innerHTML = `
<div class="resultado-encabezado">
<h3 class="resultado-titulo">${resultadoData.titulo}</h3>
<p class="resultado-subtitulo">Según tus respuestas, esto es lo que más te conviene:</p>
</div>
</div>
`;
// Agregar event listeners a las opciones
document.querySelectorAll('.opcion-tarjeta').forEach(tarjeta => {
tarjeta.addEventListener('click', () => seleccionarOpcion(tarjeta.dataset.letra));
});
}
<p class="resultado-diagnostico">${resultadoData.diagnostico}</p>
<div class="resultado-solucion">
${resultadoData.solucion}
</div>
<div class="resultado-acciones">
<a href="contacto.html" class="resultado-cta">
Hablemos sobre esto
<span aria-hidden="true">→</span>
</a>
<button class="btn-reiniciar" id="btn-reiniciar-resultado">
<span aria-hidden="true">↻</span>
Reiniciar diagnóstico
</button>
</div>
`;
// Función para seleccionar opción
function seleccionarOpcion(letra) {
respuestas[preguntaActual] = letra;
// Actualizar barra de progreso
const progreso = ((preguntaActual + 1) / preguntas.length) * 100;
document.getElementById('progreso-completado').style.width = `${progreso}%`;
// Avanzar o mostrar resultado
if (preguntaActual < preguntas.length - 1) {
preguntaActual++;
document.getElementById('progreso-texto').textContent = `Pregunta ${preguntaActual + 1} de ${preguntas.length}`;
renderizarPregunta();
} else {
mostrarResultado();
// Event listener del botón reiniciar
const btnReiniciar = document.getElementById('btn-reiniciar-resultado');
if (btnReiniciar) {
btnReiniciar.addEventListener('click', () => {
resultado.style.display = 'none';
bienvenida.style.display = 'flex';
preguntaActual = 0;
respuestas.length = 0;
barraCompletado.style.width = '0%';
});
}
}
}
// Función para mostrar resultado
function mostrarResultado() {
const perfilLetra = calcularPerfil(respuestas);
const perfil = perfiles[perfilLetra];
// Ocultar cuestionario y barra de progreso
document.getElementById('cuestionario-contenedor').style.display = 'none';
document.querySelector('.progreso-barra').style.display = 'none';
document.getElementById('progreso-texto').style.display = 'none';
document.getElementById('btn-reiniciar').style.display = 'none';
// Mostrar resultado
const resultadoContenedor = document.getElementById('resultado-contenedor');
resultadoContenedor.innerHTML = `
<h2 class="resultado-titulo">${perfil.titulo}</h2>
<p class="resultado-diagnostico">${perfil.diagnostico}</p>
<div class="resultado-solucion">
<strong>Solución Amor y Roma:</strong><br>
${perfil.solucion}
</div>
<button class="resultado-cta">${perfil.cta}</button>
`;
resultadoContenedor.style.display = 'block';
// Event listener al CTA (placeholder por ahora)
document.querySelector('.resultado-cta').addEventListener('click', () => {
alert('CTA - Por definir acción');
});
}
// Función para reiniciar
function reiniciarCuestionario() {
preguntaActual = 0;
respuestas = [];
// Resetear barra de progreso
document.getElementById('progreso-completado').style.width = '0%';
document.getElementById('progreso-texto').textContent = 'Pregunta 1 de 4';
// Mostrar elementos
document.getElementById('cuestionario-contenedor').style.display = 'block';
document.querySelector('.progreso-barra').style.display = 'block';
document.getElementById('progreso-texto').style.display = 'block';
document.getElementById('btn-reiniciar').style.display = 'inline-flex';
document.getElementById('resultado-contenedor').style.display = 'none';
// Renderizar primera pregunta
renderizarPregunta();
}
// Inicializar cuando el DOM esté listo
document.addEventListener('DOMContentLoaded', () => {
initDiagnostico();
});
/* ============================================
ANIMACIÓN AUTOMÁTICA DE METODOLOGÍA
============================================ */
@@ -671,15 +729,9 @@ function initNavbarAutoHide() {
// Inicializar cuestionario al cargar la página
document.addEventListener('DOMContentLoaded', () => {
// Solo inicializar si estamos en la sección de diagnóstico
if (document.getElementById('cuestionario-contenedor')) {
renderizarPregunta();
// Event listener al botón de reiniciar
document.getElementById('btn-reiniciar').addEventListener('click', reiniciarCuestionario);
}
// Eliminar el bloque del diagnóstico (ya se maneja en initDiagnostico)
initMetodologiaAnimation();
initPlanesFocusEffect();
initPortfolioCarousel();
});
initMarqueeHover(); // ← además, esta NUNCA se está llamando
});
+74
View File
@@ -0,0 +1,74 @@
/* ============================================
SELECTOR DE PLANES
============================================ */
function initPlanesSelector() {
const tabs = document.querySelectorAll('.plan-tab');
const pills = document.querySelectorAll('.plan-pill');
const panels = document.querySelectorAll('.plan-panel');
if (tabs.length === 0 || panels.length === 0) return;
function activarPlan(planId) {
// Desactivar todos los tabs y pills
tabs.forEach(tab => {
tab.classList.remove('active');
tab.setAttribute('aria-selected', 'false');
});
pills.forEach(pill => {
pill.classList.remove('active');
pill.setAttribute('aria-selected', 'false');
});
// Desactivar todos los panels
panels.forEach(panel => panel.classList.remove('active'));
// Activar el tab y pill correspondientes
const tabActivo = document.querySelector(`.plan-tab[data-plan="${planId}"]`);
const pillActivo = document.querySelector(`.plan-pill[data-plan="${planId}"]`);
const panelActivo = document.getElementById(`panel-${planId}`);
if (tabActivo) {
tabActivo.classList.add('active');
tabActivo.setAttribute('aria-selected', 'true');
}
if (pillActivo) {
pillActivo.classList.add('active');
pillActivo.setAttribute('aria-selected', 'true');
}
if (panelActivo) {
panelActivo.classList.add('active');
}
// Scroll suave al panel
if (panelActivo) {
panelActivo.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
}
// Event listeners para tabs
tabs.forEach(tab => {
tab.addEventListener('click', () => {
const planId = tab.dataset.plan;
activarPlan(planId);
});
});
// Event listeners para pills
pills.forEach(pill => {
pill.addEventListener('click', () => {
const planId = pill.dataset.plan;
activarPlan(planId);
});
});
// Soporte para hash en URL (ej: planes.html#premium)
const hash = window.location.hash.replace('#', '');
if (hash && document.getElementById(`panel-${hash}`)) {
activarPlan(hash);
}
}
// Inicializar cuando el DOM esté listo
document.addEventListener('DOMContentLoaded', () => {
initPlanesSelector();
});
+12 -6
View File
@@ -4,11 +4,16 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Servicios de Amor y Roma: gestión de redes, branding, desarrollo web, automatizaciones y paid media.">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css">
<title>Servicios - Amor y Roma</title>
<link rel="icon" href="/assets/img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="style/main.css">
<link rel="stylesheet" href="style/servicios.css">
</head>
<body>
<div id="fluid-bg" aria-hidden="true">
<canvas id="fluidCanvas"></canvas>
</div>
<div id="menu-container"></div>
<main>
@@ -17,7 +22,7 @@
<div class="servicios-hero-content">
<span class="servicios-hero-tag">Nuestros servicios</span>
<h1 class="servicios-hero-title">Soluciones a medida para cada etapa de tu marca</h1>
<p class="servicios-hero-subtitle">Combinamos estrategia, diseño y tecnología para construir marcas con esencia y estructura.</p>
<p class="servicios-hero-subtitle">Diseñamos servicios que se adaptan a tu realidad, para ayudarte a crecer sin perder lo que te hace único.</p>
<a href="#servicios-selector" class="btn btn-primary servicios-hero-cta">Explorar servicios</a>
</div>
</section>
@@ -253,7 +258,7 @@
<div class="panel-footer">
<div class="panel-precio">
<span class="precio-label">Desde</span>
<span class="precio-valor">$220.000<span class="precio-periodo">/mes</span></span>
<span class="precio-valor">$220.000<span class="precio-periodo">/campaña</span></span>
</div>
<a href="contacto.html?servicio=paid" class="btn btn-secondary panel-cta">Cotizar este servicio</a>
</div>
@@ -262,8 +267,8 @@
</div>
</section>
<!-- Sección 4: Separador visual -->
<section class="servicios-separador"></section>
<!-- Sección 4: Separador visual
<section class="servicios-separador"></section>-->
<!-- Sección 5: Casos de éxito -->
<section class="servicios-casos">
@@ -301,9 +306,9 @@
<section class="servicios-cta">
<div class="servicios-cta-card">
<h2 class="servicios-cta-titulo">¿No sabés cuál servicio necesitás?</h2>
<p class="servicios-cta-subtitulo">Hacé nuestro diagnóstico gratuito y te recomendamos la solución ideal para tu momento.</p>
<p class="servicios-cta-subtitle">Hacé nuestro diagnóstico gratuito y te recomendamos la solución ideal para tu momento.</p>
<div class="servicios-cta-buttons">
<a href="inicio.html#diagnostico" class="btn btn-cta-primary">Hacer el diagnóstico</a>
<a href="index.html#diagnostico" class="btn btn-cta-primary">Hacer el diagnóstico</a>
<a href="contacto.html" class="btn btn-cta-secondary">Hablemos directamente</a>
</div>
</div>
@@ -317,5 +322,6 @@
<script src="scripts/main.js"></script>
<script src="scripts/servicios.js"></script>
<script src="scripts/fluid.js"></script>
</body>
</html>
+719
View File
@@ -0,0 +1,719 @@
/* ============================================
HERO COMPACTO DEL BLOG
============================================ */
.blog-hero-compact {
padding: calc(var(--spacing-lg) + 2rem) var(--spacing-md) var(--spacing-lg);
background-color: transparent;
text-align: center;
position: relative;
}
.hero-compact-content {
max-width: 700px;
margin: 0 auto;
display: flex;
flex-direction: column;
align-items: center;
gap: var(--spacing-sm);
}
.blog-hero-compact .badge-filosofia {
display: inline-block;
padding: 0.4rem 1rem;
border-radius: 999px;
background-color: var(--badge-bg);
color: var(--badge-text);
font-family: var(--font-small);
font-weight: 600;
font-size: 0.85rem;
letter-spacing: 0.5px;
text-transform: uppercase;
opacity: 0;
animation: fadeInUp 0.9s ease-out 0s forwards;
}
.blog-hero-compact .hero-compact-title {
font-family: var(--font-title);
font-style: italic;
font-weight: 700;
font-size: clamp(2.5rem, 6vw, 4rem);
line-height: 1.1;
color: var(--text-primary);
opacity: 0;
animation: fadeInUp 0.9s ease-out 0.2s forwards;
}
.blog-hero-compact .hero-compact-subtitle {
font-family: var(--font-body);
font-size: clamp(1rem, 2vw, 1.15rem);
color: var(--text-muted);
line-height: 1.6;
max-width: 600px;
opacity: 0;
animation: fadeInUp 0.9s ease-out 0.4s forwards;
}
/* ============================================
SECCIÓN FILTROS Y BUSCADOR
============================================ */
.blog-filters-section {
padding: var(--spacing-md) var(--spacing-md);
background-color: var(--bg-surface-t0);
position: relative;
z-index: 1;
}
.filters-container {
max-width: 1400px;
margin: 0 auto;
display: flex;
flex-direction: column;
align-items: center;
gap: var(--spacing-sm);
}
.filters-top-row {
display: flex;
gap: var(--spacing-sm);
align-items: center;
justify-content: center;
flex-wrap: wrap;
}
.search-wrapper-compact {
flex: 1;
min-width: 280px;
max-width: 480px;
position: relative;
display: flex;
align-items: center;
background-color: var(--bg-base);
border: 1.5px solid var(--border);
border-radius: 999px;
padding: 0.5rem 0.5rem 0.5rem 1.1rem;
transition: all 0.3s ease;
}
.search-wrapper-compact:focus-within {
border-color: var(--brand-crimson);
box-shadow: 0 0 0 3px rgba(186, 18, 77, 0.1);
background-color: var(--bg-surface);
}
.search-wrapper-compact .search-icon {
color: var(--text-muted);
margin-right: 0.6rem;
flex-shrink: 0;
display: flex;
align-items: center;
}
.search-wrapper-compact input {
flex: 1;
border: none;
background: transparent;
font-family: var(--font-body);
font-size: 0.95rem;
color: var(--text-primary);
padding: 0.4rem 0;
outline: none;
min-width: 0;
}
.search-wrapper-compact input::placeholder {
color: var(--text-muted);
}
.search-clear {
background: none;
border: none;
color: var(--text-muted);
cursor: pointer;
padding: 0.4rem;
display: none;
border-radius: 50%;
transition: all 0.2s ease;
flex-shrink: 0;
}
.search-clear:hover {
background-color: var(--bg-surface-elevated);
color: var(--brand-crimson);
}
.search-clear.visible {
display: flex;
align-items: center;
justify-content: center;
}
.filter-group-compact {
display: flex;
gap: 0.5rem;
flex-shrink: 0;
}
.filter-btn {
font-family: var(--font-small);
font-size: 0.85rem;
font-weight: 600;
padding: 0.5rem 1rem;
border: 1.5px solid var(--border);
border-radius: 999px;
background-color: transparent;
color: var(--text-primary);
cursor: pointer;
transition: all 0.25s ease;
white-space: nowrap;
}
.filter-btn:hover {
border-color: var(--brand-crimson);
color: var(--brand-crimson);
}
.filter-btn.active {
background-color: var(--brand-crimson);
border-color: var(--brand-crimson);
color: var(--text-on-accent);
}
.filters-bottom-row {
display: flex;
justify-content: center;
align-items: center;
gap: var(--spacing-sm);
flex-wrap: wrap;
padding-top: var(--spacing-xs);
border-top: 1px solid var(--border);
}
.filter-categories-compact {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
justify-content: center;
}
.category-btn {
font-family: var(--font-small);
font-size: 0.8rem;
font-weight: 600;
padding: 0.4rem 0.85rem;
border: 1px solid var(--border);
border-radius: 999px;
background-color: var(--bg-base);
color: var(--text-muted);
cursor: pointer;
transition: all 0.2s ease;
white-space: nowrap;
}
.category-btn:hover {
border-color: var(--brand-teal);
color: var(--brand-teal);
}
.category-btn.active {
background-color: var(--brand-teal);
border-color: var(--brand-teal);
color: var(--text-on-accent);
}
.filter-secondary-compact {
flex-shrink: 0;
}
.sort-select-compact {
font-family: var(--font-small);
font-size: 0.85rem;
padding: 0.45rem 2rem 0.45rem 0.9rem;
border: 1px solid var(--border);
border-radius: 999px;
background-color: var(--bg-base);
color: var(--text-primary);
cursor: pointer;
appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23170c1d' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 0.75rem center;
transition: all 0.2s ease;
}
.sort-select-compact:hover {
border-color: var(--brand-teal);
}
.results-info-compact {
display: flex;
justify-content: center;
align-items: center;
gap: var(--spacing-sm);
font-family: var(--font-small);
font-size: 0.85rem;
color: var(--text-muted);
padding-top: var(--spacing-xs);
}
.reset-filters-compact {
background: none;
border: none;
color: var(--brand-crimson);
font-family: var(--font-small);
font-size: 0.85rem;
font-weight: 600;
cursor: pointer;
padding: 0.3rem 0.6rem;
border-radius: 6px;
transition: all 0.2s ease;
}
.reset-filters-compact:hover {
background-color: rgba(186, 18, 77, 0.1);
}
/* ============================================
TAGS DE CATEGORÍAS
============================================ */
.category-tag {
font-family: var(--font-small);
font-size: 0.75rem;
font-weight: 700;
padding: 0.35rem 0.85rem;
border-radius: 999px;
text-transform: uppercase;
letter-spacing: 0.5px;
border: 1.5px solid transparent;
transition: all 0.2s ease;
}
.category-tag.branding { background-color: var(--brand-crimson); color: #ffffff; border-color: var(--brand-crimson); }
.category-tag.web { background-color: var(--brand-teal); color: #ffffff; border-color: var(--brand-teal); }
.category-tag.automatizaciones { background-color: var(--brand-plum); color: #ffffff; border-color: var(--brand-plum); }
.category-tag.redes { background-color: #00a88c; color: #ffffff; border-color: #00a88c; }
.category-tag.paid { background-color: #6b4c9a; color: #ffffff; border-color: #6b4c9a; }
.category-tag.estrategia { background-color: #d97706; color: #ffffff; border-color: #d97706; }
.category-tag.casos { background-color: #475569; color: #ffffff; border-color: #475569; }
[data-theme="dark"] .category-tag.automatizaciones { background-color: rgba(23, 12, 29, 0.95); color: var(--brand-sage-light); border-color: rgba(23, 12, 29, 1); }
[data-theme="dark"] .category-tag.redes { background-color: rgba(5, 104, 87, 0.95); color: #ffffff; border-color: rgba(0, 168, 140, 1); }
.category-tag:hover {
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
/* ============================================
ARTÍCULOS DESTACADOS
============================================ */
.featured-posts {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base-t3);
position: relative;
}
.featured-posts .section-header {
max-width: 1400px;
margin: 0 auto var(--spacing-lg);
text-align: left;
padding-left: var(--spacing-sm);
position: relative;
}
.featured-posts .section-header::before {
content: "";
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 4px;
height: 60px;
background: linear-gradient(180deg, var(--brand-crimson) 0%, var(--brand-teal) 100%);
border-radius: 2px;
}
.featured-posts .section-title {
font-family: var(--font-title);
font-style: italic;
font-size: clamp(1.2rem, 2vw, 1.8rem);
color: var(--text-primary);
margin-bottom: var(--spacing-xs);
line-height: 1.2;
padding-left: var(--spacing-md);
}
.featured-posts .section-subtitle {
font-family: var(--font-body);
font-size: 1.1rem;
color: var(--text-muted);
line-height: 1.6;
padding-left: var(--spacing-md);
max-width: 600px;
}
.featured-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--spacing-md);
max-width: 1400px;
margin: 0 auto;
}
.featured-card {
background-color: var(--bg-surface);
border: 1.5px solid var(--border);
border-radius: 20px;
overflow: hidden;
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
position: relative;
display: flex;
flex-direction: column;
min-height: 250px !important;
}
.featured-card::before {
content: "";
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
border-radius: 20px;
padding: 2px;
background: linear-gradient(135deg, rgba(186, 18, 77, 0.3) 0%, rgba(0, 63, 82, 0.3) 50%, rgba(186, 18, 77, 0.3) 100%);
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
opacity: 0;
transition: opacity 0.4s ease;
pointer-events: none;
}
.featured-card:hover {
transform: translateY(-6px);
box-shadow: 0 20px 40px -10px rgba(0, 0, 0, 0.15);
}
.featured-card:hover::before { opacity: 1; }
.featured-badge {
position: absolute;
top: var(--spacing-sm);
left: var(--spacing-sm);
background-color: var(--brand-crimson);
color: var(--text-on-accent);
font-family: var(--font-small);
font-size: 0.7rem;
font-weight: 700;
padding: 0.35rem 0.8rem;
border-radius: 999px;
text-transform: uppercase;
letter-spacing: 0.5px;
z-index: 2;
box-shadow: 0 2px 8px rgba(186, 18, 77, 0.3);
}
.featured-image {
position: relative;
overflow: hidden;
aspect-ratio: 16/8;
flex-shrink: 0;
}
.featured-image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s ease;
}
.featured-card:hover .featured-image img { transform: scale(1.05); }
.featured-content {
padding: var(--spacing-md);
display: flex;
flex-direction: column;
gap: var(--spacing-xs);
flex: 1;
}
.featured-meta {
display: flex;
align-items: center;
gap: var(--spacing-sm);
margin-bottom: var(--spacing-xs);
}
.featured-title {
font-family: var(--font-title);
font-style: italic;
font-size: 1.1rem;
color: var(--text-primary);
line-height: 1.2;
margin-bottom: var(--spacing-xs);
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.featured-excerpt {
font-family: var(--font-body);
font-size: 0.8rem;
color: var(--text-muted);
line-height: 1.5;
flex: 1;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
margin-bottom: 0.3rem !important;
}
.featured-footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: var(--spacing-sm);
padding-top: var(--spacing-sm);
border-top: 1px solid var(--border);
}
.reading-time {
font-family: var(--font-small);
font-size: 0.85rem;
color: var(--text-muted);
}
.btn-read {
font-family: var(--font-small);
font-size: 0.9rem;
font-weight: 600;
color: var(--brand-crimson);
text-decoration: none;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
gap: 0.4rem;
}
.btn-read:hover {
transform: translateX(4px);
color: var(--brand-teal);
}
/* ============================================
GRID DE ARTÍCULOS
============================================ */
.blog-grid-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-surface-t3);
}
.blog-grid-section .section-header {
max-width: 1400px;
margin: 0 auto var(--spacing-lg);
text-align: left;
padding-left: var(--spacing-sm);
position: relative;
}
.blog-grid-section .section-header::before {
content: "";
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 4px;
height: 60px;
background: linear-gradient(180deg, var(--brand-teal) 0%, var(--brand-crimson) 100%);
border-radius: 2px;
}
.blog-grid-section .section-title {
font-family: var(--font-title);
font-style: italic;
font-size: clamp(1.2rem, 2vw, 1.8rem);
color: var(--text-primary);
margin-bottom: var(--spacing-xs);
line-height: 1.2;
padding-left: var(--spacing-md);
}
.blog-grid-section .section-subtitle {
font-family: var(--font-body);
font-size: 1.1rem;
color: var(--text-muted);
line-height: 1.6;
padding-left: var(--spacing-md);
max-width: 600px;
}
.blog-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--spacing-md);
max-width: 1400px;
margin: 0 auto;
}
.blog-card {
background-color: var(--bg-base);
border: 1px solid var(--border);
border-radius: 16px;
overflow: hidden;
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
display: flex;
flex-direction: column;
}
.blog-card:hover {
transform: translateY(-6px);
box-shadow: 0 16px 32px -8px rgba(0, 0, 0, 0.12);
border-color: var(--brand-teal);
}
.card-image {
position: relative;
aspect-ratio: 16/10;
overflow: hidden;
}
.card-image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s ease;
}
.blog-card:hover .card-image img { transform: scale(1.08); }
.card-category {
position: absolute;
top: var(--spacing-sm);
left: var(--spacing-sm);
font-family: var(--font-small);
font-size: 0.75rem;
font-weight: 700;
padding: 0.3rem 0.8rem;
border-radius: 999px;
background-color: var(--bg-surface);
color: var(--brand-crimson);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.card-content {
padding: var(--spacing-md);
display: flex;
flex-direction: column;
gap: var(--spacing-xs);
flex: 1;
}
.card-meta {
display: flex;
justify-content: space-between;
align-items: center;
font-family: var(--font-small);
font-size: 0.85rem;
color: var(--text-muted);
}
.reading-time-mini { font-weight: 600; }
.card-title {
font-family: var(--font-title);
font-style: italic;
font-size: 1.2rem;
color: var(--text-primary);
line-height: 1.3;
margin-bottom: var(--spacing-xs);
}
.card-excerpt {
font-family: var(--font-body);
font-size: 0.95rem;
color: var(--text-muted);
line-height: 1.6;
flex: 1;
}
.card-link {
font-family: var(--font-small);
font-size: 0.9rem;
font-weight: 600;
color: var(--brand-crimson);
text-decoration: none;
margin-top: var(--spacing-xs);
display: inline-flex;
align-items: center;
gap: 0.4rem;
transition: all 0.2s ease;
}
.card-link:hover {
color: var(--brand-teal);
gap: 0.6rem;
}
/* Estado vacío */
.empty-state {
text-align: center;
padding: var(--spacing-lg) var(--spacing-md);
grid-column: 1 / -1;
display: none;
}
.empty-state h3 {
font-family: var(--font-title);
font-style: italic;
font-size: 1.5rem;
color: var(--text-primary);
margin-bottom: var(--spacing-xs);
}
.empty-state p {
color: var(--text-muted);
margin-bottom: var(--spacing-md);
max-width: 500px;
margin-left: auto;
margin-right: auto;
}
.load-more-container {
text-align: center;
margin-top: var(--spacing-lg);
}
/* ============================================
RESPONSIVE BLOG
============================================ */
@media (max-width: 1024px) {
.blog-grid, .featured-grid { grid-template-columns: repeat(2, 1fr); }
.featured-card { min-height: 420px; }
}
@media (max-width: 768px) {
.blog-hero-compact { padding: var(--spacing-lg) var(--spacing-sm) var(--spacing-md); }
.blog-filters-section { padding: var(--spacing-sm); }
.filters-top-row { flex-direction: column; align-items: stretch; }
.search-wrapper-compact { max-width: 100%; min-width: 100%; }
.filter-group-compact { justify-content: center; }
.filters-bottom-row { flex-direction: column; align-items: stretch; }
.filter-categories-compact {
overflow-x: auto; flex-wrap: nowrap; -webkit-overflow-scrolling: touch;
scrollbar-width: none; padding-bottom: 4px;
}
.filter-categories-compact::-webkit-scrollbar { display: none; }
.category-btn { flex-shrink: 0; }
.filter-secondary-compact { align-self: flex-end; }
.blog-grid, .featured-grid { grid-template-columns: 1fr; max-width: 500px; }
.featured-card { min-height: auto; }
}
@media (max-width: 480px) {
.blog-hero-compact .hero-compact-title { font-size: 2rem; }
.search-wrapper-compact { padding: 0.4rem 0.4rem 0.4rem 1rem; }
.search-wrapper-compact input { font-size: 0.9rem; }
.filter-btn { font-size: 0.8rem; padding: 0.4rem 0.8rem; }
.featured-title, .card-title { font-size: 1.2rem; }
}
@media (prefers-reduced-motion: reduce) {
.blog-card, .featured-card, .filter-btn, .category-btn, .search-wrapper-compact, .category-tag { transition: none; }
}
+516
View File
@@ -0,0 +1,516 @@
/* ============================================
SECCIÓN HERO DE CONTACTO
============================================ */
.contacto-hero {
min-height: auto;
padding: calc(var(--spacing-lg) + 2rem) var(--spacing-md);
text-align: center;
}
.contacto-hero .hero-title {
font-size: clamp(2.5rem, 5vw, 3.5rem);
}
.icono-whatsapp-btn {
display: inline-block;
width: 18px;
height: 18px;
background-color: currentColor;
-webkit-mask-image: url("../assets/vectores/whatsapp.svg");
mask-image: url("../assets/vectores/whatsapp.svg");
-webkit-mask-size: contain;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-position: center;
mask-position: center;
vertical-align: middle;
margin-right: 6px;
}
/* ============================================
SECCIÓN GRID: INFO + FORMULARIO
============================================ */
.contacto-grid-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-surface-t2);
}
.contacto-grid {
display: grid;
grid-template-columns: 1fr 1.4fr;
gap: var(--spacing-lg);
max-width: 1200px;
margin: 0 auto;
align-items: start;
}
/* --- Columna Info --- */
.contacto-info {
position: sticky;
top: calc(var(--header-height) + var(--spacing-md));
background-color: var(--bg-base);
border: 1px solid var(--border);
border-radius: 20px;
padding: var(--spacing-md);
}
.contacto-info-titulo {
font-family: var(--font-title);
font-style: italic;
font-size: 1.8rem;
color: var(--text-primary);
margin-bottom: var(--spacing-xs);
}
.contacto-info-texto {
font-size: 0.95rem;
color: var(--text-muted);
line-height: 1.6;
margin-bottom: var(--spacing-md);
}
.contacto-canales {
list-style: none;
display: flex;
flex-direction: column;
gap: var(--spacing-sm);
margin-bottom: var(--spacing-md);
}
.canal-item {
display: flex;
align-items: center;
gap: var(--spacing-sm);
padding: var(--spacing-xs);
border-radius: 12px;
transition: background-color 0.25s ease;
}
.canal-item:hover {
background-color: var(--bg-surface-elevated);
}
.canal-icono {
width: 40px;
height: 40px;
flex-shrink: 0;
border-radius: 1px;
-webkit-mask-size: contain;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-position: center;
mask-position: center;
}
.canal-email {
-webkit-mask-image: url("../assets/iconos/buzon.svg");
mask-image: url("../assets/iconos/buzon.svg");
background-color: var(--brand-teal-contraste);
}
.canal-whatsapp {
-webkit-mask-image: url("../assets/logos/whatsapp.svg");
mask-image: url("../assets/logos/whatsapp.svg");
background-color: var(--brand-teal-contraste);
}
.canal-instagram {
-webkit-mask-image: url("../assets/logos/instagram.svg");
mask-image: url("../assets/logos/instagram.svg");
background-color: var(--brand-teal-contraste);
}
.canal-linkedin {
-webkit-mask-image: url("../assets/logos/linkedin.svg");
mask-image: url("../assets/logos/linkedin.svg");
background-color: var(--brand-teal-contraste);
}
.canal-facebook {
-webkit-mask-image: url("../assets/logos/facebook.svg");
mask-image: url("../assets/logos/facebook.svg");
background-color: var(--brand-teal-contraste);
}
.canal-contenido {
display: flex;
flex-direction: column;
gap: 2px;
}
.canal-contenido strong {
font-family: var(--font-small);
font-size: 0.75rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
color: var(--text-muted);
}
.canal-contenido a {
font-size: 0.95rem;
color: var(--text-primary);
font-weight: 500;
transition: color 0.2s ease;
}
.canal-contenido a:hover {
color: var(--brand-crimson);
}
.contacto-horario {
padding-top: var(--spacing-sm);
border-top: 1px solid var(--border);
}
.contacto-horario strong {
font-family: var(--font-small);
font-size: 0.75rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
color: var(--text-muted);
display: block;
margin-bottom: 4px;
}
.contacto-horario p {
font-size: 0.9rem;
color: var(--text-secondary);
}
/* --- Columna Formulario --- */
.contacto-form {
background-color: var(--bg-base);
border: 1px solid var(--border);
border-radius: 20px;
padding: var(--spacing-md);
}
.contacto-form-titulo {
font-family: var(--font-title);
font-style: italic;
font-size: 1.8rem;
color: var(--text-primary);
margin-bottom: var(--spacing-xs);
}
.contacto-form-subtitulo {
font-size: 0.95rem;
color: var(--text-muted);
margin-bottom: var(--spacing-md);
}
.form-row {
display: flex;
flex-direction: column;
gap: var(--spacing-sm);
margin-bottom: var(--spacing-sm);
}
.form-row-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--spacing-sm);
}
.form-group {
display: flex;
flex-direction: column;
gap: 6px;
margin-bottom: var(--spacing-sm);
}
.form-group label {
font-family: var(--font-small);
font-size: 0.85rem;
font-weight: 600;
color: var(--text-primary);
}
.form-required {
color: var(--brand-crimson);
}
.form-group input,
.form-group select,
.form-group textarea {
font-family: var(--font-body);
font-size: 0.95rem;
color: var(--text-primary);
background-color: var(--bg-surface);
border: 1.5px solid var(--border);
border-radius: 10px;
padding: 0.75rem 1rem;
transition: all 0.25s ease;
width: 100%;
}
.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
outline: none;
border-color: var(--brand-crimson);
box-shadow: 0 0 0 3px rgba(186, 18, 77, 0.12);
}
.form-group textarea {
resize: vertical;
min-height: 120px;
}
.form-group select {
cursor: pointer;
appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23170c1d' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 1rem center;
padding-right: 2.5rem;
}
[data-theme="dark"] .form-group select {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23eaf0ee' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
}
.form-consentimiento {
display: flex;
align-items: flex-start;
gap: 10px;
margin: var(--spacing-sm) 0;
padding: var(--spacing-sm);
background-color: var(--bg-surface-elevated);
border-radius: 10px;
}
.form-consentimiento input[type="checkbox"] {
width: 18px;
height: 18px;
margin-top: 2px;
accent-color: var(--brand-crimson);
cursor: pointer;
flex-shrink: 0;
}
.form-consentimiento label {
font-size: 0.85rem;
color: var(--text-muted);
line-height: 1.5;
cursor: pointer;
}
.btn-form-enviar {
width: 100%;
justify-content: center;
padding: 1rem 2rem;
font-size: 1rem;
margin-top: var(--spacing-xs);
}
.form-nota {
text-align: center;
margin-top: var(--spacing-sm);
color: var(--text-muted);
}
/* ============================================
SECCIÓN PROCESO (Qué pasa después)
============================================ */
.proceso-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base-t3);
}
.proceso-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--spacing-md);
max-width: 1100px;
margin: 0 auto;
position: relative;
}
.proceso-grid::before {
content: "";
position: absolute;
top: 40px;
left: 15%;
right: 15%;
height: 2px;
background: linear-gradient(90deg, transparent, var(--border), var(--brand-crimson), var(--border), transparent);
z-index: 0;
}
.proceso-paso {
position: relative;
z-index: 1;
background-color: var(--bg-surface);
border: 1px solid var(--border);
border-radius: 16px;
padding: var(--spacing-md);
text-align: center;
transition: all 0.3s ease;
}
.proceso-paso:hover {
transform: translateY(-4px);
border-color: var(--brand-crimson);
box-shadow: var(--shadow);
}
.proceso-numero {
width: 56px;
height: 56px;
border-radius: 50%;
background-color: var(--bg-surface);
border: 2px solid var(--brand-crimson);
color: var(--brand-crimson);
font-family: var(--font-title);
font-style: italic;
font-weight: 700;
font-size: 1.3rem;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto var(--spacing-sm);
box-shadow: 0 4px 12px -2px rgba(186, 18, 77, 0.2);
}
.proceso-paso h3 {
font-family: var(--font-title);
font-style: italic;
font-size: 1.2rem;
color: var(--text-primary);
margin-bottom: var(--spacing-xs);
}
.proceso-paso p {
font-size: 0.9rem;
color: var(--text-muted);
line-height: 1.6;
}
/* ============================================
SECCIÓN NOTAS IMPORTANTES
============================================ */
.notas-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-surface-t1);
}
.notas-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--spacing-md);
max-width: 1200px;
margin: 0 auto;
}
.nota-item {
padding: var(--spacing-md);
border-left: 3px solid var(--brand-teal);
background-color: var(--bg-base);
border-radius: 0 12px 12px 0;
}
.nota-item strong {
font-family: var(--font-title);
font-style: italic;
font-size: 1.1rem;
color: var(--text-primary);
display: block;
margin-bottom: var(--spacing-xs);
}
.nota-item p {
font-size: 0.9rem;
color: var(--text-muted);
line-height: 1.6;
}
.form-honeypot {
position: absolute;
left: -9999px;
width: 1px;
height: 1px;
overflow: hidden;
}
/* ============================================
RESPONSIVE CONTACTO
============================================ */
@media (max-width: 968px) {
.contacto-grid {
grid-template-columns: 1fr;
gap: var(--spacing-md);
}
.contacto-info {
position: static;
order: 2;
}
.contacto-form {
order: 1;
}
.proceso-grid {
grid-template-columns: 1fr;
max-width: 500px;
}
.proceso-grid::before {
display: none;
}
.notas-container {
grid-template-columns: 1fr;
}
}
@media (max-width: 768px) {
.contacto-hero {
padding: var(--spacing-lg) var(--spacing-sm);
}
.contacto-grid-section,
.proceso-section,
.notas-section {
padding: var(--spacing-md) var(--spacing-sm);
}
.form-row-2 {
grid-template-columns: 1fr;
}
.contacto-form,
.contacto-info {
padding: var(--spacing-sm);
}
.contacto-info-titulo,
.contacto-form-titulo {
font-size: 1.5rem;
}
.btn-form-enviar {
width: 100%;
}
}
@media (max-width: 480px) {
.hero-cta-group {
flex-direction: column;
width: 100%;
}
.hero-cta-group .btn {
width: 100%;
}
}
@media (prefers-reduced-motion: reduce) {
.proceso-paso,
.canal-item,
.form-group input,
.form-group select,
.form-group textarea {
transition: none;
}
}
File diff suppressed because it is too large Load Diff
+906 -1543
View File
File diff suppressed because it is too large Load Diff
+94
View File
@@ -0,0 +1,94 @@
/* ── Modal de contacto ──────────────────────────────────────────────── */
#modal-contacto {
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(20, 18, 15, 0.55);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
opacity: 0;
visibility: hidden;
transition: opacity .35s ease, visibility .35s ease;
z-index: 9999;
padding: 1.5rem;
}
#modal-contacto.is-visible {
opacity: 1;
visibility: visible;
}
#modal-contacto .modal-card {
background: #fff;
color: #1c1a17;
border-radius: 14px;
padding: 2.5rem 2rem;
max-width: 460px;
width: 100%;
text-align: center;
box-shadow: 0 24px 60px rgba(0, 0, 0, .25);
transform: translateY(20px) scale(.97);
transition: transform .35s cubic-bezier(.2, .8, .2, 1);
position: relative;
}
#modal-contacto.is-visible .modal-card {
transform: translateY(0) scale(1);
}
#modal-contacto .modal-icono {
width: 64px;
height: 64px;
border-radius: 50%;
background: #f1ece1;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 1.25rem;
font-size: 1.75rem;
color: #8b7355;
}
#modal-contacto .modal-titulo {
font-size: 1.4rem;
margin: 0 0 .75rem;
letter-spacing: -0.01em;
}
#modal-contacto .modal-mensaje {
font-size: .98rem;
line-height: 1.55;
color: #4a453d;
margin: 0 0 1.75rem;
}
#modal-contacto .modal-cerrar {
display: inline-block;
background: #1c1a17;
color: #fff;
border: none;
padding: .85rem 1.75rem;
border-radius: 999px;
font-size: .95rem;
cursor: pointer;
transition: background .25s ease, transform .25s ease;
font-family: inherit;
}
#modal-contacto .modal-cerrar:hover {
background: #8b7355;
transform: translateY(-1px);
}
/* Variante error */
#modal-contacto.is-error .modal-icono {
background: #fdecec;
color: #c0392b;
}
@media (max-width: 480px) {
#modal-contacto .modal-card { padding: 2rem 1.25rem; }
#modal-contacto .modal-titulo { font-size: 1.2rem; }
}
+747
View File
@@ -0,0 +1,747 @@
/* ============================================
HEADER, MENÚ Y FOOTER (Base)
============================================ */
#menu-container { position: sticky; top: 0; z-index: 100; }
.site-header {
background-color: var(--bg-surface);
border-bottom: 1px solid var(--border);
padding: var(--spacing-sm);
box-shadow: var(--shadow);
transition: transform 0.35s ease, box-shadow 0.35s ease;
}
.site-header.is-hidden { transform: translateY(-100%); box-shadow: none; }
.main-nav { display: flex; justify-content: space-between; align-items: center; max-width: 1400px; margin: 0 auto; }
.logo { display: flex; align-items: center; }
.logo img { height: 40px; width: auto; }
.logo-light { display: block; }
.logo-dark { display: none; }
[data-theme="dark"] .logo-light { display: none; }
[data-theme="dark"] .logo-dark { display: block; }
/* ============================================
COMPONENTES REUTILIZABLES
============================================ */
.btn {
display: inline-block; padding: 0.85rem 2rem; border-radius: 999px;
font-family: var(--font-small); font-weight: 600; font-size: 0.95rem;
text-align: center; cursor: pointer; transition: all 0.3s ease; text-decoration: none;
}
.btn-primary {
background-color: var(--btn-primary-bg); color: var(--text-on-accent);
border: 1.5px solid var(--btn-primary-bg);
box-shadow: 0 4px 14px -3px rgba(186, 18, 77, 0.35);
}
.btn-primary:hover {
background-color: var(--btn-primary-hover); border-color: var(--btn-primary-hover);
color: var(--text-on-accent); transform: translateY(-2px);
box-shadow: 0 6px 20px -3px rgba(186, 18, 77, 0.45);
}
.btn-secondary {
background-color: transparent; color: var(--text-primary);
border: 1.5px solid var(--text-secondary);
}
.btn-secondary:hover {
background-color: var(--bg-surface-elevated); border-color: var(--btn-primary-bg);
color: var(--btn-primary-bg); transform: translateY(-2px);
}
/* ============================================
SECCIÓN HERO (Adaptada para Nosotros)
============================================ */
.hero-section {
min-height: calc(100vh - var(--header-height));
background-color: transparent;
display: flex; align-items: center; justify-content: center;
padding: var(--spacing-lg) var(--spacing-md);
text-align: center;
}
.hero-content {
max-width: 900px; width: 100%;
display: flex; flex-direction: column; align-items: center; gap: var(--spacing-md);
}
.hero-title {
font-family: var(--font-title); font-style: italic; font-weight: 700;
font-size: clamp(2.5rem, 6vw, 4.5rem);
line-height: 1.1; color: var(--text-primary);
opacity: 0; transform: translateY(30px);
animation: fadeInUp 0.9s ease-out 0.2s forwards;
}
.hero-subtitle {
font-family: var(--font-title); font-style: italic; font-weight: 400;
font-size: clamp(1.1rem, 2.5vw, 1.5rem);
line-height: 1.5; color: var(--text-muted);
max-width: 750px;
opacity: 0; transform: translateY(30px);
animation: fadeInUp 0.9s ease-out 0.5s forwards;
}
.hero-cta-group {
display: flex; gap: var(--spacing-sm); flex-wrap: wrap; justify-content: center;
margin-top: var(--spacing-sm);
opacity: 0; transform: translateY(30px);
animation: fadeInUp 0.9s ease-out 0.8s forwards;
}
.badge-filosofia {
display: inline-block; padding: 0.4rem 1rem; border-radius: 999px;
background-color: var(--badge-bg); color: var(--badge-text);
font-family: var(--font-small); font-weight: 600; font-size: 0.85rem;
letter-spacing: 0.5px; text-transform: uppercase; margin-bottom: var(--spacing-xs);
opacity: 0; animation: fadeInUp 0.9s ease-out 0s forwards;
}
@keyframes fadeInUp {
0% { opacity: 0; transform: translateY(30px); }
100% { opacity: 1; transform: translateY(0); }
}
/* ============================================
ESTILOS ESPECÍFICOS: PÁGINA NOSOTROS
============================================ */
/* Encabezados de sección genéricos */
.section-header {
text-align: center; max-width: 800px; margin: 0 auto var(--spacing-lg);
padding: 0 var(--spacing-sm);
}
.section-title {
font-size: clamp(2rem, 4vw, 3rem); color: var(--text-primary);
margin-bottom: var(--spacing-sm); line-height: 1.15;
}
.section-subtitle {
font-family: var(--font-body); font-size: 1.1rem;
color: var(--text-muted); line-height: 1.6;
}
/* --- DUALIDAD --- */
.dualidad-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-surface-t2);
}
.dualidad-grid {
display: grid; grid-template-columns: 1fr 1fr; gap: var(--spacing-md);
max-width: 1200px; margin: 0 auto;
}
.dualidad-card {
background-color: var(--bg-base);
border: 1px solid var(--border);
border-radius: 20px;
padding: var(--spacing-lg) var(--spacing-md);
text-align: center;
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
position: relative;
overflow: hidden;
}
.dualidad-card:hover {
transform: translateY(-5px);
box-shadow: linear-gradient(90deg, var(--brand-crimson), var(--brand-teal));
border-color: var(--brand-rose-muted);
}
.dualidad-card h3 {
font-size: 2.5rem; margin: var(--spacing-sm) 0;
color: var(--text-primary);
}
.card-amor h3 { color: var(--brand-crimson); }
.card-roma h3 { color: var(--brand-teal); }
.card-tag {
display: inline-block; font-family: var(--font-small);
font-size: 0.85rem; font-weight: 700; text-transform: uppercase;
letter-spacing: 1px; color: var(--text-muted); margin-bottom: var(--spacing-sm);
}
.dualidad-card p {
font-size: 1.05rem; color: var(--text-secondary); line-height: 1.7; max-width: 450px; margin: 0 auto;
}
.card-icon {
width: 64px; height: 64px; margin: 0 auto;
background-color: currentColor;
-webkit-mask-size: contain; mask-size: contain;
-webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
-webkit-mask-position: center; mask-position: center;
}
/* Nota: Reemplaza estas URLs con tus iconos reales de amor/corazón y columna/roma */
.icon-amor {
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3E%3Cpath d='M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3E%3Cpath d='M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z'/%3E%3C/svg%3E");
color: var(--brand-crimson);
}
.icon-roma {
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3E%3Cpath d='M12 2L2 22h20L12 2zm0 3.5L18.5 20h-13L12 5.5z'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3E%3Cpath d='M12 2L2 22h20L12 2zm0 3.5L18.5 20h-13L12 5.5z'/%3E%3C/svg%3E");
color: var(--brand-teal);
}
/* --- PRINCIPIOS --- */
.principios-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base-t2);
}
.principios-grid {
display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--spacing-md);
max-width: 1200px; margin: 0 auto;
}
.principio-item {
background-color: var(--bg-surface);
border: 1px solid var(--border);
border-radius: 16px;
padding: var(--spacing-md);
position: relative;
transition: all 0.3s ease;
}
.principio-item:hover {
border-color: var(--brand-teal);
transform: translateY(-3px);
box-shadow: var(--shadow);
}
.principio-numero {
font-family: var(--font-title); font-style: italic;
font-size: 3rem; font-weight: 700; color: var(--brand-rose-muted);
line-height: 1; margin-bottom: var(--spacing-xs);
}
.principio-item h4 {
font-family: var(--font-title); font-style: italic;
font-size: 1.3rem; color: var(--text-primary); margin-bottom: var(--spacing-xs);
}
.principio-item p {
font-size: 0.95rem; color: var(--text-muted); line-height: 1.6;
}
/* ============================================
SECCIÓN CASOS TESTIGO (VERSIÓN SIMÉTRICA)
============================================ */
.casos-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base-t3);
}
.casos-grid-simetrico {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: var(--spacing-md);
max-width: 1200px;
margin: 0 auto;
}
.caso-card {
position: relative;
background-color: var(--bg-surface);
border: 1.5px solid var(--border);
border-radius: 16px;
padding: var(--spacing-md);
display: flex;
flex-direction: column;
gap: var(--spacing-sm);
min-height: 320px;
overflow: hidden; /* recorta la barra en las esquinas */
transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1),
box-shadow 0.4s cubic-bezier(0.16, 1, 0.3, 1),
border-color 0.3s ease;
will-change: transform; /* opcional, para suavizar en hover */
}
.caso-card::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, var(--brand-teal), var(--brand-crimson));
opacity: 0;
transition: opacity 0.3s ease;
pointer-events: none; /* no interfiere con el hover */
z-index: 0;
}
.caso-card > * {
position: relative;
z-index: 1; /* contenido por encima de la barra */
}
.caso-card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 32px -8px rgba(0, 0, 0, 0.12);
border-color: var(--brand-teal);
}
.caso-card:hover::before {
opacity: 1;
}
/* Arquetipo 3 - Insígnia (Destacado pero simétrico) */
.caso-insignia {
border-color: var(--brand-crimson);
background: linear-gradient(135deg, var(--bg-surface) 0%, var(--bg-surface-elevated) 100%);
box-shadow: 0 8px 24px -8px rgba(186, 18, 77, 0.15);
}
.caso-insignia::before {
opacity: 1;
background: linear-gradient(90deg, var(--brand-crimson), var(--brand-rose-muted));
}
.caso-insignia:hover {
box-shadow: 0 16px 40px -10px rgba(186, 18, 77, 0.25);
transform: translateY(-6px);
}
.caso-header {
display: flex;
flex-direction: column;
gap: var(--spacing-xs);
margin-bottom: var(--spacing-xs);
}
.caso-badge {
display: inline-block;
width: fit-content;
font-family: var(--font-small);
font-size: 0.75rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
padding: 0.3rem 0.8rem;
border-radius: 999px;
background-color: var(--badge-bg);
color: var(--badge-text);
}
.caso-badge-insignia {
background-color: var(--brand-crimson);
color: var(--text-on-accent);
box-shadow: 0 2px 8px -2px rgba(186, 18, 77, 0.3);
}
.caso-titulo {
font-family: var(--font-title);
font-style: italic;
font-size: 1.5rem;
color: var(--text-primary);
font-weight: 700;
line-height: 1.2;
}
.caso-descripcion {
font-family: var(--font-body);
font-size: 0.95rem;
color: var(--text-secondary);
line-height: 1.6;
flex: 1;
}
.caso-leccion {
font-family: var(--font-body);
font-size: 0.9rem;
color: var(--text-muted);
line-height: 1.6;
padding: var(--spacing-xs);
padding-left: var(--spacing-sm);
border-left: 3px solid var(--brand-teal);
background-color: var(--bg-surface-elevated);
border-radius: 0 8px 8px 0;
margin-top: auto;
}
.caso-leccion strong {
color: var(--text-primary);
font-family: var(--font-small);
font-weight: 600;
}
.caso-leccion-insignia {
border-left-color: var(--brand-crimson);
background-color: rgba(186, 18, 77, 0.05);
}
/* Responsive */
@media (max-width: 768px) {
.casos-grid-simetrico {
grid-template-columns: 1fr;
max-width: 500px;
}
.caso-card {
min-height: auto;
}
}
@media (max-width: 480px) {
.casos-section {
padding: var(--spacing-md) var(--spacing-sm);
}
.caso-card {
padding: var(--spacing-sm);
}
.caso-titulo {
font-size: 1.3rem;
}
}
/* --- CTA FINAL (Reutiliza y refuerza tu base) --- */
.cta-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base);
}
.cta-card {
max-width: 900px; margin: 0 auto;
background-color: var(--brand-teal);
border-radius: 24px; padding: var(--spacing-lg) var(--spacing-md);
text-align: center; position: relative; overflow: hidden;
box-shadow: 0 20px 60px -10px rgba(0, 63, 82, 0.4);
}
.cta-card::before, .cta-card::after {
content: ""; position: absolute; width: 300px; height: 300px;
border-radius: 50%; filter: blur(80px); opacity: 0.35; pointer-events: none;
}
.cta-card::before { top: -100px; left: -100px; background: radial-gradient(circle, var(--brand-crimson) 0%, transparent 70%); }
.cta-card::after { bottom: -100px; right: -100px; background: radial-gradient(circle, var(--brand-rose-muted) 0%, transparent 70%); }
.cta-title {
font-family: var(--font-title); font-style: italic;
font-size: clamp(2rem, 4vw, 3rem); color: #ffffff;
margin-bottom: var(--spacing-sm); line-height: 1.15; position: relative; z-index: 1;
}
.cta-subtitle {
font-family: var(--font-body); font-size: clamp(1rem, 2vw, 1.15rem);
color: rgba(255, 255, 255, 0.85); max-width: 600px; margin: 0 auto var(--spacing-md);
line-height: 1.6; position: relative; z-index: 1;
}
.cta-buttons {
display: flex; justify-content: center; gap: var(--spacing-sm);
flex-wrap: wrap; position: relative; z-index: 1;
}
.btn-cta-primary {
background-color: #ffffff; color: var(--brand-teal); border: 1.5px solid #ffffff;
padding: 0.85rem 2rem; border-radius: 999px; font-family: var(--font-small);
font-size: 0.95rem; font-weight: 600; cursor: pointer; transition: all 0.3s ease;
box-shadow: 0 4px 14px -3px rgba(0, 0, 0, 0.2);
}
.btn-cta-primary:hover {
background-color: var(--brand-crimson); color: #ffffff; border-color: var(--brand-crimson);
transform: translateY(-2px); box-shadow: 0 6px 20px -3px rgba(186, 18, 77, 0.45);
}
.btn-cta-secondary {
background-color: transparent; color: #ffffff; border: 1.5px solid rgba(255, 255, 255, 0.6);
padding: 0.85rem 2rem; border-radius: 999px; font-family: var(--font-small);
font-size: 0.95rem; font-weight: 600; cursor: pointer; transition: all 0.3s ease;
}
.btn-cta-secondary:hover {
background-color: rgba(255, 255, 255, 0.1); border-color: #ffffff; transform: translateY(-2px);
}
/* ============================================
SECCIÓN TRANSPARENCIA
============================================ */
.transparencia-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base-t2);
}
.transparencia-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--spacing-md);
max-width: 1200px;
margin: 0 auto;
}
.transparencia-card {
background-color: var(--bg-surface);
border: 1px solid var(--border);
border-radius: 20px;
padding: var(--spacing-lg) var(--spacing-md);
text-align: center;
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
position: relative;
overflow: hidden;
}
.transparencia-card::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 4px;
background: linear-gradient(90deg, var(--brand-crimson), var(--brand-teal));
transform: scaleX(0);
transform-origin: left;
transition: transform 0.4s ease;
}
.transparencia-card:hover {
transform: translateY(-8px);
box-shadow: 0 20px 40px -10px rgba(0, 0, 0, 0.15);
border-color: transparent;
}
.transparencia-card:hover::before {
transform: scaleX(1);
}
.transparencia-icono {
width: 80px;
height: 80px;
margin: 0 auto var(--spacing-md);
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background-color: var(--bg-surface-elevated);
border: 2px solid var(--border);
color: var(--text-secondary);
transition: all 0.3s ease;
}
.transparencia-card:hover .transparencia-icono {
border-color: var(--brand-crimson);
color: var(--brand-crimson);
transform: scale(1.1);
}
.transparencia-titulo {
font-family: var(--font-body);
font-size: 0.85rem;
font-weight: 600;
letter-spacing: 2px;
color: var(--text-muted);
margin-bottom: var(--spacing-sm);
}
.transparencia-dato {
font-family: var(--font-title);
font-style: italic;
font-size: clamp(1.5rem, 3vw, 1rem);
font-weight: 500;
color: var(--brand-teal-contraste);
margin-bottom: var(--spacing-sm);
line-height: 1.2;
}
.transparencia-texto {
font-family: var(--font-body);
font-size: 0.95rem;
color: var(--text-muted);
line-height: 1.7;
}
.transparencia-texto strong {
color: var(--text-primary);
font-weight: 500;
}
/* Responsive Transparencia */
@media (max-width: 968px) {
.transparencia-grid {
grid-template-columns: 1fr;
max-width: 500px;
}
.transparencia-card {
padding: var(--spacing-md);
}
}
@media (max-width: 480px) {
.transparencia-section {
padding: var(--spacing-md) var(--spacing-sm);
}
.transparencia-icono {
width: 64px;
height: 64px;
}
.transparencia-dato {
font-size: 1.3rem;
}
}
/* ============================================
SECCIÓN QUIÉNES SOMOS / EQUIPO
============================================ */
.equipo-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: transparent;
}
/* Título con gradiente en la palabra destacada */
.text-gradient {
background: linear-gradient(90deg, var(--brand-crimson) 0%, var(--brand-teal) 100%);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
font-style: italic;
}
.equipo-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: var(--spacing-md);
max-width: 1100px;
margin: 0 auto var(--spacing-md);
}
.equipo-card {
background-color: var(--bg-surface);
border: 1.5px solid var(--border);
border-radius: 20px;
padding: var(--spacing-lg) var(--spacing-md);
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
gap: var(--spacing-sm);
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
position: relative;
overflow: hidden;
min-height: 320px;
justify-content: center;
}
.equipo-card::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: radial-gradient(circle at center, var(--glow-animation) 0%, transparent 70%);
opacity: 0;
transition: opacity 0.5s ease;
pointer-events: none;
}
.equipo-card:hover {
transform: translateY(-6px);
border-color: var(--brand-crimson);
box-shadow: 0 20px 40px -10px rgba(186, 18, 77, 0.2);
}
.equipo-card:hover::before {
opacity: 0.3;
}
/* Firma / Nombre en tipografía script */
.equipo-firma {
font-family: var(--font-signature2);
font-weight: 400;
font-size: clamp(2.2rem, 4vw, 3rem);
color: var(--text-primary);
line-height: 1.1;
margin-bottom: var(--spacing-xs);
}
/* Rol / Especialidad */
.equipo-rol {
font-family: var(--font-small);
font-size: 0.8rem;
font-weight: 700;
letter-spacing: 2.5px;
text-transform: uppercase;
color: var(--text-muted);
padding: 0.4rem 1rem;
border: 1px solid var(--border);
border-radius: 999px;
background-color: var(--bg-surface-elevated);
}
/* Descripción */
.equipo-descripcion {
font-family: var(--font-body);
font-size: 1rem;
color: var(--text-secondary);
line-height: 1.6;
max-width: 380px;
margin-top: var(--spacing-xs);
}
/* Texto final de colaboradores */
.equipo-colaboradores {
text-align: center;
font-family: var(--font-body);
font-size: 1rem;
color: var(--text-muted);
max-width: 700px;
margin: 0 auto;
line-height: 1.6;
font-style: italic;
}
/* Responsive */
@media (max-width: 768px) {
.equipo-grid {
grid-template-columns: 1fr;
max-width: 500px;
}
.equipo-card {
padding: var(--spacing-md);
min-height: auto;
}
.equipo-firma {
font-size: 2.2rem;
}
}
@media (max-width: 480px) {
.equipo-section {
padding: var(--spacing-md) var(--spacing-sm);
}
.equipo-firma {
font-size: 1.9rem;
}
.equipo-rol {
font-size: 0.7rem;
letter-spacing: 1.5px;
}
.equipo-descripcion {
font-size: 0.95rem;
}
}
@media (prefers-reduced-motion: reduce) {
.equipo-card, .equipo-card::before {
transition: none;
}
}
/* ============================================
RESPONSIVE (MEDIA QUERIES)
============================================ */
@media (max-width: 1024px) {
.workflow-grid { grid-template-columns: repeat(3, 1fr); }
.workflow-grid::before { display: none; } /* Ocultar línea en tablet */
}
@media (max-width: 968px) {
.dualidad-grid { grid-template-columns: 1fr; }
.principios-grid { grid-template-columns: 1fr; max-width: 500px; }
.casos-grid { grid-template-columns: 1fr; }
.caso-card.featured { grid-column: span 1; grid-template-columns: 1fr; }
}
@media (max-width: 768px) {
.hero-section { padding: var(--spacing-md) var(--spacing-sm); min-height: auto; padding-top: var(--spacing-lg); padding-bottom: var(--spacing-lg); }
.section-title { font-size: 1.75rem; }
.workflow-grid { grid-template-columns: 1fr; max-width: 400px; margin: 0 auto; }
.workflow-step { flex-direction: row; text-align: left; gap: var(--spacing-sm); align-items: flex-start; }
.step-number { flex-shrink: 0; margin-bottom: 0; width: 40px; height: 40px; font-size: 1rem; }
.cta-buttons { flex-direction: column; align-items: center; }
.btn-cta-primary, .btn-cta-secondary { width: 100%; max-width: 320px; }
}
@media (max-width: 480px) {
.dualidad-card, .principio-item, .caso-card { padding: var(--spacing-sm); }
.dualidad-card h3 { font-size: 2rem; }
}
@media (prefers-reduced-motion: reduce) {
.hero-title, .hero-subtitle, .hero-cta-group, .badge-filosofia { animation: none; opacity: 1; transform: none; }
.dualidad-card, .principio-item, .workflow-step, .caso-card, .btn, .btn-cta-primary, .btn-cta-secondary { transition: none; }
}
+728
View File
@@ -0,0 +1,728 @@
/* ============================================
PLANES - HERO
============================================ */
.planes-hero {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base-t2);
min-height: 70vh;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
position: relative;
overflow: hidden;
}
.planes-hero::before {
content: "";
position: absolute;
top: -50%;
right: -20%;
width: 600px;
height: 600px;
border-radius: 50%;
background: radial-gradient(circle, var(--glow-animation) 0%, transparent 70%);
filter: blur(60px);
opacity: 0.4;
pointer-events: none;
}
.planes-hero-content {
max-width: 800px;
position: relative;
z-index: 1;
}
.planes-hero-tag {
font-family: var(--font-small);
font-size: 0.85rem;
font-weight: 600;
letter-spacing: 1.5px;
text-transform: uppercase;
color: var(--brand-crimson);
display: inline-block;
padding: 0.4rem 1rem;
border: 1px solid var(--brand-crimson);
border-radius: 999px;
margin-bottom: var(--spacing-md);
}
.planes-hero-title {
font-size: clamp(2.2rem, 5vw, 3.5rem);
color: var(--text-primary);
line-height: 1.15;
margin-bottom: var(--spacing-sm);
}
.planes-hero-subtitle {
font-size: clamp(1rem, 2vw, 1.2rem);
color: var(--text-muted);
max-width: 600px;
margin: 0 auto var(--spacing-md);
line-height: 1.6;
}
.planes-hero-cta {
display: inline-block;
}
/* ============================================
PLANES - SELECTOR (TABS + PILLS)
============================================ */
.planes-selector-section {
padding: var(--spacing-sm) var(--spacing-xs);
background-color: var(--bg-surface-t1);
border-top: 1px solid var(--border);
border-bottom: 1px solid var(--border);
}
.planes-selector-container {
max-width: 1200px;
margin: 0 auto;
}
/* Tabs desktop */
.planes-tabs {
display: flex;
justify-content: center;
gap: var(--spacing-xs);
flex-wrap: wrap;
}
.plan-tab {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.4rem;
padding: 0.9rem 1.8rem;
background: transparent;
border: 1.5px solid var(--border);
border-radius: 16px;
cursor: pointer;
font-family: var(--font-small);
font-weight: 600;
color: var(--text-primary);
transition: all 0.3s ease;
min-width: 140px;
}
.plan-tab:hover {
border-color: var(--brand-crimson);
color: var(--brand-crimson);
transform: translateY(-2px);
}
.plan-tab.active {
background-color: var(--brand-crimson);
border-color: var(--brand-crimson);
color: var(--text-on-accent);
box-shadow: 0 4px 14px -3px rgba(186, 18, 77, 0.35);
}
.tab-label {
font-size: 0.95rem;
}
.tab-precio {
font-size: 1.1rem;
font-weight: 700;
}
/* Pills mobile */
.planes-pills {
display: none;
overflow-x: auto;
gap: 0.5rem;
padding-bottom: 0.5rem;
scrollbar-width: none;
}
.planes-pills::-webkit-scrollbar {
display: none;
}
.plan-pill {
flex-shrink: 0;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.3rem;
padding: 0.7rem 1.2rem;
background: var(--bg-surface-elevated);
border: 1.5px solid var(--border);
border-radius: 12px;
cursor: pointer;
font-family: var(--font-small);
font-weight: 600;
color: var(--text-primary);
transition: all 0.3s ease;
}
.plan-pill.active {
background-color: var(--brand-crimson);
border-color: var(--brand-crimson);
color: var(--text-on-accent);
}
.pill-precio {
font-size: 0.9rem;
font-weight: 700;
}
/* ============================================
PLANES - PANEL DE CONTENIDO
============================================ */
.planes-panel-section {
padding: var(--spacing-md) var(--spacing-md);
background-color: transparent;
min-height: 600px;
}
.planes-panel-container {
max-width: 1200px;
margin: 0 auto;
position: relative;
}
.plan-panel {
display: none;
background-color: var(--bg-surface);
border-radius: 16px;
padding: var(--spacing-sm);
box-shadow: var(--shadow);
border: 1px solid var(--border);
animation: slideInPanel 0.5s ease-out;
}
.plan-panel.active {
display: block;
}
@keyframes slideInPanel {
from {
opacity: 0;
transform: translateX(30px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
/* Header del panel */
.panel-header {
margin-bottom: var(--spacing-sm);
padding-bottom: var(--spacing-xs);
border-bottom: 1px solid var(--border);
text-align: center;
}
.panel-categoria {
font-family: var(--font-small);
font-size: 0.7rem;
font-weight: 600;
letter-spacing: 1px;
text-transform: uppercase;
display: inline-block;
padding: 0.3rem 0.8rem;
background-color: var(--badge-bg);
color: var(--badge-text);
border-radius: 999px;
margin-bottom: var(--spacing-xs);
}
.panel-titulo {
font-size: clamp(1.5rem, 3vw, 2rem);
color: var(--text-primary);
margin-bottom: var(--spacing-xs);
line-height: 1.2;
opacity: 0;
animation: fadeInUp 0.6s ease-out 0.1s forwards;
}
.panel-subtitulo {
font-size: 1rem;
color: var(--text-muted);
max-width: 700px;
margin: 0 auto;
line-height: 1.5;
opacity: 0;
animation: fadeInUp 0.6s ease-out 0.2s forwards;
}
/* Grid de Dimensiones */
.panel-grid-dimensiones {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: var(--spacing-sm);
margin-bottom: var(--spacing-xs);
}
.dimension-card {
position: relative; /* Necesario para posicionar el icono decorativo */
background-color: var(--bg-surface-elevated);
border: 1px solid var(--border);
border-radius: 12px;
padding: var(--spacing-sm);
/*padding-top: 3.5rem;*/
transition: all 0.3s ease;
opacity: 0;
animation: fadeInUp 0.6s ease-out 0.3s forwards;
overflow: hidden; /* Para que el icono no se salga */
}
.dimension-card:hover {
border-color: var(--brand-crimson);
transform: translateY(-2px);
box-shadow: var(--shadow);
}
/* Icono decorativo en esquina superior derecha */
.dimension-icon-deco {
position: absolute;
top: 50%;
right: var(--spacing-sm);
transform: translateY(-50%);
width: 80px; /* Más grande para que se vea como marca de agua */
height: 80px;
display: flex;
align-items: center;
justify-content: center;
/* Sin fondo ni border-radius */
background-color: transparent;
opacity: 0.08; /* Muy sutil, casi transparente */
color: var(--brand-crimson);
font-size: 3rem; /* Icono grande */
z-index: 1;
pointer-events: none;
}
/* Título sin icono inline */
.dimension-titulo {
font-family: var(--font-subtitle);
font-size: 1.1rem; /* Un poco más grande ahora que tiene espacio */
color: var(--text-primary);
margin-bottom: var(--spacing-xs);
font-style: italic;
line-height: 1.2;
padding-right: 3.5rem; /* Espacio para que no se superponga con el icono */
}
.dimension-lista {
list-style: none;
display: flex;
flex-direction: column;
gap: 0.35rem;
}
.dimension-lista li {
font-size: 0.85rem;
color: var(--text-primary);
display: flex;
align-items: flex-start;
gap: 0.5rem;
line-height: 1.35;
}
.dimension-lista li i {
flex-shrink: 0;
margin-top: 0.15rem;
font-size: 0.75rem;
}
.dimension-lista .fa-check {
color: var(--btn-secondary-hover);
}
.dimension-lista .fa-times {
color: var(--brand-crimson);
opacity: 0.6;
}
.dimension-lista .fa-info-circle {
color: var(--brand-rose-muted);
}
/* Tarjeta de Precio */
.panel-precio-card {
background: linear-gradient(135deg, var(--brand-teal) 0%, var(--brand-plum) 100%);
border-radius: 12px;
padding: var(--spacing-sm);
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: var(--spacing-sm);
opacity: 0;
animation: fadeInUp 0.6s ease-out 0.5s forwards;
}
.precio-header {
display: flex;
flex-direction: column;
gap: 0.3rem;
}
.precio-label {
font-family: var(--font-small);
font-size: 0.75rem;
color: rgba(255, 255, 255, 0.85);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.precio-valor {
display: flex;
align-items: baseline;
gap: 0.2rem;
color: #ffffff;
}
.precio-moneda {
font-size: 1.2rem;
font-weight: 700;
}
.precio-monto {
font-size: 1.5rem;
font-weight: 700;
font-family: var(--font-title);
}
.precio-periodo {
font-size: 0.9rem;
color: rgba(255, 255, 255, 0.85);
}
.btn-contratar {
padding: 0.7rem 1.8rem;
background-color: #ffffff;
color: var(--brand-teal);
border: none;
border-radius: 999px;
font-weight: 700;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 14px -3px rgba(0, 0, 0, 0.2);
}
.btn-contratar:hover {
background-color: var(--brand-crimson);
color: #ffffff;
transform: translateY(-2px);
box-shadow: 0 6px 20px -3px rgba(186, 18, 77, 0.45);
}
/* ============================================
PLANES - TABLA COMPARATIVA
============================================ */
.planes-comparativa-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: transparent;
}
.comparativa-container {
max-width: 1100px;
margin: 0 auto;
}
.comparativa-header {
text-align: center;
margin-bottom: var(--spacing-md);
}
.comparativa-titulo {
font-size: clamp(1.8rem, 3vw, 2.5rem);
color: var(--text-primary);
margin-bottom: var(--spacing-xs);
}
.comparativa-subtitulo {
font-size: 1.1rem;
color: var(--text-muted);
}
.comparativa-table-wrapper {
overflow-x: auto;
border-radius: 12px;
box-shadow: var(--shadow);
}
.comparativa-table {
width: 100%;
border-collapse: collapse;
background-color: var(--bg-surface);
min-width: 700px;
}
.comparativa-table thead {
background-color: var(--bg-surface-elevated);
}
.comparativa-table th {
padding: var(--spacing-sm) var(--spacing-md);
text-align: center;
font-family: var(--font-small);
font-weight: 700;
color: var(--text-primary);
border-bottom: 2px solid var(--border);
}
.col-caracteristica {
text-align: left;
font-weight: 600;
}
.comparativa-table td {
padding: var(--spacing-sm) var(--spacing-md);
text-align: center;
border-bottom: 1px solid var(--border);
color: var(--text-primary);
}
.caracteristica-nombre {
text-align: left;
font-weight: 500;
}
.comparativa-table .fa-check {
color: var(--brand-teal);
font-size: 1.1rem;
}
.comparativa-table .fa-times {
color: var(--brand-crimson);
opacity: 0.6;
}
.comparativa-table .fa-minus {
color: var(--text-muted);
opacity: 0.5;
}
.row-precio {
background-color: var(--bg-surface-elevated);
font-weight: 700;
}
.precio-celda {
font-family: var(--font-title);
color: var(--brand-crimson);
font-size: 1.1rem;
}
/* ============================================
PLANES - CTA FINAL
============================================ */
.planes-cta {
padding: var(--spacing-lg) var(--spacing-md);
background-color: transparent;
}
.planes-cta-card {
max-width: 900px;
margin: 0 auto;
background-color: var(--brand-teal);
border-radius: 24px;
padding: var(--spacing-lg) var(--spacing-md);
text-align: center;
position: relative;
overflow: hidden;
box-shadow: 0 20px 60px -10px rgba(0, 63, 82, 0.4);
}
.planes-cta-card::before,
.planes-cta-card::after {
content: "";
position: absolute;
width: 300px;
height: 300px;
border-radius: 50%;
filter: blur(80px);
opacity: 0.35;
pointer-events: none;
}
.planes-cta-card::before {
top: -100px;
left: -100px;
background: radial-gradient(circle, var(--brand-crimson) 0%, transparent 70%);
}
.planes-cta-card::after {
bottom: -100px;
right: -100px;
background: radial-gradient(circle, var(--brand-rose-muted) 0%, transparent 70%);
}
.planes-cta-titulo {
font-size: clamp(1.8rem, 3.5vw, 2.5rem);
color: #ffffff;
margin-bottom: var(--spacing-sm);
position: relative;
z-index: 1;
}
.planes-cta-subtitle {
font-size: 1.1rem;
color: rgba(255, 255, 255, 0.85);
max-width: 600px;
margin: 0 auto var(--spacing-md);
position: relative;
z-index: 1;
}
.planes-cta-buttons {
display: flex;
justify-content: center;
gap: var(--spacing-sm);
flex-wrap: wrap;
position: relative;
z-index: 1;
}
.btn-cta-primary {
background-color: #ffffff;
color: var(--brand-teal);
border: 1.5px solid #ffffff;
padding: 0.85rem 2rem;
border-radius: 999px;
font-family: var(--font-small);
font-size: 0.95rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
}
.btn-cta-primary:hover {
background-color: var(--brand-crimson);
color: #ffffff;
border-color: var(--brand-crimson);
transform: translateY(-2px);
}
.btn-cta-secondary {
background-color: transparent;
color: #ffffff;
border: 1.5px solid rgba(255, 255, 255, 0.6);
padding: 0.85rem 2rem;
border-radius: 999px;
font-family: var(--font-small);
font-size: 0.95rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
}
.btn-cta-secondary:hover {
background-color: rgba(255, 255, 255, 0.1);
border-color: #ffffff;
transform: translateY(-2px);
}
/* ============================================
PLANES - CIERRE
============================================ */
.planes-cierre {
height: var(--spacing-md);
}
/* ============================================
RESPONSIVE PLANES
============================================ */
@media (max-width: 968px) {
.panel-grid-dimensiones {
grid-template-columns: 1fr;
}
.panel-precio-card {
flex-direction: column;
text-align: center;
}
}
@media (max-width: 768px) {
.planes-hero {
min-height: 60vh;
padding: var(--spacing-md) var(--spacing-sm);
}
.planes-tabs {
display: none;
}
.planes-pills {
display: flex;
}
.planes-panel-section {
padding: var(--spacing-md) var(--spacing-sm);
}
.plan-panel {
padding: var(--spacing-md);
}
.dimension-card {
padding: var(--spacing-sm);
}
.dimension-icon {
width: 40px;
height: 40px;
font-size: 1.2rem;
}
.precio-monto {
font-size: 2rem;
}
.comparativa-table-wrapper {
border-radius: 8px;
}
.comparativa-table th,
.comparativa-table td {
padding: 0.6rem 0.8rem;
font-size: 0.85rem;
}
.planes-cta-card {
padding: var(--spacing-md) var(--spacing-sm);
}
}
@media (max-width: 480px) {
.planes-hero-title {
font-size: 1.8rem;
}
.plan-panel {
padding: var(--spacing-sm);
}
.panel-titulo {
font-size: 1.5rem;
}
.dimension-titulo {
font-size: 1rem;
}
.precio-monto {
font-size: 1.8rem;
}
}
@media (prefers-reduced-motion: reduce) {
.plan-panel,
.panel-titulo,
.panel-subtitulo,
.dimension-card,
.panel-precio-card {
animation: none;
opacity: 1;
transform: none;
}
}
+23 -25
View File
@@ -3,7 +3,7 @@
============================================ */
.servicios-hero {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base);
background-color: transparent;
min-height: 70vh;
display: flex;
align-items: center;
@@ -71,14 +71,12 @@
============================================ */
.servicios-selector-section {
padding: var(--spacing-md) var(--spacing-sm);
background-color: var(--bg-surface);
background-color: var(--bg-base-t1);
border-top: 1px solid var(--border);
border-bottom: 1px solid var(--border);
}
[data-theme="dark"] .servicios-selector-section {
background-color: rgba(45, 32, 52, 0.95);
}
.servicios-selector-container {
max-width: 1200px;
@@ -194,9 +192,9 @@
SERVICIOS - PANEL DE CONTENIDO
============================================ */
.servicios-panel-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base);
min-height: 600px;
padding: var(--spacing-md) var(--spacing-xs);
background-color: transparent;
min-height: 400px;
}
.servicios-panel-container {
@@ -209,7 +207,7 @@
display: none;
background-color: var(--bg-surface);
border-radius: 20px;
padding: var(--spacing-lg);
padding: var(--spacing-md);
box-shadow: var(--shadow);
border: 1px solid var(--border);
animation: slideInPanel 0.5s ease-out;
@@ -232,8 +230,8 @@
/* icono */
.panel-icono-decorativo {
position: absolute;
top: var(--spacing-lg);
right: var(--spacing-lg);
top: var(--spacing-md);
right: var(--spacing-md);
width: 160px;
height: 160px;
display: flex;
@@ -303,7 +301,7 @@
/* Header del panel */
.panel-header {
margin-bottom: var(--spacing-md);
padding-bottom: var(--spacing-md);
padding-bottom: var(--spacing-xs);
border-bottom: 1px solid var(--border);
}
@@ -318,14 +316,14 @@
background-color: var(--bg-contraste-teal);
color: var(--text-on-accent);
border-radius: 999px;
margin-bottom: var(--spacing-sm);
margin-bottom: var(--spacing-xs);
}
.panel-titulo {
font-size: clamp(1.8rem, 3.5vw, 2.5rem);
color: var(--text-primary);
margin-bottom: var(--spacing-xs);
line-height: 1.2;
margin-bottom: var(--spacing-md);
line-height: 1;
opacity: 0;
animation: fadeInUp 0.6s ease-out 0.1s forwards;
}
@@ -334,7 +332,7 @@
font-size: 1.1rem;
color: var(--text-muted);
max-width: 700px;
line-height: 1.6;
line-height: 1.4;
opacity: 0;
animation: fadeInUp 0.6s ease-out 0.2s forwards;
}
@@ -343,8 +341,8 @@
.panel-body {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--spacing-md);
margin-bottom: var(--spacing-md);
gap: var(--spacing-xs);
margin-bottom: var(--spacing-xs);
}
.panel-columna {
@@ -400,10 +398,10 @@
display: flex;
justify-content: space-between;
align-items: center;
padding-top: var(--spacing-md);
padding-top: var(--spacing-xs);
border-top: 1px solid var(--border);
flex-wrap: wrap;
gap: var(--spacing-sm);
gap: var(--spacing-xs);
opacity: 0;
animation: fadeInUp 0.6s ease-out 0.5s forwards;
}
@@ -462,7 +460,7 @@
============================================ */
.servicios-casos {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base);
background-color: var(--bg-base-t2);
}
.servicios-casos-container {
@@ -510,11 +508,11 @@
.caso-tag {
font-family: var(--font-small);
font-size: 0.7rem;
font-weight: 600;
font-size: 0.85rem;
font-weight: 500;
letter-spacing: 0.5px;
text-transform: uppercase;
color: var(--brand-teal);
color: #006d8f;
display: inline-block;
margin-bottom: var(--spacing-xs);
}
@@ -537,7 +535,7 @@
============================================ */
.servicios-cta {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base);
background-color: transparent;
}
.servicios-cta-card {
+3
View File
@@ -0,0 +1,3 @@
<?php
echo "¡PHP funciona!";
?>
+76
View File
@@ -0,0 +1,76 @@
<?php
/**
* Funciones de sanitización y validación reutilizables.
*/
function limpiar_texto($valor, $max = 500) {
$valor = trim((string)$valor);
$valor = strip_tags($valor);
$valor = preg_replace('/[\r\n\t]+/', ' ', $valor);
if (mb_strlen($valor) > $max) {
$valor = mb_substr($valor, 0, $max);
}
return $valor;
}
function limpiar_mensaje($valor, $max = 5000) {
$valor = trim((string)$valor);
$valor = strip_tags($valor);
if (mb_strlen($valor) > $max) {
$valor = mb_substr($valor, 0, $max);
}
return $valor;
}
function limpiar_email($valor) {
return filter_var(trim((string)$valor), FILTER_SANITIZE_EMAIL);
}
function email_valido($valor) {
return (bool) filter_var($valor, FILTER_VALIDATE_EMAIL);
}
function en_lista($valor, array $permitidos) {
return in_array($valor, $permitidos, true) ? $valor : '';
}
/**
* Valida los datos del formulario y devuelve
* ['ok' => bool, 'errores' => [], 'datos' => []]
*/
function validar_contacto(array $post) {
$errores = [];
$datos = [
'nombre' => limpiar_texto($post['nombre'] ?? '', 120),
'empresa' => limpiar_texto($post['empresa'] ?? '', 120),
'email' => limpiar_email($post['email'] ?? ''),
'telefono' => limpiar_texto($post['telefono'] ?? '', 40),
'servicio' => en_lista($post['servicio'] ?? '', [
'branding','web','rrss','automatizaciones','paid','ecosistema','otro'
]),
'etapa' => en_lista($post['etapa'] ?? '', [
'idea','inicio','marcha','redisenio','escalar'
]),
'presupuesto' => en_lista($post['presupuesto'] ?? '', [
'esencial','impulso','premium','elite','proyecto','no-se'
]),
'mensaje' => limpiar_mensaje($post['mensaje'] ?? '', 5000),
'origen' => en_lista($post['origen'] ?? '', [
'instagram','linkedin','referido','google','otro'
]),
'consentimiento'=> !empty($post['consentimiento']),
];
if ($datos['nombre'] === '') $errores[] = 'El nombre es obligatorio.';
if (!email_valido($datos['email'])) $errores[] = 'El email no es válido.';
if ($datos['servicio'] === '') $errores[] = 'Seleccioná un servicio de interés.';
if ($datos['mensaje'] === '') $errores[] = 'El mensaje es obligatorio.';
if (!$datos['consentimiento']) $errores[] = 'Debés aceptar el uso de tus datos.';
return [
'ok' => empty($errores),
'errores' => $errores,
'datos' => $datos,
];
}
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<!-- Eliminamos el bloque <handlers> manual para que no choque con DonWeb -->
<!-- 1. DOCUMENTO PREDETERMINADO -->
<defaultDocument>
<files>
<clear />
<add value="index.php" />
<add value="index.html" />
</files>
</defaultDocument>
<!-- 2. MODO DETALLADO PARA DIAGNÓSTICO -->
<httpErrors errorMode="Detailed" />
</system.webServer>
</configuration>