Compare commits

..
6 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
45 changed files with 10963 additions and 1197 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.

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 -->
+29 -250
View File
@@ -4,29 +4,32 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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: HERO COMPACTO -->
<section class="blog-hero-compact">
<!-- HERO -->
<section class="blog-hero-compact">
<div class="hero-compact-content">
<span class="badge-filosofia"></span>
<h1 class="hero-compact-title">Ideas que construyen marcas</h1>
<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">
Estrategia, diseño y tecnología explicados sin tecnicismos innecesarios.
Consejos prácticos de branding, web y marketing digital para hacer crecer tu negocio con esencia y estructura.
</p>
</div>
</section>
</section>
<!-- SECCIÓN 2: HEADER DE FILTROS (STICKY CON BUSCADOR) -->
<section class="blog-filters-header" id="blog-filters-header">
<div class="filters-header-container">
<!-- Fila superior: Buscador + Filtros principales -->
<!-- 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">
@@ -35,13 +38,7 @@
<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"
>
<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"/>
@@ -55,7 +52,6 @@
</div>
</div>
<!-- Fila inferior: Categorías + Ordenamiento -->
<div class="filters-bottom-row">
<div class="filter-categories-compact">
<button class="category-btn active" data-category="all">Todas</button>
@@ -72,237 +68,38 @@
<select id="sort-select" class="sort-select-compact">
<option value="recent">Más recientes</option>
<option value="popular">Más populares</option>
<option value="alphabetical">A-Z</option>
</select>
</div>
</div>
<!-- Info de resultados -->
<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>
</section>
<!-- SECCIÓN 3: ARTÍCULOS DESTACADOS -->
<section class="featured-posts" id="featured-posts">
<!-- 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>
<div class="featured-grid">
<!-- Artículo destacado 1 -->
<article class="featured-card" data-categories="branding estrategia" data-tags="identidad, marca, posicionamiento" data-featured="true">
<div class="featured-image">
<img src="../assets/blog/branding-completo.jpg" alt="Guía completa de branding">
<span class="featured-badge">Más leído</span>
</div>
<div class="featured-content">
<div class="featured-meta">
<span class="category-tag branding">Branding</span>
<time datetime="2024-01-15">15 Ene 2024</time>
</div>
<h3 class="featured-title">Guía completa: Cómo construir una identidad de marca que perdure</h3>
<p class="featured-excerpt">
Desde el diagnóstico inicial hasta el manual de identidad. Todo lo que necesitás saber para crear una marca con esencia y solidez estratégica.
</p>
<div class="featured-footer">
<span class="reading-time">⏱ 12 min de lectura</span>
<a href="#" class="btn-read">Leer artículo →</a>
</div>
</div>
</article>
<!-- Artículo destacado 2 -->
<article class="featured-card" data-categories="web" data-tags="landing page, conversión, diseño" data-featured="true">
<div class="featured-image">
<img src="../assets/blog/landing-page.jpg" alt="Landing pages">
</div>
<div class="featured-content">
<div class="featured-meta">
<span class="category-tag web">Web</span>
<time datetime="2024-01-10">10 Ene 2024</time>
</div>
<h3 class="featured-title">Landing pages que convierten: 7 principios probados</h3>
<p class="featured-excerpt">
Estructura, copy y diseño working together para transformar visitantes en clientes reales.
</p>
<div class="featured-footer">
<span class="reading-time">⏱ 8 min de lectura</span>
<a href="#" class="btn-read">Leer artículo →</a>
</div>
</div>
</article>
<!-- Artículo destacado 3 -->
<article class="featured-card" data-categories="automatizaciones" data-tags="instagram, chatbots, leads" data-featured="true">
<div class="featured-image">
<img src="../assets/blog/automatizacion.jpg" alt="Automatizaciones">
</div>
<div class="featured-content">
<div class="featured-meta">
<span class="category-tag automatizaciones">Automatizaciones</span>
<time datetime="2024-01-05">5 Ene 2024</time>
</div>
<h3 class="featured-title">Automatizaciones en Instagram: de 0 a 100 leads/mes</h3>
<p class="featured-excerpt">
Flujos inteligentes que trabajan 24/7 mientras vos te enfocás en lo que mejor sabés hacer.
</p>
<div class="featured-footer">
<span class="reading-time"> 9 min de lectura</span>
<a href="#" class="btn-read">Leer artículo →</a>
</div>
</div>
</article>
</div>
</section>
<!-- SECCIÓN 4: GRID DE ARTÍCULOS -->
<!-- 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">
<!-- ARTÍCULO 1 -->
<article class="blog-card" data-categories="redes estrategia" data-tags="contenido, planificación, calendario" data-featured="false">
<div class="card-image">
<img src="../assets/blog/contenido-redes.jpg" alt="Contenido para redes">
<span class="card-category redes">Redes</span>
</div>
<div class="card-content">
<div class="card-meta">
<time datetime="2024-01-20">20 Ene 2024</time>
<span class="reading-time-mini">8 min</span>
</div>
<h3 class="card-title">Planificación de contenido: el método de los 3 pilares</h3>
<p class="card-excerpt">
Cómo estructurar tu calendario editorial para mantener coherencia sin volverte loco.
</p>
<div class="card-tags">
<span class="tag">Contenido</span>
<span class="tag">Planificación</span>
</div>
<a href="#" class="card-link">Leer artículo</a>
</div>
</article>
<!-- ARTÍCULO 2 -->
<article class="blog-card" data-categories="branding" data-tags="logo, identidad, diseño" data-featured="false">
<div class="card-image">
<img src="../assets/blog/logo-design.jpg" alt="Diseño de logo">
<span class="card-category branding">Branding</span>
</div>
<div class="card-content">
<div class="card-meta">
<time datetime="2024-01-18">18 Ene 2024</time>
<span class="reading-time-mini">6 min</span>
</div>
<h3 class="card-title">Tu logo no es tu marca (y por qué importa)</h3>
<p class="card-excerpt">
La diferencia entre un símbolo bonito y una identidad estratégica que realmente funciona.
</p>
<div class="card-tags">
<span class="tag">Logo</span>
<span class="tag">Identidad</span>
</div>
<a href="#" class="card-link">Leer artículo</a>
</div>
</article>
<!-- ARTÍCULO 3 -->
<article class="blog-card" data-categories="web paid" data-tags="seo, google ads, tráfico" data-featured="false">
<div class="card-image">
<img src="../assets/blog/seo-web.jpg" alt="SEO">
<span class="card-category web">Web</span>
</div>
<div class="card-content">
<div class="card-meta">
<time datetime="2024-01-12">12 Ene 2024</time>
<span class="reading-time-mini">10 min</span>
</div>
<h3 class="card-title">SEO vs Paid Media: cuándo usar cada uno</h3>
<p class="card-excerpt">
No son enemigos, son complementarios. Te explicamos cómo combinarlos estratégicamente.
</p>
<div class="card-tags">
<span class="tag">SEO</span>
<span class="tag">Google Ads</span>
</div>
<a href="#" class="card-link">Leer artículo</a>
</div>
</article>
<!-- ARTÍCULO 4 -->
<article class="blog-card" data-categories="casos estrategia" data-tags="caso de éxito, tecnología, ecosistema" data-featured="false">
<div class="card-image">
<img src="../assets/blog/caso-tech.jpg" alt="Caso de éxito">
<span class="card-category casos">Casos</span>
</div>
<div class="card-content">
<div class="card-meta">
<time datetime="2024-01-08">8 Ene 2024</time>
<span class="reading-time-mini">7 min</span>
</div>
<h3 class="card-title">Caso de éxito: Ecosistema digital para startup tech</h3>
<p class="card-excerpt">
Cómo construimos una presencia integral desde cero: branding, web y redes en 90 días.
</p>
<div class="card-tags">
<span class="tag">Caso de Éxito</span>
<span class="tag">Tecnología</span>
</div>
<a href="#" class="card-link">Leer artículo</a>
</div>
</article>
<!-- ARTÍCULO 5 -->
<article class="blog-card" data-categories="automatizaciones redes" data-tags="manychat, instagram, ventas" data-featured="false">
<div class="card-image">
<img src="../assets/blog/chatbot.jpg" alt="Chatbot">
<span class="card-category automatizaciones">Automatizaciones</span>
</div>
<div class="card-content">
<div class="card-meta">
<time datetime="2024-01-03">3 Ene 2024</time>
<span class="reading-time-mini">9 min</span>
</div>
<h3 class="card-title">Chatbots que no parecen robots: la clave está en el copy</h3>
<p class="card-excerpt">
Cómo escribir flujos de conversación que suenen humanos y realmente vendan.
</p>
<div class="card-tags">
<span class="tag">ManyChat</span>
<span class="tag">Ventas</span>
</div>
<a href="#" class="card-link">Leer artículo</a>
</div>
</article>
<!-- ARTÍCULO 6 -->
<article class="blog-card" data-categories="estrategia branding" data-tags="posicionamiento, competencia, diferenciación" data-featured="false">
<div class="card-image">
<img src="../assets/blog/posicionamiento.jpg" alt="Posicionamiento">
<span class="card-category estrategia">Estrategia</span>
</div>
<div class="card-content">
<div class="card-meta">
<time datetime="2023-12-28">28 Dic 2023</time>
<span class="reading-time-mini">11 min</span>
</div>
<h3 class="card-title">Posicionamiento: cómo destacar en un mercado saturado</h3>
<p class="card-excerpt">
Estrategias prácticas para encontrar tu espacio único y volverte inolvidable.
</p>
<div class="card-tags">
<span class="tag">Posicionamiento</span>
<span class="tag">Diferenciación</span>
</div>
<a href="#" class="card-link">Leer artículo</a>
</div>
</article>
<!-- JS inyecta las tarjetas aquí -->
</div>
<!-- ESTADO VACÍO (cuando no hay resultados) -->
<div class="empty-state" id="empty-state" style="display: none;">
<div class="empty-icon">🔍</div>
<h3>No encontramos artículos con esos filtros</h3>
@@ -310,34 +107,16 @@
<button class="btn btn-primary" id="empty-reset">Ver todos los artículos</button>
</div>
<!-- PAGINACIÓN / CARGAR MÁS -->
<div class="load-more-container">
<button class="btn btn-secondary" id="load-more">Cargar más artículos</button>
</div>
</section>
<!-- SECCIÓN 5: NEWSLETTER -->
<section class="newsletter-section">
<div class="newsletter-card">
<div class="newsletter-content">
<h2 class="newsletter-title">Ideas frescas en tu inbox</h2>
<p class="newsletter-subtitle">
Suscribite y recibí nuestras mejores estrategias de branding, web y marketing digital.
Sin spam, solo contenido de valor.
</p>
</div>
<form class="newsletter-form" id="newsletter-form">
<button type="submit" class="btn btn-primary">Tu email profesional</button>
<button type="submit" class="btn btn-primary">Suscribirme</button>
</form>
</div>
</section>
</main>
<div id="footer-container"></div>
<script src="scripts/main.js"></script>
<script src="scripts/blog.js"></script>
<link rel="stylesheet" href="style/blog.css">
<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);
+32 -6
View File
@@ -4,10 +4,17 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
@@ -45,14 +52,14 @@
<span class="canal-icono canal-email"></span>
<div class="canal-contenido">
<strong>Email</strong>
<a href="mailto:contacto@amoryroma.com">hola@amoryroma.com</a>
<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 11 0000-0000</a>
<a href="https://wa.me/543886118304" target="_blank" rel="noopener">+54 9 388 6118304</a>
</div>
</li>
<li class="canal-item">
@@ -69,6 +76,13 @@
<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>
<div class="contacto-horario">
@@ -174,6 +188,11 @@
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
@@ -238,19 +257,26 @@
<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://calendly.com/amoryroma" 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-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>
<link rel="stylesheet" href="style/contacto.css">
<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="inicio.html#portfolio">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>
+17 -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,12 +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#metodologia">Método A&R</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>
@@ -48,7 +48,7 @@
<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>-->
@@ -69,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">
@@ -81,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>
+10 -4
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>
@@ -531,6 +536,7 @@
<div id="footer-container"></div>
<script src="scripts/main.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
+15 -11
View File
@@ -5,18 +5,22 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
<!-- SECCIÓN 1: HERO / FILOSOFÍA -->
<section class="hero-section nosotros-hero">
<div class="hero-content">
<h1 class="hero-title">Amor & Roma</h1>
<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>
@@ -38,13 +42,13 @@
<div class="card-icon icon-amor"></div>
<h3>Amor</h3>
<span class="card-tag">La Pasión y el Arte</span>
<p>Representa la chispa creativa, 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. Es el alma y la identidad de cada marca.</p>
<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, la solidez, la ingeniería de procesos, la estrategia a largo plazo y la infraestructura digital orientada a resultados. Es el imperio que sostiene esa visión.</p>
<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>
@@ -77,8 +81,7 @@
</div>
<p class="equipo-colaboradores">
Como todo equipo en crecimiento, sumamos colaboradores según el proyecto — diseñadores, redactores y especialistas que se suman cuando hace falta.
</p>
Trabajamos en equipo ayudando a las PyMEs a competir y crecer. </p>
</section>
<!-- SECCIÓN 3: PRINCIPIOS BOUTIQUE -->
@@ -125,7 +128,7 @@
<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> (Esencial) hasta <strong>$1.000.000</strong> (Élite). El armado inicial —branding, sitio web— se presupuesta por proyecto.
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>
@@ -172,7 +175,7 @@
<!-- ARQUETIPO 1 -->
<article class="caso-card">
<div class="caso-header">
<span class="caso-badge">Arquetipo 1</span>
<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>
@@ -184,7 +187,7 @@
<!-- ARQUETIPO 2 -->
<article class="caso-card">
<div class="caso-header">
<span class="caso-badge">Arquetipo 2</span>
<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>
@@ -196,7 +199,7 @@
<!-- ARQUETIPO 3 (INSÍGNIA) -->
<article class="caso-card caso-insignia">
<div class="caso-header">
<span class="caso-badge caso-badge-insignia">Arquetipo 3 (Insígnia)</span>
<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>
@@ -208,7 +211,7 @@
<!-- ARQUETIPO 4 -->
<article class="caso-card">
<div class="caso-header">
<span class="caso-badge">Arquetipo 4</span>
<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>
@@ -226,7 +229,7 @@
<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="inicio.html#portfolio" class="btn btn-cta-secondary">Ver Casos de Éxito</a>
<a href="index.html#portfolio" class="btn btn-cta-secondary">Ver Casos de Éxito</a>
</div>
</div>
</section>
@@ -235,5 +238,6 @@
<div id="footer-container"></div>
<script src="scripts/main.js"></script>
<script src="scripts/fluid.js"></script>
</body>
</html>
+7 -2
View File
@@ -6,12 +6,16 @@
<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>
@@ -489,10 +493,10 @@
<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">Hablamos contigo y te recomendamos el plan ideal según tus objetivos y presupuesto.</p>
<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="inicio.html#diagnostico" class="btn btn-cta-secondary">Hacé el diagnóstico</a>
<a href="index.html#diagnostico" class="btn btn-cta-secondary">Hacé el diagnóstico</a>
</div>
</div>
</section>
@@ -505,5 +509,6 @@
<script src="scripts/main.js"></script>
<script src="scripts/planes.js"></script>
<script src="scripts/fluid.js"></script>
</body>
</html>
+213 -146
View File
@@ -1,185 +1,252 @@
document.addEventListener('DOMContentLoaded', () => {
console.log('Blog JS cargado');
document.addEventListener('DOMContentLoaded', async () => {
const GHOST_API_URL = 'https://blog.amoryroma.com.ar';
const GHOST_API_KEY = '82450ba91ca6b5b9628006eec4';
const searchInput = document.getElementById('blog-search');
const searchClear = document.getElementById('search-clear');
// Elementos del DOM
const featuredSection = document.getElementById('featured-posts');
const featuredGrid = document.getElementById('featured-grid');
const blogGrid = document.getElementById('blog-grid');
const emptyState = document.getElementById('empty-state');
const loadMoreBtn = document.getElementById('load-more');
const resultsCount = document.getElementById('results-count');
const filtersHeader = document.getElementById('blog-filters-header');
const emptyState = document.getElementById('empty-state');
const gridSectionTitle = document.getElementById('grid-section-title');
const gridSectionSubtitle = document.getElementById('grid-section-subtitle');
if (!searchInput || !blogGrid) {
console.error('Faltan elementos del DOM');
return;
}
let currentFilters = {
search: '',
// Estado de los filtros
let posts = [];
let state = {
category: 'all',
featured: 'all',
filter: 'all', // 'all' o 'destacados'
search: '',
sort: 'recent'
};
// ===== EFECTO SCROLL EN FILTROS =====
window.addEventListener('scroll', () => {
if (window.scrollY > 100) {
filtersHeader.classList.add('is-scrolled');
// 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 {
filtersHeader.classList.remove('is-scrolled');
// 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();
});
});
// ===== BUSCADOR =====
// 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) => {
const value = e.target.value.trim();
currentFilters.search = value;
if (searchClear) {
searchClear.classList.toggle('visible', value.length > 0);
}
filterArticles();
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');
currentFilters.search = '';
filterArticles();
searchInput.focus();
renderPosts();
}
});
}
// ===== FILTROS PRINCIPALES =====
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentFilters.featured = btn.dataset.filter;
filterArticles();
});
});
// ===== CATEGORÍAS =====
document.querySelectorAll('.category-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.category-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentFilters.category = btn.dataset.category;
filterArticles();
});
});
// ===== ORDENAMIENTO =====
// 4. Ordenamiento
const sortSelect = document.getElementById('sort-select');
if (sortSelect) {
sortSelect.addEventListener('change', (e) => {
currentFilters.sort = e.target.value;
sortArticles();
state.sort = e.target.value;
renderPosts();
});
}
// ===== RESET =====
const resetFilters = document.getElementById('reset-filters');
if (resetFilters) {
resetFilters.addEventListener('click', () => {
currentFilters = { search: '', category: 'all', featured: 'all', sort: 'recent' };
searchInput.value = '';
searchClear?.classList.remove('visible');
// 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');
document.querySelectorAll('.category-btn').forEach(b => b.classList.remove('active'));
document.querySelector('.category-btn[data-category="all"]')?.classList.add('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';
filterArticles();
});
renderPosts();
}
// ===== FUNCIÓN DE FILTRADO =====
const filterArticles = () => {
const articles = document.querySelectorAll('.blog-card, .featured-card');
let visibleCount = 0;
articles.forEach(article => {
const categories = article.dataset.categories || '';
const tags = article.dataset.tags || '';
const isFeatured = article.dataset.featured === 'true';
const title = article.querySelector('.card-title, .featured-title')?.textContent.toLowerCase() || '';
const excerpt = article.querySelector('.card-excerpt, .featured-excerpt')?.textContent.toLowerCase() || '';
const searchTerm = currentFilters.search.toLowerCase();
const matchSearch = searchTerm === '' ||
title.includes(searchTerm) ||
excerpt.includes(searchTerm) ||
categories.toLowerCase().includes(searchTerm) ||
tags.toLowerCase().includes(searchTerm);
const matchCategory = currentFilters.category === 'all' ||
categories.toLowerCase().includes(currentFilters.category.toLowerCase());
let matchFeatured = true;
if (currentFilters.featured === 'destacados') {
matchFeatured = isFeatured;
if (resetBtn) resetBtn.addEventListener('click', resetAll);
if (emptyReset) emptyReset.addEventListener('click', resetAll);
}
if (matchSearch && matchCategory && matchFeatured) {
article.style.display = '';
visibleCount++;
} else {
article.style.display = 'none';
}
});
sortArticles();
updateResultsCount(visibleCount);
if (emptyState) {
emptyState.style.display = visibleCount === 0 ? 'block' : 'none';
}
};
const sortArticles = () => {
const articles = Array.from(document.querySelectorAll('.blog-card'));
const container = blogGrid;
switch(currentFilters.sort) {
case 'recent':
articles.sort((a, b) => {
const dateA = new Date(a.querySelector('time')?.datetime || 0);
const dateB = new Date(b.querySelector('time')?.datetime || 0);
return dateB - dateA;
});
break;
case 'alphabetical':
articles.sort((a, b) => {
const titleA = a.querySelector('.card-title')?.textContent || '';
const titleB = b.querySelector('.card-title')?.textContent || '';
return titleA.localeCompare(titleB);
});
break;
}
articles.forEach(article => container.appendChild(article));
};
const updateResultsCount = (count) => {
if (!resultsCount) return;
if (count === 0) {
resultsCount.innerHTML = 'No se encontraron artículos';
} else if (currentFilters.category === 'all' && currentFilters.search === '') {
resultsCount.innerHTML = `Mostrando <strong>${count}</strong> artículos`;
} else {
resultsCount.innerHTML = `Mostrando <strong>${count}</strong> artículo${count !== 1 ? 's' : ''}`;
}
};
// Inicializar
filterArticles();
// 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;
}
}
});
})();
+167 -215
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,26 +146,52 @@ 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); }"
);
// ===== 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); }"
);
// 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(
@@ -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,25 +338,31 @@ 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++;
@@ -407,20 +381,22 @@ document.addEventListener("mousemove", function (e) {
pointers[0].down = true;
pointers[0].color = colorArr;
pointers[0].moved = pointers[0].down;
pointers[0].moved = true;
// Aplicar multiplicador diferente según si estamos sobre texto o no
const multiplier = overText ? 8 : 10.0; // Reducido a 4x sobre texto (vs 10x)
const multiplier = overText ? 8.0 : 10.0;
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].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) {
window.addEventListener("mouseleave", function () {
isFirstMove = true;
pointers[0].moved = false;
});
canvas.addEventListener("touchmove", function (e) {
e.preventDefault();
let touches = e.targetTouches;
count++;
@@ -437,23 +413,23 @@ canvas.addEventListener(
count = 0;
}
const rect = canvas.getBoundingClientRect();
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;
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
);
}, 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();
});
+10 -5
View File
@@ -6,10 +6,14 @@
<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>
@@ -18,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>
@@ -254,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>
@@ -263,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">
@@ -304,7 +308,7 @@
<h2 class="servicios-cta-titulo">¿No sabés cuál servicio necesitás?</h2>
<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>
@@ -318,5 +322,6 @@
<script src="scripts/main.js"></script>
<script src="scripts/servicios.js"></script>
<script src="scripts/fluid.js"></script>
</body>
</html>
+103 -346
View File
@@ -3,7 +3,7 @@
============================================ */
.blog-hero-compact {
padding: calc(var(--spacing-lg) + 2rem) var(--spacing-md) var(--spacing-lg);
background-color: var(--bg-base);
background-color: transparent;
text-align: center;
position: relative;
}
@@ -54,13 +54,12 @@
}
/* ============================================
SECCIÓN FILTROS Y BUSCADOR (INTEGRADOS, NO STICKY)
SECCIÓN FILTROS Y BUSCADOR
============================================ */
.blog-filters-section {
padding: var(--spacing-md) var(--spacing-md);
background-color: var(--bg-surface);
border-bottom: 1px solid var(--border);
position: relative; /* Sin sticky, fluye normal */
background-color: var(--bg-surface-t0);
position: relative;
z-index: 1;
}
@@ -69,18 +68,18 @@
margin: 0 auto;
display: flex;
flex-direction: column;
align-items: center;
gap: var(--spacing-sm);
}
/* Fila superior: Buscador + Filtros principales */
.filters-top-row {
display: flex;
gap: var(--spacing-sm);
align-items: center;
justify-content: center;
flex-wrap: wrap;
}
/* Buscador con forma redondeada (pill) */
.search-wrapper-compact {
flex: 1;
min-width: 280px;
@@ -90,7 +89,7 @@
align-items: center;
background-color: var(--bg-base);
border: 1.5px solid var(--border);
border-radius: 999px; /* Forma redondeada como los botones */
border-radius: 999px;
padding: 0.5rem 0.5rem 0.5rem 1.1rem;
transition: all 0.3s ease;
}
@@ -148,7 +147,6 @@
justify-content: center;
}
/* Filtros principales (Todos / Destacados) */
.filter-group-compact {
display: flex;
gap: 0.5rem;
@@ -180,10 +178,9 @@
color: var(--text-on-accent);
}
/* Fila inferior: Categorías + Ordenamiento */
.filters-bottom-row {
display: flex;
justify-content: space-between;
justify-content: center;
align-items: center;
gap: var(--spacing-sm);
flex-wrap: wrap;
@@ -195,7 +192,7 @@
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
flex: 1;
justify-content: center;
}
.category-btn {
@@ -247,11 +244,11 @@
border-color: var(--brand-teal);
}
/* Info de resultados */
.results-info-compact {
display: flex;
justify-content: space-between;
justify-content: center;
align-items: center;
gap: var(--spacing-sm);
font-family: var(--font-small);
font-size: 0.85rem;
color: var(--text-muted);
@@ -276,7 +273,7 @@
}
/* ============================================
TAGS CON MEJOR CONTRASTE (UNIFICADO)
TAGS DE CATEGORÍAS
============================================ */
.category-tag {
font-family: var(--font-small);
@@ -290,89 +287,16 @@
transition: all 0.2s ease;
}
/* Branding */
.category-tag.branding {
background-color: var(--brand-crimson);
color: #ffffff;
border-color: var(--brand-crimson);
}
[data-theme="dark"] .category-tag.branding {
background-color: rgba(186, 18, 77, 0.95);
color: #ffffff;
border-color: rgba(186, 18, 77, 1);
}
.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; }
/* Web */
.category-tag.web {
background-color: var(--brand-teal);
color: #ffffff;
border-color: var(--brand-teal);
}
[data-theme="dark"] .category-tag.web {
background-color: rgba(0, 63, 82, 0.95);
color: #ffffff;
border-color: rgba(0, 63, 82, 1);
}
/* Automatizaciones */
.category-tag.automatizaciones {
background-color: var(--brand-plum);
color: #ffffff;
border-color: var(--brand-plum);
}
[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);
}
/* Redes */
.category-tag.redes {
background-color: #00a88c;
color: #ffffff;
border-color: #00a88c;
}
[data-theme="dark"] .category-tag.redes {
background-color: rgba(5, 104, 87, 0.95);
color: #ffffff;
border-color: rgba(0, 168, 140, 1);
}
/* Paid Media */
.category-tag.paid {
background-color: #6b4c9a;
color: #ffffff;
border-color: #6b4c9a;
}
[data-theme="dark"] .category-tag.paid {
background-color: rgba(107, 76, 154, 0.95);
color: #ffffff;
border-color: rgba(107, 76, 154, 1);
}
/* Estrategia */
.category-tag.estrategia {
background-color: #d97706;
color: #ffffff;
border-color: #d97706;
}
[data-theme="dark"] .category-tag.estrategia {
background-color: rgba(217, 119, 6, 0.95);
color: #ffffff;
border-color: rgba(217, 119, 6, 1);
}
/* Casos */
.category-tag.casos {
background-color: #475569;
color: #ffffff;
border-color: #475569;
}
[data-theme="dark"] .category-tag.casos {
background-color: rgba(71, 85, 105, 0.95);
color: #ffffff;
border-color: rgba(71, 85, 105, 1);
}
[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);
@@ -380,11 +304,11 @@
}
/* ============================================
ARTÍCULOS DESTACADOS (VERSIÓN SIMÉTRICA)
ARTÍCULOS DESTACADOS
============================================ */
.featured-posts {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base);
background-color: var(--bg-base-t3);
position: relative;
}
@@ -411,7 +335,7 @@
.featured-posts .section-title {
font-family: var(--font-title);
font-style: italic;
font-size: clamp(2rem, 4vw, 2.8rem);
font-size: clamp(1.2rem, 2vw, 1.8rem);
color: var(--text-primary);
margin-bottom: var(--spacing-xs);
line-height: 1.2;
@@ -444,24 +368,16 @@
position: relative;
display: flex;
flex-direction: column;
min-height: 480px;
min-height: 250px !important;
}
/* Glow sutil para destacar en hover */
.featured-card::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
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%
);
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;
@@ -475,9 +391,7 @@
box-shadow: 0 20px 40px -10px rgba(0, 0, 0, 0.15);
}
.featured-card:hover::before {
opacity: 1;
}
.featured-card:hover::before { opacity: 1; }
.featured-badge {
position: absolute;
@@ -499,7 +413,7 @@
.featured-image {
position: relative;
overflow: hidden;
aspect-ratio: 16/10;
aspect-ratio: 16/8;
flex-shrink: 0;
}
@@ -510,9 +424,7 @@
transition: transform 0.5s ease;
}
.featured-card:hover .featured-image img {
transform: scale(1.05);
}
.featured-card:hover .featured-image img { transform: scale(1.05); }
.featured-content {
padding: var(--spacing-md);
@@ -532,18 +444,27 @@
.featured-title {
font-family: var(--font-title);
font-style: italic;
font-size: 1.3rem;
font-size: 1.1rem;
color: var(--text-primary);
line-height: 1.3;
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.95rem;
font-size: 0.8rem;
color: var(--text-muted);
line-height: 1.6;
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 {
@@ -583,9 +504,45 @@
============================================ */
.blog-grid-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-surface);
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);
@@ -623,9 +580,7 @@
transition: transform 0.5s ease;
}
.blog-card:hover .card-image img {
transform: scale(1.08);
}
.blog-card:hover .card-image img { transform: scale(1.08); }
.card-category {
position: absolute;
@@ -659,9 +614,7 @@
color: var(--text-muted);
}
.reading-time-mini {
font-weight: 600;
}
.reading-time-mini { font-weight: 600; }
.card-title {
font-family: var(--font-title);
@@ -680,23 +633,6 @@
flex: 1;
}
.card-tags {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
margin-top: var(--spacing-xs);
}
.tag {
font-family: var(--font-small);
font-size: 0.75rem;
padding: 0.25rem 0.7rem;
background-color: var(--bg-surface);
border: 1px solid var(--border);
border-radius: 999px;
color: var(--text-secondary);
}
.card-link {
font-family: var(--font-small);
font-size: 0.9rem;
@@ -723,12 +659,6 @@
display: none;
}
.empty-icon {
font-size: 4rem;
margin-bottom: var(--spacing-sm);
opacity: 0.5;
}
.empty-state h3 {
font-family: var(--font-title);
font-style: italic;
@@ -750,213 +680,40 @@
margin-top: var(--spacing-lg);
}
/* ============================================
NEWSLETTER
============================================ */
.newsletter-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base);
}
.newsletter-card {
max-width: 900px;
margin: 0 auto;
background-color: var(--brand-teal);
border-radius: 24px;
padding: var(--spacing-lg) var(--spacing-md);
display: grid;
grid-template-columns: 1.5fr 1fr;
gap: var(--spacing-lg);
align-items: center;
position: relative;
overflow: hidden;
}
.newsletter-card::before {
content: "";
position: absolute;
top: -100px;
right: -100px;
width: 300px;
height: 300px;
border-radius: 50%;
background: radial-gradient(circle, var(--brand-crimson) 0%, transparent 70%);
opacity: 0.3;
filter: blur(60px);
}
.newsletter-content {
position: relative;
z-index: 1;
}
.newsletter-title {
font-family: var(--font-title);
font-style: italic;
font-size: clamp(1.8rem, 3vw, 2.5rem);
color: #ffffff;
margin-bottom: var(--spacing-xs);
}
.newsletter-subtitle {
font-family: var(--font-body);
font-size: 1rem;
color: rgba(255, 255, 255, 0.85);
line-height: 1.6;
}
.newsletter-form {
display: flex;
gap: var(--spacing-sm);
position: relative;
z-index: 1;
}
.newsletter-form input {
flex: 1;
padding: 0.85rem 1.2rem;
border: none;
border-radius: 999px;
font-family: var(--font-body);
font-size: 0.95rem;
background-color: rgba(255, 255, 255, 0.95);
color: var(--text-primary);
}
.newsletter-form input::placeholder {
color: var(--text-muted);
}
.newsletter-form .btn {
white-space: nowrap;
background-color: var(--brand-crimson);
color: var(--text-on-accent);
border: 1.5px solid var(--brand-crimson);
}
.newsletter-form .btn:hover {
background-color: #ffffff;
color: var(--brand-teal);
border-color: #ffffff;
}
/* ============================================
RESPONSIVE BLOG
============================================ */
@media (max-width: 1024px) {
.blog-grid,
.featured-grid {
grid-template-columns: repeat(2, 1fr);
}
.featured-card {
min-height: 420px;
}
.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;
}
.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;
}
.newsletter-card {
grid-template-columns: 1fr;
text-align: center;
}
.newsletter-form {
flex-direction: column;
}
.newsletter-form .btn {
width: 100%;
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;
}
.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;
}
.blog-card, .featured-card, .filter-btn, .category-btn, .search-wrapper-compact, .category-tag { transition: none; }
}
+26 -15
View File
@@ -33,7 +33,7 @@
============================================ */
.contacto-grid-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-surface);
background-color: var(--bg-surface-t2);
}
.contacto-grid {
@@ -95,8 +95,7 @@
width: 40px;
height: 40px;
flex-shrink: 0;
background-color: var(--brand-crimson);
border-radius: 10px;
border-radius: 1px;
-webkit-mask-size: contain;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
@@ -108,22 +107,27 @@
.canal-email {
-webkit-mask-image: url("../assets/iconos/buzon.svg");
mask-image: url("../assets/iconos/buzon.svg");
background-color: var(--brand-teal);
background-color: var(--brand-teal-contraste);
}
.canal-whatsapp {
-webkit-mask-image: url("../assets/vectores/whatsapp.svg");
mask-image: url("../assets/vectores/whatsapp.svg");
background-color: #25D366;
-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/vectores/insta.svg");
mask-image: url("../assets/vectores/insta.svg");
background: linear-gradient(45deg, #f09433, #e6683c, #dc2743, #cc2366, #bc1888);
-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("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3E%3Cpath d='M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.063 2.063 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z'/%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='M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.063 2.063 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z'/%3E%3C/svg%3E");
background-color: #0A66C2;
-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 {
@@ -311,7 +315,7 @@
============================================ */
.proceso-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base);
background-color: var(--bg-base-t3);
}
.proceso-grid {
@@ -388,7 +392,7 @@
============================================ */
.notas-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-surface);
background-color: var(--bg-surface-t1);
}
.notas-container {
@@ -420,6 +424,13 @@
color: var(--text-muted);
line-height: 1.6;
}
.form-honeypot {
position: absolute;
left: -9999px;
width: 1px;
height: 1px;
overflow: hidden;
}
/* ============================================
RESPONSIVE CONTACTO
File diff suppressed because it is too large Load Diff
+259 -40
View File
@@ -31,6 +31,14 @@
--bg-surface-elevated: #f5f9f8;
--bg-icon-contrast: var(--brand-teal);
--bg-base-t0:rgba(234,240,238, 0.98);
--bg-base-t1:rgba(234,240,238, 0.95);
--bg-base-t2:rgba(234,240,238, 0.7);
--bg-base-t3:rgba(234,240,238, 0.5);
--bg-surface-t0:rgb(255, 255, 255, 0.98);
--bg-surface-t1:rgb(255, 255, 255, 0.95);
--bg-surface-t2: rgb(255, 255, 255, 0.7);
--text-primary: var(--brand-plum);
--text-secondary: var(--brand-teal);
--text-muted: rgba(34, 23, 40, 0.65);
@@ -77,6 +85,14 @@
--brand-teal-contraste: #116c88;
--brand-crimson-contraste: #d81a5c;
--bg-base-t0:rgba(17,9,22, 0.98);
--bg-base-t1:rgba(17,9,22, 0.95);
--bg-base-t2:rgba(17,9,22, 0.7);
--bg-base-t3:rgba(17,9,22, 0.5);
--bg-surface-t0:rgb(23,12,29, 0.98);
--bg-surface-t1:rgb(23,12,29, 0.95);
--bg-surface-t2: rgb(23,12,29, 0.7);
--text-primary: var(--brand-sage-light);
--text-secondary: var(--brand-rose-muted);
--text-muted: rgba(234, 240, 238, 0.65);
@@ -108,11 +124,13 @@
html {
font-size: var(--font-size-base);
scroll-behavior: smooth;
background-color: var(--bg-base);
}
body {
font-family: var(--font-family-base);
background-color: var(--bg-base);
/*background-color: var(--bg-base);*/
background-color: transparent;
color: var(--text-primary);
line-height: 1.5;
min-height: 100vh;
@@ -156,6 +174,20 @@ ul { list-style: none; }
z-index: 100;
}
.badge-filosofia {
display: inline-block;
padding: 0.4rem 1rem;
border-radius: 999px;
color: var(--badge-text);
font-family: var(--font-small);
font-weight: 400;
font-size: 1rem;
letter-spacing: 0.5px;
text-transform: uppercase;
opacity: 0;
animation: fadeInUp 0.9s ease-out 0s forwards;
}
.site-header {
background-color: var(--bg-surface);
border-bottom: 1px solid var(--border);
@@ -500,7 +532,8 @@ body.menu-open .site-header {
============================================ */
main section {
padding: var(--spacing-md) var(--spacing-sm);
border-bottom: 1px dashed var(--border);
background-color: transparent;
/*border-bottom: 1px dashed var(--border);*/
}
main section h2 { margin-bottom: var(--spacing-sm); font-size: 1.5rem; }
@@ -508,7 +541,7 @@ main section h2 { margin-bottom: var(--spacing-sm); font-size: 1.5rem; }
border-top: 1px solid var(--border);
padding-top: var(--spacing-lg);
margin-top: auto;
background-color: var(--bg-surface);
background-color: var(--bg-surface-t0);
position: relative;
}
@@ -565,7 +598,7 @@ main section h2 { margin-bottom: var(--spacing-sm); font-size: 1.5rem; }
============================================ */
.hero-section {
min-height: calc(100vh - var(--header-height));
background-color: var(--bg-base);
background-color: var(--bg-base-t3);
display: flex; align-items: center; justify-content: center;
padding: var(--spacing-lg) var(--spacing-md);
text-align: center;
@@ -665,7 +698,7 @@ main section h2 { margin-bottom: var(--spacing-sm); font-size: 1.5rem; }
============================================ */
.servicios-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base);
background-color: var(--bg-base-t3);
}
.servicios-container {
@@ -789,7 +822,7 @@ SECCIÓN DIAGNÓSTICO
============================================ */
.diagnostico-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base);
background-color: transparent;
}
.diagnostico-header {
@@ -1364,7 +1397,7 @@ RESPONSIVE DIAGNÓSTICO
SECCIÓN METODOLOGÍA
============================================ */
.metodologia-section {
padding: var(--spacing-lg) var(--spacing-md); background-color: var(--bg-base);
padding: var(--spacing-lg) var(--spacing-md); background-color: var(--bg-base-t2);
}
.metodologia-header {
@@ -1474,7 +1507,7 @@ RESPONSIVE DIAGNÓSTICO
SECCIÓN PLANES DESTACADOS
============================================ */
.planes-section {
padding: var(--spacing-lg) var(--spacing-md); background-color: var(--bg-base);
padding: var(--spacing-lg) var(--spacing-md); background-color: transparent;
}
.planes-header { text-align: center; max-width: 700px; margin: 0 auto var(--spacing-lg); }
@@ -1550,7 +1583,7 @@ RESPONSIVE DIAGNÓSTICO
/* ============================================
SECCIÓN PORTFOLIO
============================================ */
.portfolio-section { padding: var(--spacing-lg) var(--spacing-md); background-color: var(--bg-base); }
.portfolio-section { padding: var(--spacing-lg) var(--spacing-md); background-color: var(--bg-base-t2); }
.portfolio-container {
display: grid; grid-template-columns: 1fr 1.2fr; gap: var(--spacing-lg);
max-width: 1400px; margin: 0 auto; align-items: center;
@@ -1667,56 +1700,242 @@ RESPONSIVE DIAGNÓSTICO
/* ============================================
SECCIÓN CTA FINAL
============================================ */
.cta-section { padding: var(--spacing-lg) var(--spacing-md); background-color: var(--bg-base); }
.cta-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: transparent;
}
.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);
max-width: 900px;
margin: 0 auto;
/* Fondo teal sólido y oscuro para máximo contraste */
background-color: var(--brand-teal);
border-radius: 24px;
padding: var(--spacing-lg) var(--spacing-md);
text-align: center;
position: relative;
overflow: hidden;
/* Sombra más pronunciada */
box-shadow: 0 20px 60px -10px rgba(0, 63, 82, 0.5);
/* Borde sutil para definir mejor */
border: 1px solid rgba(255, 255, 255, 0.1);
}
.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;
/* Glows decorativos con degradé crimson-teal */
.cta-card::before,
.cta-card::after {
content: "";
position: absolute;
width: 400px;
height: 400px;
border-radius: 50%;
filter: blur(100px);
opacity: 0.4;
pointer-events: none;
z-index: 0;
}
/* Glow superior izquierdo - Crimson/Rosa */
.cta-card::before {
top: -150px;
left: -150px;
background: radial-gradient(
circle,
rgba(186, 18, 77, 0.6) 0%,
rgba(186, 18, 77, 0.3) 40%,
transparent 70%
);
animation: glowPulse 8s ease-in-out infinite;
}
/* Glow inferior derecho - Teal/Rose */
.cta-card::after {
bottom: -150px;
right: -150px;
background: radial-gradient(
circle,
rgba(0, 168, 140, 0.5) 0%,
rgba(223, 189, 185, 0.3) 40%,
transparent 70%
);
animation: glowPulse 8s ease-in-out infinite reverse;
}
/* Animación sutil de los glows */
@keyframes glowPulse {
0%, 100% {
transform: scale(1) translate(0, 0);
opacity: 0.4;
}
50% {
transform: scale(1.1) translate(20px, -20px);
opacity: 0.5;
}
}
.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;
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;
/* Sombra de texto para mejorar legibilidad */
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.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;
font-family: var(--font-body);
font-size: clamp(1rem, 2vw, 1.15rem);
color: rgba(255, 255, 255, 0.9);
max-width: 600px;
margin: 0 auto var(--spacing-md);
line-height: 1.6;
position: relative;
z-index: 1;
text-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
}
.cta-buttons {
display: flex; justify-content: center; gap: var(--spacing-sm);
flex-wrap: wrap; position: relative; z-index: 1;
display: flex;
justify-content: center;
gap: var(--spacing-sm);
flex-wrap: wrap;
position: relative;
z-index: 1;
}
/* Botón primario - Blanco con hover crimson */
.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);
background-color: #ffffff;
color: var(--brand-teal);
border: 2px solid #ffffff;
padding: 0.85rem 2.2rem;
border-radius: 999px;
font-family: var(--font-small);
font-size: 0.95rem;
font-weight: 700;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
box-shadow: 0 4px 14px -3px rgba(0, 0, 0, 0.25);
text-decoration: none;
display: inline-block;
}
.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-primary:hover {
background-color: var(--brand-crimson);
color: #ffffff;
border-color: var(--brand-crimson);
transform: translateY(-3px);
box-shadow: 0 8px 24px -4px rgba(186, 18, 77, 0.5);
}
/* Botón secundario - Transparente con borde blanco */
.btn-cta-secondary {
background-color: transparent;
color: #ffffff;
border: 2px solid rgba(255, 255, 255, 0.8);
padding: 0.85rem 2.2rem;
border-radius: 999px;
font-family: var(--font-small);
font-size: 0.95rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
text-decoration: none;
display: inline-block;
}
.btn-cta-secondary:hover {
background-color: rgba(255, 255, 255, 0.1); border-color: #ffffff; transform: translateY(-2px);
background-color: rgba(255, 255, 255, 0.15);
border-color: #ffffff;
transform: translateY(-3px);
box-shadow: 0 8px 24px -4px rgba(255, 255, 255, 0.2);
}
/* ===== CANVAS FLUIDO Y APILAMIENTO ===== */
main {
position: relative;
z-index: 1;
}
#footer-container {
position: relative;
z-index: 2;
}
#fluid-bg {
position: fixed;
inset: 0;
z-index: 0;
pointer-events: none;
}
#fluidCanvas {
display: block;
width: 100vw;
height: 100vh;
background: transparent;
}
/* Responsive */
@media (max-width: 768px) {
.cta-section {
padding: var(--spacing-md) var(--spacing-sm);
}
.cta-card {
padding: var(--spacing-lg) var(--spacing-md);
border-radius: 20px;
}
.cta-card::before,
.cta-card::after {
width: 250px;
height: 250px;
filter: blur(60px);
}
.cta-buttons {
flex-direction: column;
align-items: center;
}
.btn-cta-primary,
.btn-cta-secondary {
width: 100%;
max-width: 320px;
}
}
@media (max-width: 480px) {
.cta-card {
padding: var(--spacing-md) var(--spacing-sm);
}
.cta-title {
font-size: 1.8rem;
}
.cta-subtitle {
font-size: 1rem;
}
}
@media (prefers-reduced-motion: reduce) {
.cta-card::before,
.cta-card::after {
animation: none;
}
.btn-cta-primary,
.btn-cta-secondary {
transition: none;
}
}
@media (max-width: 768px) {
+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; }
}
+7 -24
View File
@@ -18,24 +18,7 @@
[data-theme="dark"] .logo-light { display: none; }
[data-theme="dark"] .logo-dark { display: block; }
/* (Se omiten estilos intermedios del menú por brevedad, asumo que ya los tienes en tu archivo original.
Si necesitas el bloque completo del menú, avísame, pero se mantiene intacto tu CSS original aquí). */
.site-footer {
border-top: 1px solid var(--border);
padding-top: var(--spacing-lg);
margin-top: auto;
background-color: var(--bg-surface);
}
.footer-bottom {
border-top: 1px solid var(--border);
padding: var(--spacing-sm);
text-align: center;
font-size: 0.875rem;
color: var(--text-muted);
background-color: var(--bg-surface);
font-family: 'Jost', sans-serif;
}
/* ============================================
COMPONENTES REUTILIZABLES
@@ -69,7 +52,7 @@
============================================ */
.hero-section {
min-height: calc(100vh - var(--header-height));
background-color: var(--bg-base);
background-color: transparent;
display: flex; align-items: center; justify-content: center;
padding: var(--spacing-lg) var(--spacing-md);
text-align: center;
@@ -133,7 +116,7 @@
/* --- DUALIDAD --- */
.dualidad-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-surface);
background-color: var(--bg-surface-t2);
}
.dualidad-grid {
display: grid; grid-template-columns: 1fr 1fr; gap: var(--spacing-md);
@@ -191,7 +174,7 @@
/* --- PRINCIPIOS --- */
.principios-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base);
background-color: var(--bg-base-t2);
}
.principios-grid {
display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--spacing-md);
@@ -228,7 +211,7 @@
============================================ */
.casos-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base);
background-color: var(--bg-base-t3);
}
.casos-grid-simetrico {
@@ -341,7 +324,7 @@
.caso-descripcion {
font-family: var(--font-body);
font-size: 0.95rem;
color: var(--brand-sage-light);
color: var(--text-secondary);
line-height: 1.6;
flex: 1;
}
@@ -452,7 +435,7 @@
============================================ */
.transparencia-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base);
background-color: var(--bg-base-t2);
}
.transparencia-grid {
@@ -580,7 +563,7 @@
============================================ */
.equipo-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base);
background-color: transparent;
}
/* Título con gradiente en la palabra destacada */
+5 -5
View File
@@ -3,7 +3,7 @@
============================================ */
.planes-hero {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base);
background-color: var(--bg-base-t2);
min-height: 70vh;
display: flex;
align-items: center;
@@ -71,7 +71,7 @@
============================================ */
.planes-selector-section {
padding: var(--spacing-sm) var(--spacing-xs);
background-color: var(--bg-surface);
background-color: var(--bg-surface-t1);
border-top: 1px solid var(--border);
border-bottom: 1px solid var(--border);
}
@@ -174,7 +174,7 @@
============================================ */
.planes-panel-section {
padding: var(--spacing-md) var(--spacing-md);
background-color: var(--bg-base);
background-color: transparent;
min-height: 600px;
}
@@ -419,7 +419,7 @@
============================================ */
.planes-comparativa-section {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base);
background-color: transparent;
}
.comparativa-container {
@@ -517,7 +517,7 @@
============================================ */
.planes-cta {
padding: var(--spacing-lg) var(--spacing-md);
background-color: var(--bg-base);
background-color: transparent;
}
.planes-cta-card {
+9 -11
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;
@@ -195,7 +193,7 @@
============================================ */
.servicios-panel-section {
padding: var(--spacing-md) var(--spacing-xs);
background-color: var(--bg-base);
background-color: transparent;
min-height: 400px;
}
@@ -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>