diff --git a/admin/auth.php b/admin/auth.php deleted file mode 100644 index d66c615..0000000 --- a/admin/auth.php +++ /dev/null @@ -1,19 +0,0 @@ -prepare("SELECT id, nombre, email FROM admin_users WHERE id = ?"); - $stmt->execute([$_SESSION['admin_id']]); - return $stmt->fetch(); -} -?> \ No newline at end of file diff --git a/admin/dashboard.php b/admin/dashboard.php deleted file mode 100644 index f1d9367..0000000 --- a/admin/dashboard.php +++ /dev/null @@ -1,176 +0,0 @@ -prepare(" - SELECT p.*, u.nombre as autor_nombre - FROM blog_posts p - LEFT JOIN admin_users u ON p.autor_id = u.id - ORDER BY p.created_at DESC -"); -$stmt->execute(); -$posts = $stmt->fetchAll(); - -$admin = getAdminActual(); -?> - - - - - - Dashboard - Blog Amor y Roma - - - - -
-
-

Hola,

-

Gestión de artículos del blog

-
-
- Ver Blog - + Nuevo Artículo - Cerrar sesión -
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TítuloCategoríaAutorEstadoFechaVistasAcciones
- No hay artículos creados aún. Crear el primero -
- - - - - Editar - Eliminar -
-
- - \ No newline at end of file diff --git a/admin/editor.php b/admin/editor.php deleted file mode 100644 index c93880c..0000000 --- a/admin/editor.php +++ /dev/null @@ -1,294 +0,0 @@ -prepare("SELECT * FROM blog_posts WHERE id = ?"); - $stmt->execute([$_GET['id']]); - $post = $stmt->fetch(); - if (!$post) { - die('Artículo no encontrado'); - } - $modo_edicion = true; -} - -// Procesar formulario -if ($_SERVER['REQUEST_METHOD'] === 'POST') { - $titulo = trim($_POST['titulo']); - $slug = strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $titulo))); - $extracto = trim($_POST['extracto']); - $contenido = $_POST['contenido']; - $categoria = $_POST['categoria']; - $tags = trim($_POST['tags']); - $destacado = isset($_POST['destacado']) ? 1 : 0; - $estado = $_POST['estado']; - $tiempo_lectura = (int)$_POST['tiempo_lectura']; - $autor_id = $admin['id']; - - // Subida de imagen - $imagen = $post['imagen'] ?? ''; - if (isset($_FILES['imagen']) && $_FILES['imagen']['error'] === UPLOAD_ERR_OK) { - $allowed = ['image/jpeg', 'image/png', 'image/webp']; - $max_size = 5 * 1024 * 1024; // 5MB - - if (!in_array($_FILES['imagen']['type'], $allowed)) { - $error = 'Solo se permiten imágenes JPG, PNG o WebP'; - } elseif ($_FILES['imagen']['size'] > $max_size) { - $error = 'La imagen no puede superar los 5MB'; - } else { - $extension = pathinfo($_FILES['imagen']['name'], PATHINFO_EXTENSION); - $nombre_imagen = $slug . '-' . time() . '.' . $extension; - $ruta_destino = '../assets/blog/' . $nombre_imagen; - - if (!is_dir('../assets/blog')) { - mkdir('../assets/blog', 0755, true); - } - - if (move_uploaded_file($_FILES['imagen']['tmp_name'], $ruta_destino)) { - $imagen = 'assets/blog/' . $nombre_imagen; - } else { - $error = 'Error al subir la imagen'; - } - } - } - - if (!isset($error)) { - if ($modo_edicion) { - $stmt = $pdo->prepare(" - UPDATE blog_posts SET - titulo = ?, slug = ?, extracto = ?, contenido = ?, - categoria = ?, tags = ?, imagen = ?, destacado = ?, - estado = ?, tiempo_lectura = ? - WHERE id = ? - "); - $stmt->execute([ - $titulo, $slug, $extracto, $contenido, - $categoria, $tags, $imagen, $destacado, - $estado, $tiempo_lectura, $post['id'] - ]); - } else { - $stmt = $pdo->prepare(" - INSERT INTO blog_posts - (titulo, slug, extracto, contenido, categoria, tags, imagen, autor_id, destacado, estado, tiempo_lectura) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - "); - $stmt->execute([ - $titulo, $slug, $extracto, $contenido, - $categoria, $tags, $imagen, $autor_id, $destacado, - $estado, $tiempo_lectura - ]); - } - header('Location: dashboard.php'); - exit; - } -} -?> - - - - - - <?= $modo_edicion ? 'Editar' : 'Nuevo' ?> Artículo - Amor y Roma - - - - - - -
-

Artículo

- ← Volver al dashboard -
- -
- -
- - -
-
- - -
- -
- - -
- -
- - -
- -
-
- - -
- -
- - -
-
- -
-
- - -
- -
- - -
-
- -
- - > - -
- Imagen actual -

Imagen actual:

-
- -
- -
-
- > - -
-
- -
- - Cancelar -
-
-
- - \ No newline at end of file diff --git a/admin/eliminar.php b/admin/eliminar.php deleted file mode 100644 index 4934671..0000000 --- a/admin/eliminar.php +++ /dev/null @@ -1,29 +0,0 @@ -prepare("SELECT imagen FROM blog_posts WHERE id = ?"); -$stmt->execute([$_GET['id']]); -$post = $stmt->fetch(); - -if ($post && $post['imagen']) { - $ruta_imagen = '../' . $post['imagen']; - if (file_exists($ruta_imagen)) { - unlink($ruta_imagen); - } -} - -// Eliminar el artículo -$stmt = $pdo->prepare("DELETE FROM blog_posts WHERE id = ?"); -$stmt->execute([$_GET['id']]); - -header('Location: dashboard.php'); -exit; -?> \ No newline at end of file diff --git a/admin/login.php b/admin/login.php deleted file mode 100644 index 40db1cd..0000000 --- a/admin/login.php +++ /dev/null @@ -1,130 +0,0 @@ -prepare("SELECT id, nombre, password FROM admin_users WHERE email = ?"); - $stmt->execute([$email]); - $user = $stmt->fetch(); - - // Comparación directa sin hash (como pediste) - if ($user && $password === $user['password']) { - $_SESSION['admin_id'] = $user['id']; - $_SESSION['admin_nombre'] = $user['nombre']; - header('Location: dashboard.php'); - exit; - } else { - $error = 'Email o contraseña incorrectos'; - } -} -?> - - - - - - Admin Login - Amor y Roma - - - -
-

Amor y Roma

-

Panel de Administración del Blog

- - -
- - -
-
- - -
-
- - -
- -
-
- - \ No newline at end of file diff --git a/admin/logout.php b/admin/logout.php deleted file mode 100644 index 1f4bcf7..0000000 --- a/admin/logout.php +++ /dev/null @@ -1,6 +0,0 @@ - \ No newline at end of file diff --git a/articulo.php b/articulo.php deleted file mode 100644 index 6d0c232..0000000 --- a/articulo.php +++ /dev/null @@ -1,117 +0,0 @@ -prepare(" - SELECT p.*, u.nombre as autor_nombre - FROM blog_posts p - LEFT JOIN admin_users u ON p.autor_id = u.id - WHERE p.id = ? AND p.estado = 'publicado' -"); -$stmt->execute([$_GET['id']]); -$post = $stmt->fetch(); - -if (!$post) { - header('Location: blog.php'); - exit; -} - -// Incrementar vistas -$stmt = $pdo->prepare("UPDATE blog_posts SET vistas = vistas + 1 WHERE id = ?"); -$stmt->execute([$post['id']]); -?> - - - - - - - <?= htmlspecialchars($post['titulo']) ?> | Blog Amor y Roma - - - - - - -
-
-
- ← Volver al blog - -

-
- 📅 - min de lectura - ✍️ -
- <?= htmlspecialchars($post['titulo']) ?> -
- -
- -
-
-
- - - - - \ No newline at end of file diff --git a/articulos/automatizaciones-instagram.html b/articulos/automatizaciones-instagram.html new file mode 100644 index 0000000..82b4885 --- /dev/null +++ b/articulos/automatizaciones-instagram.html @@ -0,0 +1,131 @@ + + + + + + + + + + + Automatizaciones en Instagram | Blog Amor y Roma + + + + + + + +
+
+
+ ← Volver al blog + Automatizaciones +

Automatizaciones en Instagram: de 0 a 100 leads/mes sin volverte loco

+
+ 📅 5 de enero de 2024 + ⏱ 9 min de lectura + ✍️ Amor y Roma +
+ Automatizaciones en Instagram +
+ +
+

Si tenés un negocio y usás Instagram para vender, probablemente vivís esto:

+
    +
  • Te escriben por DM preguntando lo mismo una y otra vez
  • +
  • Se te escapan mensajes entre medio de otras tareas
  • +
  • Perdé ventas por no responder a tiempo
  • +
  • Pasás horas al día pegado al celular
  • +
+

Hay una forma mejor.

+ +

¿Qué son las automatizaciones (y qué no son)?

+

No son robots fríos que responden "Hola, en breve te atendemos". Eso es lo que la gente ODIA.

+

Las automatizaciones bien hechas son flujos conversacionales inteligentes que:

+
    +
  • Responden al instante, 24/7
  • +
  • Hacen preguntas para entender qué necesita la persona
  • +
  • Filtran y cualifican leads automáticamente
  • +
  • Derivan a WhatsApp o agendan llamadas solo cuando corresponde
  • +
  • Recopilan datos (nombre, email, teléfono) sin que vos pidas nada
  • +
+ +

El sistema de 0 a 100 leads/mes

+ +

Paso 1: Identificá las preguntas repetitivas

+

¿Qué te preguntan siempre?

+
    +
  • "¿Cuál es el precio?"
  • +
  • "¿Hacés envíos a...?"
  • +
  • "¿Tienen disponibilidad para...?"
  • +
+

Esas son tus primeras automatizaciones.

+ +

Paso 2: Creá flujos por palabras clave

+

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.

+

Ejemplo:

+
    +
  • Publicás: "¿Querés saber más sobre nuestro servicio? Comentá INFO"
  • +
  • La persona comenta "INFO"
  • +
  • Automáticamente recibe un DM con información y preguntas de cualificación
  • +
+ +

Paso 3: Cualificá antes de derivar

+

No todos los que escriben son clientes ideales. Tu flujo debería preguntar:

+
    +
  • ¿Qué necesitás específicamente?
  • +
  • ¿Cuándo lo necesitás?
  • +
  • ¿Tenés presupuesto definido?
  • +
+

Así solo recibís notificaciones de leads calificados.

+ +

Paso 4: Integrá con tu CRM o base de datos

+

Los datos que recopilás deberían ir a algún lado útil:

+
    +
  • Google Sheets
  • +
  • Tu CRM
  • +
  • Tu plataforma de email marketing
  • +
+

Así no perdés ningún prospecto y podés hacer seguimiento.

+ +

Errores que matan tus automatizaciones

+
    +
  • Ser demasiado robótico: Usá un tono conversacional, como si hablaras vos.
  • +
  • Pedir demasiada información de una: Pedí solo lo esencial al principio.
  • +
  • No dar opción a hablar con humano: Siempre dejá una salida: "Si preferís hablar con alguien, escribinos 'AGENTE'".
  • +
  • Configurar y olvidar: Revisá cada tanto si los flujos funcionan y ajustá según feedback.
  • +
+ +

Herramientas que usamos en Amor y Roma

+

Trabajamos principalmente con:

+
    +
  • ManyChat: El más completo para Instagram y Facebook
  • +
  • Zapier: Para conectar todo entre sí
  • +
  • Google Sheets/Airtable: Para almacenar leads
  • +
+ +

El resultado: tiempo + conversión

+

Cuando implementamos automatizaciones para un cliente, normalmente vemos:

+
    +
  • ⏰ 8-12 horas/semana ahorradas en respuestas manuales
  • +
  • 📈 40-60% más de leads cualificados (porque no se escapa nadie)
  • +
  • Cero estrés por "no respondí a tiempo"
  • +
+ +
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.
+ +

¿Listo para dejar de vivir pegado al celular?

+

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.

+ +
+ Automatizá tu Instagram +
+
+
+
+ + + + + \ No newline at end of file diff --git a/articulos/landing-pages-que-convierten.html b/articulos/landing-pages-que-convierten.html new file mode 100644 index 0000000..7839e20 --- /dev/null +++ b/articulos/landing-pages-que-convierten.html @@ -0,0 +1,109 @@ + + + + + + + + + + + Landing pages que convierten | Blog Amor y Roma + + + + + + +
+
+
+ ← Volver al blog + Web +

Landing pages que convierten: 7 principios probados

+
+ 10 de enero de 2024 + ⏱ 8 min de lectura + ✍️ Amor y Roma +
+ Landing page que convierte +
+ +
+

Si estás invirtiendo en publicidad o generando contenido en redes, pero tu sitio web no convierte, estás tirando plata. Literal.

+

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.

+ +

Los 7 principios que usamos en Amor y Roma

+ +

1. Claridad antes que creatividad

+

Tu visitante tiene 3 segundos para entender:

+
    +
  • Qué ofrecés
  • +
  • Para quién es
  • +
  • Qué tiene que hacer
  • +
+

Si necesita más tiempo, perdiste. Por eso, evitamos lenguaje rebuscado y vamos directo al grano.

+ +

2. Un solo objetivo, un solo llamado a la acción

+

¿Querés que agenden una llamada? ¿Que descarguen algo? ¿Que compren? Elegí UNA cosa y eliminá toda distracción. Menos es más.

+ +

3. Beneficios, no características

+

A nadie le importa que tu sitio tenga "diseño responsive" o "SEO optimizado". Lo que importa es:

+
    +
  • "Podés contactarnos desde el celular en cualquier momento"
  • +
  • "Te van a encontrar cuando te busquen en Google"
  • +
+

Traducí cada característica en un beneficio tangible.

+ +

4. Prueba social real

+

Testimonios genéricos ("Excelente servicio, muy recomendado") no sirven. Necesitás:

+
    +
  • Nombres reales (o al menos iniciales y cargo)
  • +
  • Resultados específicos ("Aumentamos un 40% las consultas en 2 meses")
  • +
  • Fotos o logos que den credibilidad
  • +
+ +

5. Diseño que guía la mirada

+

Usamos patrones visuales probados:

+
    +
  • F-Pattern: La gente escanea en forma de F
  • +
  • Z-Pattern: Para páginas con menos contenido
  • +
+

Colocamos la información clave en esos puntos calientes.

+ +

6. Velocidad = Conversiones

+

Cada segundo de carga reduce tus conversiones un 7%. Por eso:

+
    +
  • Optimizamos cada imagen
  • +
  • Minimizamos código
  • +
  • Usamos hosting de calidad
  • +
  • Evitamos plugins innecesarios
  • +
+ +

7. Mobile-first, no mobile-also

+

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.

+ +

El método Amor y Roma: Estrategia + Ejecución

+

No usamos plantillas de WordPress pesadas ni constructores visuales que ralentizan todo. Desarrollamos cada landing desde cero, pensando en:

+
    +
  • Tu audiencia específica
  • +
  • Tu propuesta de valor única
  • +
  • Tus objetivos comerciales reales
  • +
+ +
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.
+ +

¿Tu web convierte o solo existe?

+

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.

+ +
+ Desarrollá tu landing page +
+
+
+
+ + + + + \ No newline at end of file diff --git a/articulos/to-logo-no-es-tu-marca.html b/articulos/to-logo-no-es-tu-marca.html new file mode 100644 index 0000000..f281fa2 --- /dev/null +++ b/articulos/to-logo-no-es-tu-marca.html @@ -0,0 +1,87 @@ + + + + + + + + + + + Tu logo no es tu marca | Blog Amor y Roma + + + + + + +
+
+
+ ← Volver al blog + Branding +

Tu logo no es tu marca (y por qué importa)

+
+ 📅 18 de enero de 2024 + ⏱ 6 min de lectura + ✍️ Amor y Roma +
+ Logo vs Marca +
+ +
+

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.

+ +

Logo vs. Marca: la diferencia fundamental

+

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.

+

Pensalo así: el logo es tu firma. La marca es tu reputación.

+ +

¿Por qué las plantillas de branding no funcionan?

+

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:

+
    +
  • Perdés diferenciación: Si tu logo se parece al de otros 50 negocios, ¿por qué te elegirían a vos?
  • +
  • No comunicás tu esencia: Un símbolo genérico no transmite tu historia, tus valores ni tu forma única de operar.
  • +
  • Limitás tu crecimiento: Lo que funciona hoy para un emprendimiento incipiente, mañana puede quedar chico para una empresa consolidada.
  • +
+ +

El branding estratégico: Amor + Roma en acción

+

En Amor y Roma, no empezamos dibujando. Empezamos preguntando:

+
    +
  • ¿Qué problema resolvés?
  • +
  • ¿A quién le hablás?
  • +
  • ¿Qué te hace diferente?
  • +
  • ¿Cómo querés que se sienta la gente al interactuar con vos?
  • +
+

Recién después de entender eso, construimos:

+
    +
  • Arquetipo de marca: ¿Sos el héroe, el sabio, el creador? Esto define tu personalidad.
  • +
  • Sistema visual completo: No solo un logo, sino colores, tipografías, estilos de imagen que funcionen juntos.
  • +
  • Manual de aplicación: Para que tu marca se vea coherente en cada punto de contacto.
  • +
  • Personajes o elementos distintivos: Si aplica, creamos activos que humanicen tu comunicación.
  • +
+ +

El resultado: una marca que resuena

+

Cuando invertís en branding estratégico, no estás comprando "un dibujo lindo". Estás construyendo:

+
    +
  • Reconocimiento: La gente te identifica al instante.
  • +
  • Confianza: Transmitís profesionalismo y solidez.
  • +
  • Conexión emocional: Tu audiencia se siente representada por vos.
  • +
  • Base para crecer: Tenés los cimientos para escalar sin perder identidad.
  • +
+ +
Una marca bien construida no solo se ve profesional: genera confianza, atrae clientes ideales y permite cobrar lo que realmente valés.
+ +

¿Estás listo para construir una marca, no solo un logo?

+

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.

+ +
+ Hablemos sobre tu marca +
+
+
+
+ + + + + \ No newline at end of file diff --git a/assets/blog/automatizacion.jpg b/assets/blog/automatizacion.jpg new file mode 100644 index 0000000..80689bf Binary files /dev/null and b/assets/blog/automatizacion.jpg differ diff --git a/assets/blog/landing-page.jpg b/assets/blog/landing-page.jpg new file mode 100644 index 0000000..df742f5 Binary files /dev/null and b/assets/blog/landing-page.jpg differ diff --git a/assets/blog/logo-marca.jpg b/assets/blog/logo-marca.jpg new file mode 100644 index 0000000..527ea92 Binary files /dev/null and b/assets/blog/logo-marca.jpg differ diff --git a/blog.html b/blog.html index 8fb4246..9fe1cc9 100644 --- a/blog.html +++ b/blog.html @@ -4,193 +4,163 @@ - Blog | Amor y Roma — Recursos y Estrategias + +
- -
-
- -

Ideas que construyen marcas

-

- Estrategia, diseño y tecnología explicados sin tecnicismos innecesarios. -

-
-
- - -
-
- - -
-
- - - - - - - - -
- -
- - -
-
- - -
-
- - - - - - - - -
- -
- -
-
- - -
- Mostrando todos los artículos - -
-
-
- - - - - - - - - - - - -
-
- - -
-
- Contenido para redes - Redes + +
+
+
+
+ + + + + + + +
-
-
- - 8 min + +
+ + +
+
+ +
+
+ + + + + + + + +
+ +
+ +
+
+ +
+ Mostrando todos los artículos + +
+
+
+ + + + + -
+
- SEO + Landing pages que convierten Web
- - 10 min + + 8 min
-

SEO vs Paid Media: cuándo usar cada uno

+

Landing pages que convierten: 7 principios probados

- No son enemigos, son complementarios. Te explicamos cómo combinarlos estratégicamente. + No es magia, es método. Una landing page efectiva no depende de la suerte.

-
- SEO - Google Ads -
- Leer artículo + Leer artículo
- -
+
- Caso de éxito - Casos -
-
-
- - 7 min -
-

Caso de éxito: Ecosistema digital para startup tech

-

- Cómo construimos una presencia integral desde cero: branding, web y redes en 90 días. -

-
- Caso de Éxito - Tecnología -
- Leer artículo -
-
- - -
-
- Chatbot + Automatizaciones en Instagram Automatizaciones
- + 9 min
-

Chatbots que no parecen robots: la clave está en el copy

+

Automatizaciones en Instagram: de 0 a 100 leads/mes

- Cómo escribir flujos de conversación que suenen humanos y realmente vendan. + Responder el mismo mensaje 50 veces al día no es escalable.

-
- ManyChat - Ventas -
- Leer artículo + Leer artículo
- -
-
- Posicionamiento - Estrategia -
-
-
- - 11 min -
-

Posicionamiento: cómo destacar en un mercado saturado

-

- Estrategias prácticas para encontrar tu espacio único y volverte inolvidable. -

-
- Posicionamiento - Diferenciación -
- Leer artículo -
-
- -
-
+ --> - +
@@ -339,6 +247,6 @@ - + \ No newline at end of file diff --git a/blog.php b/blog.php deleted file mode 100644 index b016202..0000000 --- a/blog.php +++ /dev/null @@ -1,194 +0,0 @@ -prepare(" - SELECT p.*, u.nombre as autor_nombre - FROM blog_posts p - LEFT JOIN admin_users u ON p.autor_id = u.id - WHERE p.estado = 'publicado' - ORDER BY p.created_at DESC -"); -$stmt->execute(); -$posts = $stmt->fetchAll(); - -// Obtener destacados -$stmt = $pdo->prepare(" - SELECT p.*, u.nombre as autor_nombre - FROM blog_posts p - LEFT JOIN admin_users u ON p.autor_id = u.id - WHERE p.estado = 'publicado' AND p.destacado = 1 - ORDER BY p.vistas DESC - LIMIT 3 -"); -$stmt->execute(); -$destacados = $stmt->fetchAll(); -?> - - - - - - - Blog | Amor y Roma — Recursos y Estrategias - - - - - - -
- -
-
- Ideas que construyen marcas -

Estrategia, diseño y tecnología explicados sin tecnicismos

-

- Consejos prácticos de branding, web y marketing digital para hacer crecer tu negocio con esencia y estructura. -

-
-
- - -
-
- - -
-
- - - - - - - - -
- -
- - -
-
- - -
-
- - - - - - - - -
- -
- -
-
- - -
- Mostrando todos los artículos - -
-
-
- - - - - - - -
-
- - - -
- - -
-
📝
-

Aún no hay artículos publicados

-

Volvé pronto para encontrar contenido de valor sobre branding, web y marketing digital.

-
- -
- - - -
- - - - - - - \ No newline at end of file diff --git a/config.php b/config.php index daddba3..eecc0d0 100644 --- a/config.php +++ b/config.php @@ -19,7 +19,7 @@ define('MAIL_TO', 'contacto@amoryroma.com.ar'); define('MAIL_TO_NAME', 'Amor & Roma'); // ─── Redirección post-éxito ──────────────────────────────────────────── -define('REDIRECT_URL', 'inicio.html'); +define('REDIRECT_URL', 'index.html'); define('REDIRECT_MS', 4000); // milisegundos antes de redirigir // ─── Modo debug ──────────────────────────────────────────────────────── diff --git a/config/db.php b/config/db.php deleted file mode 100644 index 312889c..0000000 --- a/config/db.php +++ /dev/null @@ -1,29 +0,0 @@ - PDO::ERRMODE_EXCEPTION, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_EMULATE_PREPARES => false - ] - ); -} catch (PDOException $e) { - die("Error de conexión: " . $e->getMessage()); -} - -// Iniciar sesión si no está iniciada -if (session_status() === PHP_SESSION_NONE) { - session_start(); -} -?> \ No newline at end of file diff --git a/contacto.html b/contacto.html index 8a98808..a07f7c0 100644 --- a/contacto.html +++ b/contacto.html @@ -11,6 +11,9 @@ +
@@ -266,5 +269,6 @@ + \ No newline at end of file diff --git a/includes/footer.html b/includes/footer.html index b1c3bb3..74ce7df 100644 --- a/includes/footer.html +++ b/includes/footer.html @@ -3,7 +3,7 @@
diff --git a/nosotros.html b/nosotros.html index 54bba2f..ba6918e 100644 --- a/nosotros.html +++ b/nosotros.html @@ -10,6 +10,9 @@ +
@@ -124,7 +127,7 @@

INVERSIÓN

Desde $250.000/mes

- Planes desde $250.000 (Esencial) hasta $1.000.000 (Élite). El armado inicial —branding, sitio web— se presupuesta por proyecto. + Planes desde $250.000 (Esencia) hasta $1.000.000 (Élite). El armado inicial —branding, sitio web— se presupuesta por proyecto.

@@ -225,7 +228,7 @@

Agendemos una reunión. Sin plantillas, sin compromisos, solo estrategia a medida.

@@ -234,5 +237,6 @@ + \ No newline at end of file diff --git a/planes.html b/planes.html index 964735e..aa89a5f 100644 --- a/planes.html +++ b/planes.html @@ -12,6 +12,9 @@ +
@@ -489,10 +492,10 @@

¿No sabés cuál plan elegir?

-

Hablamos contigo y te recomendamos el plan ideal según tus objetivos y presupuesto.

+

Contanos sobre tu negocio y te recomendamos el plan ideal según tus objetivos y presupuesto.

@@ -505,5 +508,6 @@ + \ No newline at end of file diff --git a/scripts/contacto.js b/scripts/contacto.js index a2ec486..46594e5 100644 --- a/scripts/contacto.js +++ b/scripts/contacto.js @@ -27,7 +27,7 @@ modal.setAttribute('aria-hidden', 'true'); document.body.style.overflow = ''; if (redirectTimer) clearTimeout(redirectTimer); - if (redirigir) window.location.href = 'inicio.html'; + if (redirigir) window.location.href = 'index.html'; } function mostrarError(mensaje) { @@ -86,7 +86,7 @@ const delay = Number(json.delay) || 4000; redirectTimer = setTimeout(() => { - window.location.href = json.redirect || 'inicio.html'; + window.location.href = json.redirect || 'index.html'; }, delay); } else { mostrarError(json.message || 'No pudimos enviar tu mensaje.'); diff --git a/scripts/fluid.js b/scripts/fluid.js index 69ccdc3..c113202 100644 --- a/scripts/fluid.js +++ b/scripts/fluid.js @@ -1,6 +1,6 @@ "use strict"; -// ===== CONFIGURACIÓN DEL EFECTO ===== +// ===== CONFIGURACIÓN DEL EFECTO (Idéntica a fluid - copia.js) ===== const config = { TEXTURE_DOWNSAMPLE: 1, DENSITY_DISSIPATION: 0.975, @@ -11,22 +11,20 @@ const config = { SPLAT_RADIUS: 0.003 }; -// ===== COLORES DE MARCA (Modo Claro / Oscuro) ===== +// ===== COLORES DE MARCA SEGÚN EL TEMA ===== function getBrandColors() { const isDark = document.documentElement.getAttribute('data-theme') === 'dark'; if (isDark) { - // Tonos luminiscentes y vibrantes para contrastar sobre #110916 return [ - [0.920, 0.120, 0.420], // Carmesí brillante (#EA1E6B) - [0.050, 0.680, 0.780], // Teal cian luminoso (#0DAEC7) - [0.850, 0.550, 0.700] // Rosa suave (#D98CB3) + [0.920, 0.120, 0.420], // Carmesí / Fucsia luminoso (#EA1E6B) + [0.080, 0.650, 0.780], // Teal cian luminoso (#14A6C7) + [0.850, 0.500, 0.720] // Rosa suave (#D980B8) ]; } else { - // Tonos puros y elegantes para teñir el fondo claro sin ensuciarlo return [ [0.729, 0.071, 0.302], // Bordo de marca (#BA124D) - [0.000, 0.320, 0.420], // Teal medio (#00526B) - [0.780, 0.280, 0.400] // Rosa carmesí (#C74766) + [0.000, 0.247, 0.322], // Teal de marca (#003F52) + [0.780, 0.280, 0.420] // Carmesí (#C7476B) ]; } } @@ -37,8 +35,7 @@ let targetColor = brandColors[1]; let transitionProgress = 0; const transitionSpeed = 0.008; -// Observar cambios de tema: actualiza paleta y reinicia transición de color. -// El fondo CSS cambia automáticamente (el canvas es transparente, el fondo del se ve a través). +// Observador para detectar el switch de tema en tiempo real const themeObserver = new MutationObserver(() => { brandColors = getBrandColors(); currentColor = brandColors[0]; @@ -59,18 +56,17 @@ function lerpColor(colorA, colorB, t) { let canvas = document.getElementById("fluidCanvas"); if (!canvas) { console.error("ERROR: No se encontró el canvas con id 'fluidCanvas'"); -} else { - canvas.width = window.innerWidth; - canvas.height = window.innerHeight; } +canvas.width = window.innerWidth; +canvas.height = window.innerHeight; -// ===== CONTEXTO WEBGL ===== +// ===== CONTEXTO WEBGL TRANSPARENTE ===== let pointers = []; function getWebGLContext(canvas) { let params = { - alpha: true, // Canvas transparente: el fondo CSS se ve a través - premultipliedAlpha: false, // CLAVE: colores sin premultiplicar para composición correcta + alpha: true, // Transparente para respetar el fondo CSS + premultipliedAlpha: false, // Clave para composición limpia sobre el fondo depth: false, stencil: false, antialias: false @@ -79,22 +75,21 @@ function getWebGLContext(canvas) { let isWebGL2 = !!gl; if (!isWebGL2) 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"); } - - // ✅ CLAVE: Fondo transparente para que se vea el color del body - gl.clearColor(0.0, 0.0, 0.0, 0.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: { @@ -125,7 +120,7 @@ function pointerPrototype() { } pointers.push(new pointerPrototype()); -// ===== SHADERS ===== +// ===== SHADERS BASE ===== let GLProgram = (function () { function GLProgram(vertexShader, fragmentShader) { if (!(this instanceof GLProgram)) throw new TypeError("Cannot call a class as a function"); @@ -165,6 +160,7 @@ let clearShader = compileShader( "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 ADAPTATIVO AL FONDO Y TEMA let displayShader = compileShader( gl.FRAGMENT_SHADER, `precision highp float; @@ -175,24 +171,22 @@ let displayShader = compileShader( void main () { vec4 c = texture2D(uTexture, vUv); - float maxC = max(c.r, max(c.g, c.b)); - if (maxC < 0.001) { + float density = max(c.r, max(c.g, c.b)); + + if (density < 0.001) { gl_FragColor = vec4(0.0); return; } - // Normalizamos el tono cromático para conservar la saturación original - vec3 nColor = c.rgb / maxC; - if (uIsDark > 0.5) { - // MODO OSCURO: fluido con mayor presencia y brillo - float alpha = clamp(maxC * 2.5, 0.0, 0.70); - vec3 glow = clamp(nColor * 1.2, 0.0, 1.0); - gl_FragColor = vec4(glow, alpha); + // MODO OSCURO: Núcleo luminoso y bordes de humo orgánico + float alpha = clamp(density * 2.2, 0.0, 0.90); + vec3 rgb = c.rgb * (1.15 + density * 1.3); + gl_FragColor = vec4(clamp(rgb, 0.0, 1.0), alpha); } else { - // MODO CLARO: tinte traslúcido suave que no satura el fondo sage-light - float alpha = clamp(maxC * 1.5, 0.0, 0.35); - gl_FragColor = vec4(nColor, alpha); + // MODO CLARO: Tinte de acuarela suave que no ensucia el fondo claro + float alpha = clamp(density * 1.35, 0.0, 0.45); + gl_FragColor = vec4(c.rgb, alpha); } }` ); @@ -217,6 +211,7 @@ let divergenceShader = compileShader( "precision highp float; precision mediump sampler2D; varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB; uniform sampler2D uVelocity; vec2 sampleVelocity (in vec2 uv) { vec2 multiplier = vec2(1.0, 1.0); if (uv.x < 0.0) { uv.x = 0.0; multiplier.x = -1.0; } if (uv.x > 1.0) { uv.x = 1.0; multiplier.x = -1.0; } if (uv.y < 0.0) { uv.y = 0.0; multiplier.y = -1.0; } if (uv.y > 1.0) { uv.y = 1.0; multiplier.y = -1.0; } return multiplier * texture2D(uVelocity, uv).xy; } void main () { float L = sampleVelocity(vL).x; float R = sampleVelocity(vR).x; float T = sampleVelocity(vT).y; float B = sampleVelocity(vB).y; float div = 0.5 * (R - L + T - B); gl_FragColor = vec4(div, 0.0, 0.0, 1.0); }" ); +// RESTAURACIÓN EXACTA DE LA FÍSICA DE COPIA (Sin inversión de ejes) let curlShader = compileShader( gl.FRAGMENT_SHADER, "precision highp float; precision mediump sampler2D; varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB; uniform sampler2D uVelocity; void main () { float L = texture2D(uVelocity, vL).y; float R = texture2D(uVelocity, vR).y; float T = texture2D(uVelocity, vT).x; float B = texture2D(uVelocity, vB).x; float vorticity = R - L - T + B; gl_FragColor = vec4(vorticity, 0.0, 0.0, 1.0); }" @@ -321,18 +316,16 @@ function splat(x, y, dx, dy, color) { velocity.swap(); gl.uniform1i(splatProgram.uniforms.uTarget, density.first[2]); - const isDark = document.documentElement.getAttribute('data-theme') === 'dark'; - const densityIntensity = isDark ? 0.65 : 0.45; - gl.uniform3f(splatProgram.uniforms.color, color[0] * densityIntensity, color[1] * densityIntensity, color[2] * densityIntensity); + gl.uniform3f(splatProgram.uniforms.color, color[0] * 0.35, color[1] * 0.35, color[2] * 0.35); blit(density.second[1]); density.swap(); } -// ===== RESIZE ===== +// ===== RESIZE SIN DESFASES ===== function resizeCanvas() { - if (canvas.width !== window.innerWidth || canvas.height !== window.innerHeight) { - canvas.width = window.innerWidth; - canvas.height = window.innerHeight; + if (canvas.width !== canvas.clientWidth || canvas.height !== canvas.clientHeight) { + canvas.width = canvas.clientWidth; + canvas.height = canvas.clientHeight; initFramebuffers(); } } @@ -343,7 +336,8 @@ let count = 0; // ===== DETECTAR ELEMENTOS DE TEXTO ===== function isMouseOverTextElement(target) { const textSelectors = [ - 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'a', 'span', 'button', '.btn', '.card-content', '.hero-content' + 'p', '.hero-content p', 'h1', 'h2', 'h3', 'h4', 'h5', '.hero-content h1', + '.hero-content h2', '.eyebrow', 'a', 'button', '.btn', '.servicio-item', '.plan-card' ]; for (const selector of textSelectors) { if (target.closest(selector)) return true; @@ -351,10 +345,24 @@ function isMouseOverTextElement(target) { return false; } -// ===== EVENTOS CON COLORES DE MARCA ===== +// ===== CONTROL DE MOUSE CENTRADO Y SIMÉTRICO ===== +let isFirstMove = true; + document.addEventListener("mousemove", function (e) { + const rect = canvas.getBoundingClientRect(); + const currentX = e.clientX - rect.left; + const currentY = e.clientY - rect.top; + + // Evita el salto o raya diagonal al entrar por primera vez + if (isFirstMove) { + pointers[0].x = currentX; + pointers[0].y = currentY; + isFirstMove = false; + return; + } + const overText = isMouseOverTextElement(e.target); - + count++; if (count > 1) { transitionProgress += transitionSpeed; @@ -371,15 +379,20 @@ document.addEventListener("mousemove", function (e) { pointers[0].down = true; pointers[0].color = colorArr; - pointers[0].moved = pointers[0].down; - - // ✅ CLAVE: Reducir la fuerza del fluido sobre texto para no dificultar la lectura - const multiplier = overText ? 4.0 : 10.0; - - pointers[0].dx = (e.clientX - pointers[0].x) * multiplier; - pointers[0].dy = (e.clientY - pointers[0].y) * multiplier; - pointers[0].x = e.clientX; - pointers[0].y = e.clientY; + pointers[0].moved = true; + + // Multiplicador simétrico de fluid - copia.js (10.0 en fondo, 8.0 en texto) + const multiplier = overText ? 8.0 : 10.0; + + pointers[0].dx = (currentX - pointers[0].x) * multiplier; + pointers[0].dy = (currentY - pointers[0].y) * multiplier; + pointers[0].x = currentX; + pointers[0].y = currentY; +}); + +window.addEventListener("mouseleave", function () { + isFirstMove = true; + pointers[0].moved = false; }); canvas.addEventListener("touchmove", function (e) { @@ -398,20 +411,24 @@ canvas.addEventListener("touchmove", function (e) { colorArr = lerpColor(currentColor, targetColor, transitionProgress); count = 0; } - + + const rect = canvas.getBoundingClientRect(); for (let i = 0, len = touches.length; i < len; i++) { if (i >= pointers.length) pointers.push(new pointerPrototype()); let pointer = pointers[i]; + let touchX = touches[i].clientX - rect.left; + let touchY = touches[i].clientY - rect.top; + pointer.id = touches[i].identifier; pointer.down = true; pointer.color = colorArr; pointer.moved = true; - pointer.dx = (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; + pointer.dx = (touchX - pointer.x) * 10.0; + pointer.dy = (touchY - pointer.y) * 10.0; + pointer.x = touchX; + pointer.y = touchY; } -}, { passive: false }); +}, false); // ===== LOOP PRINCIPAL ===== let lastTime = Date.now(); @@ -495,10 +512,13 @@ function update() { gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); displayProgram.bind(); gl.uniform1i(displayProgram.uniforms.uTexture, density.first[2]); + + // Informar al shader si estamos en modo oscuro 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); @@ -506,55 +526,9 @@ function update() { update(); - -/* captura del movimiento del mouse*/ -let isFirstMove = true; - -document.addEventListener("mousemove", function (e) { - if (isFirstMove) { - pointers[0].x = e.clientX; - pointers[0].y = e.clientY; - isFirstMove = false; - return; - } - - const overText = isMouseOverTextElement(e.target); - - count++; - if (count > 1) { - transitionProgress += transitionSpeed; - if (transitionProgress >= 1) { - transitionProgress = 0; - let currentIndex = brandColors.indexOf(currentColor); - let nextIndex = (currentIndex + 1) % brandColors.length; - currentColor = targetColor; - targetColor = brandColors[nextIndex]; - } - colorArr = lerpColor(currentColor, targetColor, transitionProgress); - count = 0; - } - - pointers[0].down = true; - pointers[0].color = colorArr; - pointers[0].moved = true; - - // Fuerza balanceada sobre el texto y sobre el fondo - const multiplier = overText ? 4.0 : 8.0; - - pointers[0].dx = (e.clientX - pointers[0].x) * multiplier; - pointers[0].dy = (e.clientY - pointers[0].y) * multiplier; - pointers[0].x = e.clientX; - pointers[0].y = e.clientY; -}); - -window.addEventListener("mouseleave", function () { - isFirstMove = true; - pointers[0].moved = false; -}); - -// ===== 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(); }); \ No newline at end of file diff --git a/servicios.html b/servicios.html index 442f660..51e983b 100644 --- a/servicios.html +++ b/servicios.html @@ -10,6 +10,9 @@ +
@@ -18,7 +21,7 @@
Nuestros servicios

Soluciones a medida para cada etapa de tu marca

-

Combinamos estrategia, diseño y tecnología para construir marcas con esencia y estructura.

+

Diseñamos servicios que se adaptan a tu realidad, para ayudarte a crecer sin perder lo que te hace único.

Explorar servicios
@@ -254,7 +257,7 @@ @@ -304,7 +307,7 @@

¿No sabés cuál servicio necesitás?

Hacé nuestro diagnóstico gratuito y te recomendamos la solución ideal para tu momento.

@@ -318,5 +321,6 @@ + \ No newline at end of file diff --git a/style/blog.css b/style/blog.css index 9367fe9..9f9369f 100644 --- a/style/blog.css +++ b/style/blog.css @@ -69,6 +69,7 @@ margin: 0 auto; display: flex; flex-direction: column; + align-items: center; gap: var(--spacing-sm); } @@ -77,6 +78,7 @@ display: flex; gap: var(--spacing-sm); align-items: center; + justify-content: center; flex-wrap: wrap; } @@ -250,8 +252,9 @@ /* 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); @@ -810,17 +813,22 @@ gap: var(--spacing-sm); position: relative; z-index: 1; + justify-content: center; } .newsletter-form input { flex: 1; - padding: 0.85rem 1.2rem; - border: none; + max-width: 320px; /* Limitar ancho para que parezca botón */ + padding: 0.85rem 1.5rem; + border: 1.5px solid rgba(255, 255, 255, 0.3); border-radius: 999px; font-family: var(--font-body); font-size: 0.95rem; - background-color: rgba(255, 255, 255, 0.95); - color: var(--text-primary); + font-weight: 500; + background-color: rgba(255, 255, 255, 0.15); /* Fondo sutil tipo botón */ + color: #ffffff; /* ← CLAVE: Texto blanco siempre visible */ + backdrop-filter: blur(4px); + transition: all 0.3s ease; } .newsletter-form input::placeholder { @@ -1052,10 +1060,17 @@ .newsletter-form { flex-direction: column; + align-items: center; + } + + .newsletter-form input { + max-width: 100%; + width: 100%; } .newsletter-form .btn { width: 100%; + max-width: 320px; } } diff --git a/style/main.css b/style/main.css index 8abf210..e5d10b1 100644 --- a/style/main.css +++ b/style/main.css @@ -1862,6 +1862,7 @@ main { width: 100vw; height: 100vh; background: transparent; + } .hero-section, diff --git a/style/servicios.css b/style/servicios.css index 455627f..c9eb099 100644 --- a/style/servicios.css +++ b/style/servicios.css @@ -510,11 +510,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); } diff --git a/test.php b/test.php new file mode 100644 index 0000000..988c34d --- /dev/null +++ b/test.php @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/web.config b/web.config new file mode 100644 index 0000000..a15f614 --- /dev/null +++ b/web.config @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file