diff --git a/AGENTS.md b/AGENTS.md index 39ea1a9..17f92e7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,14 +1,20 @@ # AGENTS.md para Web A&R 2026 -## Estructura del sitio web +## Estructura y Archivos Clave -Sitio corporativo simple para agencia de marketing digital: -- Archivos HTML principales: index.html, nosotros.html, servicios.html, planes.html -- Componentes reutilizables en `include/` (header.html, footer.html) -- assets/ y styles/ directorios vacíos - diseño pendiente +- **Páginas principales**: index.html, nosotros.html, servicios.html, planes.html +- **Componentes reutilizables** en `partials/` (menu.html, footer.html) +- **Assets vacíos**: assets/, styles/ (diseño pendiente) +- **Scripts JavaScript**: scripts/loader.js, scripts/main.js -## Convenciones +## Convenciones Específicas del Repo -- Nombre de la empresa: Amor&Roma (incluye símbolo "&" - no acento) -- Estética boutique como enfoque de diseño -- Desarrollado con HTML/CSS vanilla (sin frameworks detectados en el código actual) +- **Nombre correcto**: Amor&Roma (símbolo "&", NO acento ni tilde) +- **Estructura**: HTML/CSS vanilla, sin frameworks detectados +- **Componentes reutilizables**: Los partials se incluyen en páginas principales (ej: include header html) +- **Nomenclatura de archivos**: Minúsculas con nombres descriptivos + +## Convenciones Técnicas + +- Usar doble comillas (") para rutas que contienen "&&" de caracteres especiales +- Directorios `partials/` y `scripts/` se reflejan en la estructura como subdirectorios no raíces \ No newline at end of file diff --git a/assets/iconos/moon.svg b/assets/iconos/moon.svg new file mode 100644 index 0000000..792cf05 --- /dev/null +++ b/assets/iconos/moon.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/assets/iconos/sun.svg b/assets/iconos/sun.svg new file mode 100644 index 0000000..dbdca5d --- /dev/null +++ b/assets/iconos/sun.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/blog.html b/blog.html new file mode 100644 index 0000000..d657c25 --- /dev/null +++ b/blog.html @@ -0,0 +1,68 @@ + + + + + + + Blog - [Nombre de la agencia] + + + + + + +
+ +
+

Blog

+

Contenido pendiente de definir.

+
+ + +
+
+ + + + + + + + + + + +
+
+ + +
+
+ +

Cargando artículos...

+
+
+ + +
+ +
+ + +
+

Suscríbete

+

Contenido pendiente de definir.

+
+
+ + + + + + + \ No newline at end of file diff --git a/contacto.html b/contacto.html new file mode 100644 index 0000000..4a35602 --- /dev/null +++ b/contacto.html @@ -0,0 +1,70 @@ + + + + + + + Contacto - [Nombre de la agencia] + + + + + +
+ +
+

Contacto

+

Contenido pendiente de definir.

+
+ + +
+

Escríbenos

+
+ + + + + + + + + + + + + + + + +
+
+ + +
+

Síguenos

+ +
+ + +
+

¿Prefieres WhatsApp?

+ + Escríbenos por WhatsApp + +
+
+ + + + + + + \ No newline at end of file diff --git a/includes/footer.html b/includes/footer.html new file mode 100644 index 0000000..0612525 --- /dev/null +++ b/includes/footer.html @@ -0,0 +1,38 @@ + \ No newline at end of file diff --git a/includes/menu.html b/includes/menu.html new file mode 100644 index 0000000..75c9fd2 --- /dev/null +++ b/includes/menu.html @@ -0,0 +1,76 @@ + + + + + + +
+ + + +
\ No newline at end of file diff --git a/index.html b/index.html deleted file mode 100644 index 75ff145..0000000 --- a/index.html +++ /dev/null @@ -1,562 +0,0 @@ - - - - - - Amor & Roma — Estudio Creativo - - - - - - - - - -
- - - - - -
- - -
- - -
-
-
Estudio Creativo · Agencia Boutique
-

Marcas con esencia,
construidas con estrategia.

-

Branding, diseño web y marketing digital para negocios que quieren crecer sin perder lo que los hace únicos.

- -
-
Scroll
-
- - -
-
Lo que hacemos
-

Servicios pensados para marcas con esencia.

-

Cuatro disciplinas que trabajan juntas, no por separado — cada proyecto se arma con la combinación justa para tu marca.

-
- - - - -
-
-
-

Identidad con alma,
no solo con estilo.

-

Construimos el sistema visual y verbal que sostiene tu marca: desde el naming y el logo hasta el tono de voz con el que hablás en cada canal.

- Quiero mi identidad de marca → -
-
-
✦ Naming y concepto de marca
-
✦ Diseño de logo e isotipo
-
✦ Paleta, tipografía y manual de marca
-
✦ Tono de voz y guía de comunicación
-
-
-
-
-

Sitios que convierten,
no solo que se ven bien.

-

Diseño y desarrollo de sitios web a medida — rápidos, responsivos y pensados para que quien llega, actúe.

- Quiero mi sitio web → -
-
-
✦ Landing pages y sitios institucionales
-
✦ UX/UI a medida
-
✦ Optimización SEO técnica
-
✦ E-commerce y tiendas online
-
-
-
-
-

Presencia constante,
estrategia real.

-

Gestión de redes, contenido y pauta — con reportes claros para que sepas siempre qué está funcionando y por qué.

- Quiero mi estrategia digital → -
-
-
✦ Community management
-
✦ Publicidad en Meta e Instagram Ads
-
✦ Estrategia de contenido y calendario
-
✦ Reportes mensuales de performance
-
-
-
-
-

Tecnología al servicio
de tu tiempo.

-

Automatizamos lo repetitivo para que tu equipo se enfoque en lo estratégico — sin perder el trato cercano con tus clientes.

- Quiero automatizar procesos → -
-
-
✦ Chatbots y respuestas automáticas
-
✦ Automatización de leads y seguimiento
-
✦ Integraciones con CRM y WhatsApp
-
✦ Consultoría en IA aplicada a tu negocio
-
-
-
- - -
-
Inversión
-

Un plan para cada etapa de tu marca.

-

Cuatro niveles pensados para acompañar tu crecimiento — desde presencia digital consistente hasta gestión integral de marca.

-
-
-
Esencial
-
★
-
Establecer una presencia digital profesional y consistente.
-
    -
  • 2 redes sociales
  • -
  • 8 publicaciones + 8 historias / mes
  • -
  • 1 diseño de marca (logo)
  • -
  • Reunión mensual de estrategia
  • -
  • Reporte mensual de métricas
  • -
- +Info -
-
-
Impulso
-
★★
-
Aumentar visibilidad, interacción y generación de leads calificados.
-
    -
  • 2 redes · 12 publicaciones + 4 reels
  • -
  • Logo + paleta de colores
  • -
  • 1 campaña Meta Ads + retargeting
  • -
  • Automatización de respuestas frecuentes
  • -
  • Gestión de Meta Business Suite
  • -
- +Info -
-
-
Más Popular
-
Premium
-
★★★
-
Consolidar y expandir la empresa comercialmente.
-
    -
  • 3 redes · 16 publicaciones + 8 reels
  • -
  • Sesión de fotos/video quincenal
  • -
  • 2 campañas Meta Ads + Google Ads
  • -
  • Respuestas con IA 24/7
  • -
  • Reporte semanal + reunión mensual
  • -
  • Soporte prioritario
  • -
- +Info -
-
-
Elite
-
★★★★
-
Máximo posicionamiento y gestión integral de marca.
-
    -
  • 4 redes · 20 publicaciones + 16 reels
  • -
  • Dirección creativa integral de marca
  • -
  • 3 campañas + TikTok Ads + Google Ads
  • -
  • Estrategia 360° con planificación mensual
  • -
  • Gestión de reputación online
  • -
- +Info -
-
- Consulta tu plan ideal -
- - -
-
Potenciadores de negocio
-

Para complementar cualquier plan,
o contratar de forma independiente.

-

Elegí los servicios que necesitás, sin compromiso mensual. Todo lo que tu marca necesita, a tu ritmo.

-
-
-
-
01Diseño Web & Desarrollo
-
+
-
-
-
-
Landing Page ProfesionalDiseño de una sección, UI/UX + SEO básico Desde $350.000
-
Sitio Institucional (hasta 7 secciones)Inicio, Servicios, Nosotros, Blog, Contacto Desde $600.000
-
E-commerceTienda online autoadministrable con pasarela de pago Desde $900.000
-
Mantenimiento WebBackups, seguridad y soporte técnico Desde $50.000/mes
-
-
-
-
-
-
02Branding e Identidad Visual
-
+
-
-
-
-
Diseño de Logotipo3 propuestas + revisiones Desde $180.000
-
Manual de Marca CompletoLogo, paleta, tipografías, tono de voz Desde $300.000
-
Rediseño de Identidad VisualActualización de marca existente A cotizar
-
-
-
-
-
-
03Publicidad Digital Avanzada
-
+
-
-
-
-
Campaña Google AdsBúsqueda y display Desde $150.000/mes
-
Campaña TikTok AdsAlcance a audiencias jóvenes Desde $120.000/mes
-
Auditoría de CampañasAnálisis y oportunidades de mejora Desde $90.000
-
-
-
-
-
-
04Diseño Digital & Gráfico
-
+
-
-
-
-
InfografíasComunicación visual de datos y procesos Desde $80.000/u
-
Plantillas para RedesSet editable de 5 piezas Desde $100.000
-
Material ImpresoFlyers, folletos, tarjetas A cotizar
-
-
-
-
-
-
05Producción Audiovisual
-
+
-
-
-
-
Sesión FotográficaProducto, instalaciones o equipo A cotizar
-
Reel / Video CortoHasta 30 segundos, con edición Desde $120.000
-
Pack de 3 ReelsContenido consistente de alto impacto Desde $300.000
-
-
-
-
-
- - -
-
Cómo trabajamos
-

Tu proyecto, paso a paso, y sin sorpresas.

-

Un proceso claro y colaborativo — sabés exactamente qué pasa en cada etapa, sin plantillas genéricas.

-
-
-
01
-
Contacto
-
Reunión de brief
-
Nos contás tu marca y objetivos.
-
-
-
02
-
Propuesta
-
Plan de trabajo
-
Entregables, inversión y tiempos.
-
-
-
03
-
Diseño
-
Dirección de arte
-
Concepto visual a tu aprobación.
-
-
-
04
-
Producción
-
Desarrollo
-
Construimos con seguimiento.
-
-
-
05
-
Revisión
-
Ajustes finales
-
Tu feedback moldea el resultado.
-
-
-
-
Lanzamiento
-
Entrega
-
Accesos y capacitación completa.
-
-
-
- - -
-
Inversión & tiempos
-

Transparencia antes de la primera reunión.

-

Los números, dichos de entrada — no como parte de una negociación, sino como punto de partida.

-
-
-
-
Inversión
-
Desde $250.000/mes
-
Planes desde $250.000 (Esencial) hasta $1.000.000 (Elite). El armado inicial —branding, sitio web— se presupuesta por proyecto.
-
-
-
-
Tiempos
-
15–30 días
-
Presencia digital lista en 15-30 días. Resultados de posicionamiento sostenido en 3-6 meses. Sin promesas de magia inmediata.
-
-
-
-
Contrato
-
3 meses · luego mensual
-
Compromiso mínimo de 3 meses para que la estrategia tome forma, luego renovación mensual. Cancelación con 30 días de aviso.
-
-
-
- - -
-
Cotizador
-

¿Cuál es tu plan ideal?

-

3 preguntas rápidas y te decimos qué plan se ajusta mejor a tu marca.

-
-
-
-
-
-
-
-
Pregunta 01
-
¿Cómo describirías el momento de tu negocio?
-
-
Recién empezando
Necesito presencia digital desde cero
-
En crecimiento
Ya tengo redes, quiero más alcance
-
Establecido
Busco consolidar y vender más
-
Consolidado
Quiero gestión integral de marca
-
- -
-
-
Pregunta 02
-
¿Qué es lo que más necesitás hoy?
-
-
Presencia en redes
Contenido consistente y profesional
-
Más leads y ventas
Publicidad digital que convierta
-
Producción de contenido
Fotos, video y piezas de calidad
-
Todo integrado
Estrategia 360° gestionada por otros
-
- -
-
-
Pregunta 03
-
¿Cuál es tu presupuesto mensual aproximado?
-
-
Hasta $300.000
ARS / mes
-
$300.000 – $450.000
ARS / mes
-
$450.000 – $700.000
ARS / mes
-
Más de $700.000
ARS / mes
-
- -
-
-
Tu plan recomendado
-
—
-
—
-

—

-
- Quiero este plan - -
-
-
-
- - -
-
Nosotros
-

Mentes creativas, con mucha energía.

-

Combinamos el arte del Marketing con la Ciencia de los datos.

-
-
-
Patricia Pugliese
-
Estrategia & Creatividad
-
Investigación, branding, identidad visual y todo lo que da forma a una marca con personalidad.
-
-
-
Francisco Anfuso
-
Desarrollo & Tecnología
-
Diseño web, desarrollo, automatizaciones y soluciones técnicas que funcionan sin complicaciones.
-
-
- -
- - -
-
Preguntas Frecuentes
-

Todo lo que necesitás saber antes de empezar.

-

Respondemos las dudas más comunes para que llegues con confianza al primer encuentro.

-
-
-
- ¿Cómo funciona el proceso de trabajo? - − -
-

Empezamos con una llamada de descubrimiento para conocer tu negocio, objetivos y desafíos. Luego armamos una propuesta a medida, la ejecutamos con entregas parciales y ajustamos hasta que estés 100% conforme. Todo con comunicación clara y tiempos acordados.

-
-
-
- ¿Qué incluye exactamente cada plan? - + -
-

Cada plan tiene un desglose detallado en la sección de Planes. Pero en resumen: incluyen gestión de redes, diseño de marca, publicidad digital, automatizaciones y reportes. Si necesitás algo específico que no esté listado, lo sumamos a medida.

-
-
-
- ¿Puedo contratar servicios sueltos sin un plan mensual? - + -
-

¡Sí! En la sección "Servicios a la carta" tenés disponibles branding, diseño web, campañas puntuales y producción de contenido. Podés contratarlos de forma independiente, sin compromiso mensual.

-
-
-
- ¿Qué resultados puedo esperar? - + -
-

Depende del punto de partida, pero nuestros clientes suelen ver aumento en alcance, engagement y generación de leads en los primeros 3 meses. Compartimos reportes mensuales para que siempre sepas cómo evoluciona tu marca.

-
-
-
- ¿Trabajan con negocios de cualquier rubro? - + -
-

Trabajamos con marcas de moda, gastronomía, tecnología, salud, educación y más. Lo importante es que tengas claros tus valores y quieras construir una marca con identidad propia — el rubro es secundario.

-
-
-
- ¿Cómo facturan? ¿Hay algún costo de inicio? - + -
-

Facturamos con factura electrónica tipo C o E. No hay costo de inicio: los planes se abonan mes a mes, con un 50% de anticipo en proyectos puntuales (como diseño web o branding completo).

-
-
-
- ¿Puedo cambiar de plan o cancelar cuando quiera? - + -
-

Por supuesto. Podés subir o bajar de plan con 15 días de aviso. Si querés cancelar, también con 15 días de anticipación. Sin letra chica ni permanencias forzadas.

-
-
-
- - -
-
Contacto
-

¿Empezamos a construir tu marca?

-

Completá el formulario o escribinos directo — te respondemos en menos de 24 horas.

-
-
-
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
- -
- - - - - - -
- - -
-
- - -
-
-
- -
- -
-
-
-
-
-
📧
- -
-
-
💬
-
-
WhatsApp
- +54 9 388 611-8304 -
-
-
-
📱
-
-
Redes
- -
-
-
-
📍
-
-
Argentina
- Trabajamos remoto worldwide -
-
-
-
-
- - - - - - - - - - \ No newline at end of file diff --git a/inicio.html b/inicio.html new file mode 100644 index 0000000..dbd448d --- /dev/null +++ b/inicio.html @@ -0,0 +1,62 @@ + + + + + + + Inicio - [Nombre de la agencia] + + + + + +
+ +
+

Sección 1

+

Contenido pendiente de definir.

+
+ + +
+

Sección 2

+

Contenido pendiente de definir.

+
+ + +
+

Sección 3

+

Contenido pendiente de definir.

+
+ + +
+

Sección 4

+

Contenido pendiente de definir.

+
+ + +
+

Sección 5

+

Contenido pendiente de definir.

+
+ + +
+

Sección 6

+

Contenido pendiente de definir.

+
+ + +
+

Sección 7

+

Contenido pendiente de definir.

+
+
+ + + + + + + \ No newline at end of file diff --git a/nosotros.html b/nosotros.html index e69de29..bd31c13 100644 --- a/nosotros.html +++ b/nosotros.html @@ -0,0 +1,24 @@ + + + + + + + Nosotros - [Nombre de la agencia] + + + + + +
+

Sección 1

Contenido pendiente de definir.

+

Sección 2

Contenido pendiente de definir.

+

Sección 3

Contenido pendiente de definir.

+
+ + + + + + + \ No newline at end of file diff --git a/partials/footer.html b/partials/footer.html deleted file mode 100644 index 073d26e..0000000 --- a/partials/footer.html +++ /dev/null @@ -1,43 +0,0 @@ - \ No newline at end of file diff --git a/partials/menu.html b/partials/menu.html deleted file mode 100644 index a7aa657..0000000 --- a/partials/menu.html +++ /dev/null @@ -1,71 +0,0 @@ - -
- - - \ No newline at end of file diff --git a/planes.html b/planes.html index e69de29..68656cf 100644 --- a/planes.html +++ b/planes.html @@ -0,0 +1,28 @@ + + + + + + + Planes - [Nombre de la agencia] + + + + + +
+

Sección 1

Contenido pendiente de definir.

+

Sección 2

Contenido pendiente de definir.

+

Sección 3

Contenido pendiente de definir.

+

Sección 4

Contenido pendiente de definir.

+

Sección 5

Contenido pendiente de definir.

+

Sección 6

Contenido pendiente de definir.

+

Sección 7

Contenido pendiente de definir.

+
+ + + + + + + \ No newline at end of file diff --git a/portfolio.html b/portfolio.html new file mode 100644 index 0000000..6dddc03 --- /dev/null +++ b/portfolio.html @@ -0,0 +1,26 @@ + + + + + + + Portfolio - [Nombre de la agencia] + + + + + +
+

Sección 1

Contenido pendiente de definir.

+

Sección 2

Contenido pendiente de definir.

+

Sección 3

Contenido pendiente de definir.

+

Sección 4

Contenido pendiente de definir.

+

Sección 5

Contenido pendiente de definir.

+
+ + + + + + + \ No newline at end of file diff --git a/scripts/blog.js b/scripts/blog.js new file mode 100644 index 0000000..e69de29 diff --git a/scripts/fluid.js b/scripts/fluid.js new file mode 100644 index 0000000..85c8be7 --- /dev/null +++ b/scripts/fluid.js @@ -0,0 +1,582 @@ +"use strict"; + +// ===== CONFIGURACIÓN DEL EFECTO ===== +const config = { + TEXTURE_DOWNSAMPLE: 1, + DENSITY_DISSIPATION: 0.975, + VELOCITY_DISSIPATION: 0.98, + PRESSURE_DISSIPATION: 0.8, + PRESSURE_ITERATIONS: 20, + CURL: 30, + SPLAT_RADIUS: 0.003 +}; + +// ===== 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 ===== +let pointers = []; +let splatStack = []; + +function getWebGLContext(canvas) { + let params = { + alpha: false, + depth: false, + stencil: false, + antialias: false + }; + let gl = canvas.getContext("webgl2", params); + 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"); + } + gl.clearColor(0.0, 0.0, 0.0, 1.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: { + internalFormat: internalFormat, + internalFormatRG: internalFormatRG, + formatRG: formatRG, + texType: texType + }, + support_linear_float: support_linear_float + }; +} + +let _getWebGLContext = getWebGLContext(canvas); +let gl = _getWebGLContext.gl; +let ext = _getWebGLContext.ext; +let support_linear_float = _getWebGLContext.support_linear_float; + +// ===== POINTER ===== +function pointerPrototype() { + this.id = -1; + this.x = 0; + this.y = 0; + this.dx = 0; + this.dy = 0; + this.down = false; + this.moved = false; + this.color = [30, 0, 300]; +} +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"); + 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); + 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 + ); + } + } + GLProgram.prototype.bind = function bind() { + gl.useProgram(this.program); + }; + return GLProgram; +})(); + +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); + 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); }" +); + +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); }" +); + +let splatShader = compileShader( + gl.FRAGMENT_SHADER, + "precision highp float; precision mediump sampler2D; varying vec2 vUv; uniform sampler2D uTarget; uniform float aspectRatio; uniform vec3 color; uniform vec2 point; uniform float radius; void main () { vec2 p = vUv - point.xy; p.x *= aspectRatio; vec3 splat = exp(-dot(p, p) / radius) * color; vec3 base = texture2D(uTarget, vUv).xyz; gl_FragColor = vec4(base + splat, 1.0); }" +); + +let advectionManualFilteringShader = compileShader( + gl.FRAGMENT_SHADER, + "precision highp float; precision mediump sampler2D; varying vec2 vUv; uniform sampler2D uVelocity; uniform sampler2D uSource; uniform vec2 texelSize; uniform float dt; uniform float dissipation; vec4 bilerp (in sampler2D sam, in vec2 p) { vec4 st; st.xy = floor(p - 0.5) + 0.5; st.zw = st.xy + 1.0; vec4 uv = st * texelSize.xyxy; vec4 a = texture2D(sam, uv.xy); vec4 b = texture2D(sam, uv.zy); vec4 c = texture2D(sam, uv.xw); vec4 d = texture2D(sam, uv.zw); vec2 f = p - st.xy; return mix(mix(a, b, f.x), mix(c, d, f.x), f.y); } void main () { vec2 coord = gl_FragCoord.xy - dt * texture2D(uVelocity, vUv).xy; gl_FragColor = dissipation * bilerp(uSource, coord); gl_FragColor.a = 1.0; }" +); + +let advectionShader = compileShader( + gl.FRAGMENT_SHADER, + "precision highp float; precision mediump sampler2D; varying vec2 vUv; uniform sampler2D uVelocity; uniform sampler2D uSource; uniform vec2 texelSize; uniform float dt; uniform float dissipation; void main () { vec2 coord = vUv - dt * texture2D(uVelocity, vUv).xy * texelSize; gl_FragColor = dissipation * texture2D(uSource, coord); }" +); + +let divergenceShader = compileShader( + gl.FRAGMENT_SHADER, + "precision highp float; precision mediump sampler2D; varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB; uniform sampler2D uVelocity; vec2 sampleVelocity (in vec2 uv) { vec2 multiplier = vec2(1.0, 1.0); if (uv.x < 0.0) { uv.x = 0.0; multiplier.x = -1.0; } if (uv.x > 1.0) { uv.x = 1.0; multiplier.x = -1.0; } if (uv.y < 0.0) { uv.y = 0.0; multiplier.y = -1.0; } if (uv.y > 1.0) { uv.y = 1.0; multiplier.y = -1.0; } return multiplier * texture2D(uVelocity, uv).xy; } void main () { float L = sampleVelocity(vL).x; float R = sampleVelocity(vR).x; float T = sampleVelocity(vT).y; float B = sampleVelocity(vB).y; float div = 0.5 * (R - L + T - B); gl_FragColor = vec4(div, 0.0, 0.0, 1.0); }" +); + +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); }" +); + +let vorticityShader = compileShader( + gl.FRAGMENT_SHADER, + "precision highp float; precision mediump sampler2D; varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB; uniform sampler2D uVelocity; uniform sampler2D uCurl; uniform float curl; uniform float dt; void main () { float L = texture2D(uCurl, vL).y; float R = texture2D(uCurl, vR).y; float T = texture2D(uCurl, vT).x; float B = texture2D(uCurl, vB).x; float C = texture2D(uCurl, vUv).x; vec2 force = vec2(abs(T) - abs(B), abs(R) - abs(L)); force *= 1.0 / length(force + 0.00001) * curl * C; vec2 vel = texture2D(uVelocity, vUv).xy; gl_FragColor = vec4(vel + force * dt, 0.0, 1.0); }" +); + +let pressureShader = compileShader( + gl.FRAGMENT_SHADER, + "precision highp float; precision mediump sampler2D; varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB; uniform sampler2D uPressure; uniform sampler2D uDivergence; vec2 boundary (in vec2 uv) { uv = min(max(uv, 0.0), 1.0); return uv; } void main () { float L = texture2D(uPressure, boundary(vL)).x; float R = texture2D(uPressure, boundary(vR)).x; float T = texture2D(uPressure, boundary(vT)).x; float B = texture2D(uPressure, boundary(vB)).x; float C = texture2D(uPressure, vUv).x; float divergence = texture2D(uDivergence, vUv).x; float pressure = (L + R + B + T - divergence) * 0.25; gl_FragColor = vec4(pressure, 0.0, 0.0, 1.0); }" +); + +let gradientSubtractShader = compileShader( + gl.FRAGMENT_SHADER, + "precision highp float; precision mediump sampler2D; varying vec2 vUv; varying vec2 vL; varying vec2 vR; varying vec2 vT; varying vec2 vB; uniform sampler2D uPressure; uniform sampler2D uVelocity; vec2 boundary (in vec2 uv) { uv = min(max(uv, 0.0), 1.0); return uv; } void main () { float L = texture2D(uPressure, boundary(vL)).x; float R = texture2D(uPressure, boundary(vR)).x; float T = texture2D(uPressure, boundary(vT)).x; float B = texture2D(uPressure, boundary(vB)).x; vec2 velocity = texture2D(uVelocity, vUv).xy; velocity.xy -= vec2(R - L, T - B); gl_FragColor = vec4(velocity, 0.0, 1.0); }" +); + +// ===== FRAMEBUFFERS ===== +let textureWidth, textureHeight; +let density, velocity, divergence, curl, pressure; + +function initFramebuffers() { + textureWidth = gl.drawingBufferWidth >> config.TEXTURE_DOWNSAMPLE; + textureHeight = gl.drawingBufferHeight >> config.TEXTURE_DOWNSAMPLE; + let iFormat = ext.internalFormat; + 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 + ); +} + +function createFBO(texId, w, h, internalFormat, format, type, param) { + gl.activeTexture(gl.TEXTURE0 + texId); + let texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, param); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, param); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + 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.viewport(0, 0, w, h); + gl.clear(gl.COLOR_BUFFER_BIT); + return [texture, fbo, texId]; +} + +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; + } + }; +} + +initFramebuffers(); + +// ===== PROGRAMS ===== +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 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 +); + +// ===== 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.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.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(0); + return function (destination) { + gl.bindFramebuffer(gl.FRAMEBUFFER, destination); + gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + }; +})(); + +// ===== SPLAT ===== +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.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 + ); + 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 + ]; +} + +let colorArr = currentColor; +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' + ]; + + // Verificar si el target o sus ancestros coinciden con algún selector + for (const selector of textSelectors) { + if (target.closest(selector)) { + return true; + } + } + return false; +} + +// ===== EVENTOS CON COLORES DE MARCA ===== +document.addEventListener("mousemove", function (e) { + // Detectar si estamos sobre un elemento de texto + 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 = pointers[0].down; + + // Aplicar multiplicador diferente según si estamos sobre texto o no + const multiplier = overText ? 8 : 10.0; // Reducido a 4x sobre texto (vs 10x) + + pointers[0].dx = (e.clientX - canvas.offsetLeft - pointers[0].x) * multiplier; + pointers[0].dy = (e.clientY - canvas.offsetTop - pointers[0].y) * multiplier; + pointers[0].x = e.clientX - canvas.offsetLeft; + pointers[0].y = e.clientY - canvas.offsetTop; +}); + +canvas.addEventListener( + "touchmove", + function (e) { + e.preventDefault(); + let touches = e.targetTouches; + count++; + if (count > 20) { + transitionProgress += transitionSpeed; + if (transitionProgress >= 1) { + transitionProgress = 0; + let currentIndex = brandColors.indexOf(currentColor); + let nextIndex = (currentIndex + 1) % brandColors.length; + currentColor = targetColor; + targetColor = brandColors[nextIndex]; + } + colorArr = lerpColor(currentColor, targetColor, transitionProgress); + count = 0; + } + + for (let i = 0, len = touches.length; i < len; i++) { + if (i >= pointers.length) pointers.push(new pointerPrototype()); + pointers[i].id = touches[i].identifier; + pointers[i].down = true; + pointers[i].x = touches[i].pageX; + pointers[i].y = touches[i].pageY; + pointers[i].color = colorArr; + let pointer = pointers[i]; + pointer.moved = pointer.down; + pointer.dx = (touches[i].pageX - pointer.x) * 10.0; + pointer.dy = (touches[i].pageY - pointer.y) * 10.0; + pointer.x = touches[i].pageX; + pointer.y = touches[i].pageY; + } + }, + false +); + +// ===== LOOP PRINCIPAL ===== +let lastTime = Date.now(); + +function update() { + resizeCanvas(); + let dt = Math.min((Date.now() - lastTime) / 1000, 0.016); + lastTime = Date.now(); + gl.viewport(0, 0, textureWidth, textureHeight); + + advectionProgram.bind(); + 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 + ); + 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 + ); + blit(density.second[1]); + density.swap(); + + for (let i = 0, len = pointers.length; i < len; i++) { + let pointer = pointers[i]; + if (pointer.moved) { + splat(pointer.x, pointer.y, pointer.dx, pointer.dy, pointer.color); + pointer.moved = false; + } + } + + curlProgram.bind(); + 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.uniform1i(vorticityProgram.uniforms.uVelocity, velocity.first[2]); + gl.uniform1i(vorticityProgram.uniforms.uCurl, curl[2]); + gl.uniform1f(vorticityProgram.uniforms.curl, config.CURL); + gl.uniform1f(vorticityProgram.uniforms.dt, dt); + blit(velocity.second[1]); + velocity.swap(); + + divergenceProgram.bind(); + gl.uniform2f( + divergenceProgram.uniforms.texelSize, + 1.0 / textureWidth, + 1.0 / textureHeight + ); + gl.uniform1i(divergenceProgram.uniforms.uVelocity, velocity.first[2]); + blit(divergence[1]); + + clearProgram.bind(); + let pressureTexId = pressure.first[2]; + gl.activeTexture(gl.TEXTURE0 + pressureTexId); + gl.bindTexture(gl.TEXTURE_2D, pressure.first[0]); + gl.uniform1i(clearProgram.uniforms.uTexture, pressureTexId); + gl.uniform1f(clearProgram.uniforms.value, config.PRESSURE_DISSIPATION); + blit(pressure.second[1]); + pressure.swap(); + + pressureProgram.bind(); + 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); + for (let _i = 0; _i < config.PRESSURE_ITERATIONS; _i++) { + gl.bindTexture(gl.TEXTURE_2D, pressure.first[0]); + gl.uniform1i(pressureProgram.uniforms.uPressure, pressureTexId); + blit(pressure.second[1]); + pressure.swap(); + } + + gradienSubtractProgram.bind(); + 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]); + velocity.swap(); + + gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + displayProgram.bind(); + gl.uniform1i(displayProgram.uniforms.uTexture, density.first[2]); + blit(null); + + requestAnimationFrame(update); +} + +update(); + +// ===== REDIMENSIONAR AL CAMBIAR TAMAÑO DE VENTANA ===== +window.addEventListener("resize", function() { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + initFramebuffers(); +}); \ No newline at end of file diff --git a/scripts/main.js b/scripts/main.js index 14f16d4..2a1aa37 100644 --- a/scripts/main.js +++ b/scripts/main.js @@ -1,150 +1,122 @@ -// ===== MENU ===== -function toggleMenu() { - document.getElementById('sheet').classList.toggle('open'); - document.getElementById('overlay').classList.toggle('open'); -} - -// ===== TABS ===== -function showTab(i, el) { - document.querySelectorAll('.tab').forEach(t => t.classList.remove('active')); - document.querySelectorAll('.panel').forEach(p => p.classList.remove('active')); - el.classList.add('active'); - document.querySelector('.panel[data-panel="' + i + '"]').classList.add('active'); -} - -// ===== ACCORDION ===== -function toggleAcc(head) { - const item = head.parentElement; - document.querySelectorAll('.acc-item').forEach(i => { if (i !== item) i.classList.remove('open'); }); - item.classList.toggle('open'); -} - -// ===== FAQ ===== -function toggleFaq(head) { - const item = head.parentElement; - const isOpen = item.classList.contains('open'); - document.querySelectorAll('.faq-item').forEach(i => { - i.classList.remove('open'); - const t = i.querySelector('.faq-toggle'); - if (t) t.textContent = '+'; - }); - if (!isOpen) { - item.classList.add('open'); - const toggle = item.querySelector('.faq-toggle'); - if (toggle) toggle.textContent = '−'; +/* ============================================ + CARGA DE INCLUDES (menu y footer) + ============================================ */ +async function loadInclude(selector, url) { + try { + const response = await fetch(url); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + const html = await response.text(); + const container = document.querySelector(selector); + if (container) container.innerHTML = html; + } catch (error) { + console.error(`Error cargando ${url}:`, error); } } -// ===== COTIZADOR ===== -const answers = [null, null, null]; -let current = 0; +/* ============================================ + SWITCH DE TEMA (claro por defecto) + ============================================ */ +function initTheme() { + const savedTheme = localStorage.getItem('theme') || 'light'; + document.documentElement.setAttribute('data-theme', savedTheme); +} -document.querySelectorAll('.opt').forEach(opt => { - opt.addEventListener('click', function() { - const group = this.parentElement; - const q = parseInt(group.dataset.q); - group.querySelectorAll('.opt').forEach(o => o.classList.remove('selected')); - this.classList.add('selected'); - answers[q] = parseInt(this.dataset.val); - document.getElementById('next' + q).disabled = false; - const step = this.closest('.step'); - const qNum = step.querySelector('.q-num'); - if (qNum) qNum.classList.add('active'); - }); +function toggleTheme() { + const current = document.documentElement.getAttribute('data-theme') || 'light'; + const next = current === 'dark' ? 'light' : 'dark'; + document.documentElement.setAttribute('data-theme', next); + localStorage.setItem('theme', next); +} + +// Ejecutar al cargar la página +document.addEventListener('DOMContentLoaded', () => { + initTheme(); + + const themeBtn = document.querySelector('.theme-toggle'); + if (themeBtn) { + themeBtn.addEventListener('click', toggleTheme); + } }); +/* ============================================ + CALCULAR ANCHO DEL SCROLLBAR + ============================================ */ +function getScrollbarWidth() { + return window.innerWidth - document.documentElement.clientWidth; +} -function updateProgress() { - for (let i = 0; i < 3; i++) { - document.getElementById('p' + (i + 1)).style.width = i <= current ? '100%' : '0%'; +function applyScrollbarCompensation() { + const scrollbarWidth = getScrollbarWidth(); + document.documentElement.style.setProperty('--scrollbar-width', `${scrollbarWidth}px`); +} + +/* ============================================ + MENÚ FULLSCREEN + ============================================ */ +function openMenu() { + const menu = document.getElementById('fullscreen-menu'); + const overlay = document.getElementById('menu-overlay'); + const menuToggle = document.querySelector('.menu-toggle'); + + if (menu && overlay) { + applyScrollbarCompensation(); + menu.classList.add('is-open'); + overlay.classList.add('is-open'); + document.body.classList.add('menu-open'); + menuToggle.setAttribute('aria-expanded', 'true'); } } -function next() { - document.querySelector('.step[data-step="' + current + '"]').classList.remove('active'); - current++; - document.querySelector('.step[data-step="' + current + '"]').classList.add('active'); - updateProgress(); -} - -function prev() { - document.querySelector('.step[data-step="' + current + '"]').classList.remove('active'); - current--; - document.querySelector('.step[data-step="' + current + '"]').classList.add('active'); - updateProgress(); -} - -const plans = [ - { name: 'Esencial', price: '$250.000 ARS', desc: 'Ideal para arrancar con presencia digital profesional y consistente, sin sobre-invertir todavía.' }, - { name: 'Impulso', price: '$420.000 ARS', desc: 'Pensado para marcas en crecimiento que necesitan más alcance, leads y una primera campaña de publicidad.' }, - { name: 'Premium', price: '$650.000 ARS + pauta', desc: 'Nuestro plan más recomendado: gestión integral de contenido, publicidad y estrategia para consolidar y expandir.' }, - { name: 'Elite', price: '$1.000.000 ARS', desc: 'Máximo posicionamiento y gestión de marca completa, para negocios listos para escalar en serio.' } -]; - -function showResult() { - document.querySelector('.step[data-step="2"]').classList.remove('active'); - const avg = Math.round((answers[0] + answers[1] + answers[2]) / 3); - const idx = Math.min(Math.max(avg - 1, 0), 3); - document.getElementById('rp-name').textContent = plans[idx].name; - document.getElementById('rp-price').innerHTML = plans[idx].price + ' / mes'; - document.getElementById('rp-desc').textContent = plans[idx].desc; - document.getElementById('result').classList.add('active'); -} - -function restart() { - answers[0] = answers[1] = answers[2] = null; - current = 0; - document.querySelectorAll('.opt').forEach(o => o.classList.remove('selected')); - document.querySelectorAll('[id^="next"]').forEach(b => b.disabled = true); - document.querySelectorAll('.q-num').forEach(q => q.classList.remove('active')); - document.getElementById('result').classList.remove('active'); - document.querySelectorAll('.step').forEach(s => s.classList.remove('active')); - document.querySelector('.step[data-step="0"]').classList.add('active'); - updateProgress(); -} - -// ===== FILTRO DE SERVICIOS EN CONTACTO ===== -function selectFilter(event) { - const el = event.currentTarget; - const container = el.parentElement; - container.querySelectorAll('.filter-tag').forEach(t => t.classList.remove('active')); - el.classList.add('active'); - const value = el.dataset.value; - document.getElementById('servicioSeleccionado').value = value; - const otroInput = document.getElementById('servicioOtro'); - if (value === 'otro') { - otroInput.style.display = 'block'; - otroInput.required = true; - } else { - otroInput.style.display = 'none'; - otroInput.required = false; - otroInput.value = ''; +function closeMenu() { + const menu = document.getElementById('fullscreen-menu'); + const overlay = document.getElementById('menu-overlay'); + const menuToggle = document.querySelector('.menu-toggle'); + + if (menu && overlay) { + menu.classList.remove('is-open'); + overlay.classList.remove('is-open'); + document.body.classList.remove('menu-open'); + menuToggle.setAttribute('aria-expanded', 'false'); } } -// ===== FORMULARIO ===== -function handleSubmit(e) { - e.preventDefault(); - const form = document.getElementById('contactForm'); - const data = new FormData(form); - const nombre = data.get('nombre'); - const email = data.get('email'); - const mensaje = data.get('mensaje'); - if (!nombre || !email || !mensaje) { - alert('Por favor, completá todos los campos obligatorios.'); - return false; - } - const btn = form.querySelector('button[type="submit"]'); - const originalText = btn.textContent; - btn.textContent = 'Enviando...'; - btn.disabled = true; - setTimeout(() => { - alert('¡Mensaje enviado con éxito! Te responderemos a la brevedad.'); - form.reset(); - btn.textContent = originalText; - btn.disabled = false; - document.querySelectorAll('.filter-tag').forEach(t => t.classList.remove('active')); - document.querySelector('.filter-tag[data-value="todos"]').classList.add('active'); - document.getElementById('servicioOtro').style.display = 'none'; - }, 1500); - return false; -} \ No newline at end of file +/* ============================================ + INICIALIZACIÓN + ============================================ */ +document.addEventListener('DOMContentLoaded', async () => { + // Cargar menú y footer + await Promise.all([ + loadInclude('#menu-container', 'includes/menu.html'), + loadInclude('#footer-container', 'includes/footer.html') + ]); + + // Inicializar tema + initTheme(); + + // Eventos del tema + const themeBtn = document.querySelector('.theme-toggle'); + if (themeBtn) themeBtn.addEventListener('click', toggleTheme); + + // Eventos del menú + const menuToggle = document.querySelector('.menu-toggle'); + const menuClose = document.querySelector('.menu-close'); + const menuOverlay = document.getElementById('menu-overlay'); + const menuLinks = document.querySelectorAll('.fullscreen-menu a'); + + if (menuToggle) menuToggle.addEventListener('click', openMenu); + if (menuClose) menuClose.addEventListener('click', closeMenu); + if (menuOverlay) menuOverlay.addEventListener('click', closeMenu); + + // Cerrar menú al hacer clic en un enlace + menuLinks.forEach(link => { + link.addEventListener('click', closeMenu); + }); + + // Cerrar menú con tecla Escape + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape') closeMenu(); + }); + + // Año dinámico en el footer + const yearEl = document.getElementById('current-year'); + if (yearEl) yearEl.textContent = new Date().getFullYear(); +}); \ No newline at end of file diff --git a/servicios.html b/servicios.html index e69de29..1ae3ebf 100644 --- a/servicios.html +++ b/servicios.html @@ -0,0 +1,29 @@ + + + + + + + Servicios - [Nombre de la agencia] + + + + + +
+

Sección 1

Contenido pendiente de definir.

+

Sección 2

Contenido pendiente de definir.

+

Sección 3

Contenido pendiente de definir.

+

Sección 4

Contenido pendiente de definir.

+

Sección 5

Contenido pendiente de definir.

+

Sección 6

Contenido pendiente de definir.

+

Sección 7

Contenido pendiente de definir.

+

Sección 8

Contenido pendiente de definir.

+
+ + + + + + + \ No newline at end of file diff --git a/style/blog.css b/style/blog.css new file mode 100644 index 0000000..e69de29 diff --git a/style/main.css b/style/main.css new file mode 100644 index 0000000..6a9f053 --- /dev/null +++ b/style/main.css @@ -0,0 +1,492 @@ +/* ============================================ + VARIABLES DE TEMA (modo claro por defecto) + ============================================ */ +:root { + /* Paleta Base / Primitivas de Marca */ + --brand-plum: #221728; + --brand-crimson: #ba124d; + --brand-teal: #003f52; + --brand-sage-light: #eaf0ee; + --brand-rose-muted: #dfbdb9; + + /* Tema Claro (Por Defecto) */ + --bg-base: var(--brand-sage-light); + --bg-surface: #ffffff; + --bg-surface-elevated: #f5f9f8; + + --text-primary: var(--brand-plum); + --text-secondary: var(--brand-teal); + --text-muted: rgba(34, 23, 40, 0.65); + --text-on-accent: #ffffff; + + --btn-primary-bg: var(--brand-crimson); + --btn-primary-hover: #9c0f40; + --btn-secondary-bg: var(--brand-teal); + --btn-secondary-hover: #002c3a; + + --badge-bg: var(--brand-rose-muted); + --badge-text: var(--brand-plum); + + --border: rgba(0, 63, 82, 0.12); + --shadow: 0 4px 20px -2px rgba(34, 23, 40, 0.08); + --glow-animation: rgba(186, 18, 77, 0.25); + + /* Tipografía - se completará */ + --font-family-base: sans-serif; + --font-size-base: 16px; + + /* Espaciados - se completarán */ + --spacing-xs: 0.5rem; + --spacing-sm: 1rem; + --spacing-md: 2rem; + --spacing-lg: 4rem; +} + +/* Modo oscuro */ +[data-theme="dark"] { + --bg-base: var(--brand-plum); + --bg-surface: #2d2034; + --bg-surface-elevated: #392842; + + --text-primary: var(--brand-sage-light); + --text-secondary: var(--brand-rose-muted); + --text-muted: rgba(234, 240, 238, 0.65); + --text-on-accent: #ffffff; + + --btn-primary-bg: var(--brand-crimson); + --btn-primary-hover: #d81a5c; + --btn-secondary-bg: #0b5066; + --btn-secondary-hover: #10637d; + + --badge-bg: rgba(223, 189, 185, 0.18); + --badge-text: var(--brand-rose-muted); + + --border: rgba(234, 240, 238, 0.12); + --shadow: 0 4px 24px -2px rgba(0, 0, 0, 0.45); + --glow-animation: rgba(186, 18, 77, 0.45); +} + +/* ============================================ + RESET BÁSICO + ============================================ */ +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html { + font-size: var(--font-size-base); + scroll-behavior: smooth; +} + +body { + font-family: var(--font-family-base); + background-color: var(--bg-base); + color: var(--text-primary); + line-height: 1.5; + min-height: 100vh; + display: flex; + flex-direction: column; + transition: background-color 0.3s ease, color 0.3s ease; +} + +body.menu-open { + overflow: hidden; + padding-right: var(--scrollbar-width, 0px); +} + +main { + flex: 1; +} + +img, +video { + max-width: 100%; + display: block; +} + +a { + color: inherit; + text-decoration: none; +} + +ul { + list-style: none; +} + +/* ============================================ + HEADER Y NAVEGACIÓN + ============================================ */ +.site-header { + background-color: var(--bg-surface); + border-bottom: 1px solid var(--border); + padding: var(--spacing-sm); + position: sticky; + top: 0; + z-index: 100; + box-shadow: var(--shadow); +} + +.main-nav { + display: flex; + justify-content: space-between; + align-items: center; + max-width: 1400px; + margin: 0 auto; +} + +/* Logo */ +.logo { + display: flex; + align-items: center; +} + +.logo img { + height: 40px; + width: auto; +} + +.logo-light { + display: block; +} + +.logo-dark { + display: none; +} + +[data-theme="dark"] .logo-light { + display: none; +} + +[data-theme="dark"] .logo-dark { + display: block; +} + +/* ============================================ + ESTILOS DE BARRA DE NAVEGACIÓN (BOTONES) + ============================================ */ + +/* Contenedor general de acciones */ +.nav-actions { + display: flex; + gap: var(--spacing-sm); + align-items: center; +} + +/* Base común para botones (menú y tema) */ +.menu-toggle, +.theme-toggle { + background: none; + border: 1px solid var(--border); + color: var(--text-primary); + padding: 0.5rem 1rem; + cursor: pointer; + font-size: 1rem; + border-radius: 4px; + transition: all 0.3s ease; +} + +.menu-toggle:hover, +.theme-toggle:hover { + background-color: var(--bg-surface-elevated); + border-color: var(--text-primary); +} + +/* ============================================ + SWITCH DE TEMA (ESPECÍFICO CON ANIMACIÓN) + ============================================ */ + +/* Ajustes del botón contenedor para que sea relativo y un círculo */ +.theme-toggle { + padding: 0; /* Removemos el padding para controlar el centrado */ + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; /* Es más estético como un círculo */ + overflow: hidden; /* Mantiene la rotación dentro del botón */ + position: relative; /* Esencial para superponer los iconos */ +} + +/* Estilos base para los iconos SVG */ +.theme-icon { + width: 20px; + height: 20px; + display: block; + position: absolute; /* Superponemos los iconos uno encima del otro */ + + /* === EL EFECTO: Transiciones suaves de opacidad y rotación === */ + transition: transform 0.5s ease, opacity 0.5s ease; +} + +/* --- LÓGICA DE VISIBILIDAD Y ANIMACIÓN CON DATA-THEME --- */ + +/* 1. MODO CLARO (POR DEFECTO) O INICIAL */ + +/* Sol (oculto en modo claro, rotado 180 grados y transparente) */ +[data-theme="light"] .icon-sun, +:root:not([data-theme="dark"]) .icon-sun { + opacity: 0; + transform: rotate(180deg); + pointer-events: none; /* No interactuable */ +} + +/* Luna (visible en modo claro, posición normal y opaca) */ +[data-theme="light"] .icon-moon, +:root:not([data-theme="dark"]) .icon-moon { + opacity: 1; + transform: rotate(0deg); + pointer-events: auto; /* Interactuable */ +} + + +/* 2. MODO OSCURO */ + +/* Sol (visible en modo oscuro, posición normal y opaco) */ +[data-theme="dark"] .icon-sun { + opacity: 1; + transform: rotate(0deg); + pointer-events: auto; /* Interactuable */ +} + +/* Luna (oculta en modo oscuro, rotada negativamente y transparente) */ +[data-theme="dark"] .icon-moon { + opacity: 0; + transform: rotate(-180deg); /* Rota en dirección opuesta al sol */ + pointer-events: none; /* No interactuable */ +} + +/* ============================================ + MENÚ DESPLEGABLE (desde abajo) + ============================================ */ +.menu-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + opacity: 0; + visibility: hidden; + transition: opacity 0.3s ease, visibility 0.3s ease; + z-index: 998; +} + +.menu-overlay.is-open { + opacity: 1; + visibility: visible; +} + +.fullscreen-menu { + position: fixed; + bottom: 0; + left: 0; + width: 100%; + height: 50vh; /* Mitad del alto en desktop */ + background-color: var(--bg-surface); + transform: translateY(100%); + transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1); + z-index: 999; + overflow-y: auto; + padding: var(--spacing-md) var(--spacing-lg); + box-shadow: 0 -4px 20px -2px rgba(0, 0, 0, 0.15); +} + +.fullscreen-menu.is-open { + transform: translateY(0); +} + +.menu-close { + position: absolute; + top: var(--spacing-sm); + right: var(--spacing-md); + background: none; + border: 1px solid var(--border); + color: var(--text-primary); + font-size: 1.5rem; + width: 40px; + height: 40px; + cursor: pointer; + border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; +} + +.menu-close:hover { + background-color: var(--bg-surface-elevated); + border-color: var(--text-primary); +} + +.menu-content { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: var(--spacing-md); + max-width: 1400px; + margin: 0 auto; + height: 100%; + align-content: start; +} + +.menu-column h3 { + font-size: 1rem; + margin-bottom: var(--spacing-sm); + color: var(--text-secondary); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.menu-column ul { + display: flex; + flex-direction: column; + gap: var(--spacing-xs); +} + +.menu-column a { + color: var(--text-primary); + font-size: 0.95rem; + transition: color 0.3s ease; + display: block; + padding: 0.2rem 0; +} + +.menu-column a:hover { + color: var(--btn-primary-bg); +} + +/* Columna 3 - Contacto y botones */ +.menu-contact-info { + margin-bottom: var(--spacing-sm); +} + +.menu-contact-info p { + margin-bottom: 0.25rem; + color: var(--text-muted); + font-size: 0.9rem; +} + +.menu-social { + display: flex; + gap: var(--spacing-sm); + margin-top: var(--spacing-xs); +} + +.menu-social a { + font-size: 0.9rem; + color: var(--text-secondary); +} + +.menu-buttons { + display: flex; + flex-direction: column; + gap: var(--spacing-xs); + margin-top: var(--spacing-sm); +} + +.btn-menu { + display: block; + padding: 0.6rem 1.2rem; + text-align: center; + border-radius: 4px; + font-weight: 600; + font-size: 0.9rem; + transition: all 0.3s ease; +} + +.btn-menu-primary { + background-color: var(--btn-primary-bg); + color: var(--text-on-accent); +} + +.btn-menu-primary:hover { + background-color: var(--btn-primary-hover); +} + +.btn-menu-secondary { + background-color: var(--btn-secondary-bg); + color: var(--text-on-accent); +} + +.btn-menu-secondary:hover { + background-color: var(--btn-secondary-hover); +} + +/* Responsive - Mobile */ +@media (max-width: 768px) { + .fullscreen-menu { + height: 85vh; /* En mobile ocupa más espacio */ + padding: var(--spacing-md); + } + + .menu-content { + grid-template-columns: 1fr; + gap: var(--spacing-md); + } + + .menu-column h3 { + font-size: 1.1rem; + } + + .menu-column a { + font-size: 1rem; + } +} + +/* Pantallas muy pequeñas */ +@media (max-width: 480px) { + .fullscreen-menu { + height: 90vh; + } +} + +/* ============================================ + SECCIONES BÁSICAS + ============================================ */ +main section { + padding: var(--spacing-md) var(--spacing-sm); + border-bottom: 1px dashed var(--border); +} + +main section h2 { + margin-bottom: var(--spacing-sm); + font-size: 1.5rem; +} + +/* ============================================ + FOOTER + ============================================ */ +.site-footer { + border-top: 1px solid var(--border); + padding: var(--spacing-md) var(--spacing-sm); + margin-top: auto; + background-color: var(--bg-surface); +} + +.footer-content { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: var(--spacing-md); + margin-bottom: var(--spacing-md); + max-width: 1400px; + margin-left: auto; + margin-right: auto; +} + +.footer-col h4 { + margin-bottom: var(--spacing-xs); + color: var(--text-secondary); +} + +.footer-bottom { + border-top: 1px solid var(--border); + padding-top: var(--spacing-sm); + text-align: center; + font-size: 0.875rem; + color: var(--text-muted); +} \ No newline at end of file diff --git a/styles/main.css b/styles/main.css deleted file mode 100644 index f9ed71e..0000000 --- a/styles/main.css +++ /dev/null @@ -1,768 +0,0 @@ -/* ===== FUENTES ===== */ -@import url('https://fonts.googleapis.com/css2?family=Literata:ital,wght@0,400;0,500;0,600;0,700;0,800;1,400;1,500;1,600;1,700;1,800&family=Raleway:wght@300;400;500;600;700&family=Jost:wght@300;400;500;600;700&display=swap'); - -/* ===== VARIABLES ===== */ -:root { - --teal: #003F52; - --ligth-teal: #006d8f; - --bordo: #BA124D; - --oscuro: #110916; - --casi-negro: #0B060E; - --dusty: #cec7d1; - --claro: #EAF0EE; - --rose-gold-1: #DFBDB9; - --rose-gold-2: #BA8B7A; - --rose-gold-3: #C89A82; - --font-display: 'Literata', serif; - --font-ui: 'Raleway', sans-serif; - --font-body: 'Jost', sans-serif; - --font-name: 'Kaleagnetta', handwriting; -} - -* { box-sizing: border-box; margin: 0; padding: 0; } - -body { - font-family: var(--font-body); - background: var(--oscuro); - color: var(--claro); - overflow-x: hidden; - font-weight: 300; -} - -/* ===== LOGO ===== */ -.logo-img { height: 32px; width: auto; display: block; } - -/* ===== CANVAS FLUIDO ===== */ -#fluidCanvas { - display: block; - width: 100%; - height: 100vh; - position: fixed; - top: 0; - left: 0; - z-index: 0; - pointer-events: auto; - background: var(--oscuro); -} - -/* Asegurar que el contenido esté por encima */ -.hero, section, .footer { - position: relative; - z-index: 1; -} - -/* ===== HEADER ===== */ -header { - position: fixed; top: 0; left: 0; right: 0; z-index: 50; - display: flex; align-items: center; justify-content: space-between; - padding: 26px 48px; - background: linear-gradient(180deg, rgba(17,9,22,.9) 0%, rgba(17,9,22,0) 100%); -} -.menu-btn { - display: flex; align-items: center; gap: 10px; - background: transparent; border: 1px solid rgba(234,240,238,.2); - border-radius: 100px; padding: 10px 20px; - color: var(--claro); font-family: var(--font-ui); font-size: 12px; - letter-spacing: .14em; text-transform: uppercase; font-weight: 500; - cursor: pointer; transition: .25s; -} -.menu-btn:hover { border-color: var(--claro); color: var(--claro); } -.menu-btn .bars { display: flex; flex-direction: column; gap: 3px; } -.menu-btn .bars span { width: 14px; height: 1.4px; background: currentColor; display: block; } - -/* ===== OVERLAY & SHEET ===== */ -.overlay { - position: fixed; inset: 0; background: rgba(0,0,0,1); - opacity: 0; pointer-events: none; transition: .35s; z-index: 90; -} -.overlay.open { opacity: 1; pointer-events: auto; } - -.sheet { - position: fixed; left: 0; right: 0; bottom: 0; z-index: 100; - background: var(--claro); border-radius: 22px 22px 0 0; - padding: 10px 36px 30px; - transform: translateY(102%); - transition: transform .4s cubic-bezier(.2,.8,.2,1); - max-height: 55vh; overflow-y: auto; - color: var(--oscuro); box-shadow: 0 -8px 40px rgba(0,0,0,.3); -} -.sheet.open { transform: translateY(0); } -.sheet-handle { width: 44px; height: 4px; background: rgba(34,23,40,.2); border-radius: 100px; margin: 0 auto 16px; } -.sheet-top { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } -.sheet-top .logo { font-size: 0; } -.sheet-top .logo img { height: 28px; width: auto; } -.close-btn { - width: 32px; height: 32px; border-radius: 100px; - border: 1px solid rgba(34,23,40,.2); - background: transparent; color: var(--oscuro); font-size: 14px; - cursor: pointer; display: flex; align-items: center; justify-content: center; - transition: .2s; -} -.close-btn:hover { border-color: var(--bordo); color: var(--bordo); } - -.sheet-body { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 30px; align-items: start; } -.sheet-col { display: flex; flex-direction: column; gap: 2px; } -.sheet-col-title { - font-family: var(--font-ui); font-size: 18px; font-weight: 500; - letter-spacing: .12em; text-transform: uppercase; - color: var(--bordo); margin-bottom: 8px; padding-right: 12px; text-align: right; -} -.sheet-link { - display: grid; grid-template-columns: 1fr 20px; align-items: center; - gap: 8px; padding: 6px 12px; border-radius: 6px; - text-decoration: none; color: var(--oscuro); transition: .2s; - background: transparent; text-align: right; -} -.sheet-link:hover { background: rgba(186,18,77,.06); } -.sheet-link-icon { font-size: 16px; color: var(--bordo); opacity: .4; text-align: center; grid-row: 1/3; grid-column: 2; } -.sheet-link-main { - font-family: var(--font-display); font-style: italic; font-weight: 600; - font-size: 18px; color: var(--oscuro); line-height: 1.2; grid-column: 1; -} -.sheet-link-desc { - font-family: var(--font-ui); font-size: 14px; color: var(--oscuro); - font-weight: 500; opacity: .8; grid-column: 1; margin-top: -2px; -} -.sheet-link.highlight { - background: var(--bordo); border-radius: 6px; padding: 10px 14px; margin-top: 6px; -} -.sheet-link.highlight .sheet-link-icon { color: #fff; opacity: 1; } -.sheet-link.highlight .sheet-link-main { color: #fff; } -.sheet-link.highlight .sheet-link-desc { color: rgba(255,255,255,.7); } -.sheet-link.highlight:hover { background: #9c0f40; } - -/* ===== HERO ===== */ -.hero { - min-height: 100vh; - display: flex; - flex-direction: column; - justify-content: center; - position: relative; - padding: 0 80px; - max-width: 1200px; - margin: 0 auto; - text-align: center; - pointer-events: none; -} -.hero-content { - position: relative; - z-index: 2; - max-width: 900px; - margin: 0 auto; - pointer-events: auto; -} - -/* ===== TIPOGRAFÍA ===== */ -.eyebrow { - font-family: var(--font-ui); font-size: 12px; letter-spacing: .28em; - text-transform: uppercase; color: var(--claro); margin-bottom: 22px; - display: flex; align-items: center; gap: 12px; opacity: 0.6; -} -.eyebrow::before { - content: ''; width: 30px; height: 1px; - background: linear-gradient(90deg, var(--rose-gold-3), var(--rose-gold-1)); -} -h1, h2 { - font-family: var(--font-display); font-weight: 500; font-style: italic; - font-size: clamp(40px, 6vw, 72px); - max-width: 900px; - line-height: 1.05; - margin-bottom: 16px; -} -.grad-word { - background: linear-gradient(100deg, var(--rose-gold-1) 0%, var(--bordo) 70%, var(--ligth-teal) 100%); - -webkit-background-clip: text; background-clip: text; color: transparent; -} -p, .lede { - font-family: var(--font-ui); font-size: 22px; line-height: 1.7; - color: var(--claro); max-width: 600px; margin: 0 auto 16px; opacity: 0.8; - font-weight: 400; -} -.lede { font-size: 18px; opacity: 0.7; max-width: 640px; } - -/* ===== BOTONES ===== */ -.btn { - font-family: var(--font-ui); font-size: 13px; font-weight: 500; - letter-spacing: .05em; padding: 16px 30px; border-radius: 2px; - cursor: pointer; transition: .25s; text-decoration: none; - display: inline-flex; align-items: center; gap: 8px; -} - -.btn-solid { - background: var(--bordo); color: #fff; border: 1px solid var(--bordo); -} -.btn-solid:hover { background: #9c0f40; } -.btn-outline { - background: transparent; color: var(--claro); - border: 1px solid rgba(234,240,238,.2); -} -.btn-outline:hover { border-color: var(--claro); color: var(--claro); } -.hero-actions { display: flex; gap: 16px; justify-content: center; margin-top: 40px; } -.hero-actions .btn { - pointer-events: auto; -} - -/* ===== HOME BUTTON ===== */ -.home-btn { - position: absolute; right: 20px; bottom: 20px; - font-size: 20px; color: var(--rose-gold-1); - text-decoration: none; transition: .3s; z-index: 10; - pointer-events: auto; -} -.home-btn:hover { color: rgba(234,240,238,.4); } - -/* ===== SCROLL HINT ===== */ -.scroll-hint { - position: absolute; bottom: 36px; left: 50%; transform: translateX(-50%); - font-family: var(--font-ui); font-size: 10.5px; letter-spacing: .2em; - text-transform: uppercase; color: rgba(234,240,238,.7); - display: flex; flex-direction: column; align-items: center; gap: 8px; - pointer-events: auto; -} -.scroll-hint .line { width: 1px; height: 36px; background: rgba(234,240,238,.5); } - -/* ===== SECCIONES GENERALES ===== */ -section { padding: 80px 48px; max-width: 1200px; margin: 0 auto; position: relative; } -section .eyebrow { justify-content: center; } -section h2 { text-align: center; max-width: 800px; margin: 0 auto 12px; } -section .lede { text-align: center; max-width: 900px; margin-bottom: 38px; } - -/* ===== SERVICIOS ===== */ -.tabs { - display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; - margin-bottom: 44px; border-bottom: 1px solid rgba(234,240,238,.06); -} -.tab { - font-family: var(--font-ui); font-size: 20px; font-weight: 400; - letter-spacing: .03em; color: var(--claro); - background: none; border: none; cursor: pointer; - padding: 14px 22px; position: relative; transition: .2s; -} -.tab .num { - font-family: var(--font-display); font-style: italic; font-size: 13px; - color: var(--claro); margin-right: 8px; -} -.tab.active { color: var(--claro); } -.tab.active::after { - content: ''; position: absolute; left: 0; right: 0; bottom: -1px; - height: 2px; background: linear-gradient(90deg, var(--rose-gold-3), var(--bordo)); -} -.tab:hover { color: var(--claro); } -.panel { display: none; animation: fade .4s ease; } -.panel.active { display: grid; grid-template-columns: 1fr 1fr; gap: 60px; align-items: start; } -@keyframes fade { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } -.panel-copy h3 { - font-family: var(--font-display); font-style: italic; font-weight: 500; - font-size: 25px; margin-bottom: 16px; -} -.panel-copy h3 em { color: var(--bordo); font-style: italic; } -.panel-copy p { font-size: 15px; max-width: 600px; margin-bottom: 26px; } - -.panel-list { display: flex; flex-direction: column; border-top: 1px solid rgba(234,240,238,.06); } -.panel-list .item { - display: flex; align-items: center; gap: 14px; - padding: 14px 0; border-bottom: 1px solid rgba(234,240,238,.06); - font-family: var(--font-ui); font-size: 15px; color: var(--claro); opacity: 0.8; -} -.icon-min { - font-size: 14px; color: var(--rose-gold-1); opacity: 0.5; - flex-shrink: 0; width: 24px; text-align: center; -} - -/* ===== PLANES ===== */ -.plans-grid { - display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; margin-bottom: 40px; -} -.plan-card { - background: rgba(22, 22, 9, 0.85); /* Antes era rgba(234,240,238,.03) */ - border: 1px solid rgba(234,240,238,.1); - border-radius: 10px; - padding: 30px 24px; - display: flex; - flex-direction: column; - text-align: center; - backdrop-filter: blur(4px); /* Opcional: agrega desenfoque al fondo */ -} -.plan-card.reco { - border: 1px solid rgba(223,189,185,.2); - background: rgba(234,240,238,.04); - box-shadow: 0 0 30px rgba(186,18,77,.2); -} -.badge { - align-self: center; font-family: var(--font-ui); font-size: 9px; font-weight: 700; - letter-spacing: .1em; text-transform: uppercase; - color: var(--bordo); border: 1px solid var(--bordo); - padding: 4px 14px; border-radius: 100px; margin-bottom: 14px; -} -.plan-name { - font-family: var(--font-display); font-style: italic; font-weight: 500; - font-size: 28px; margin-bottom: 4px; -} -.plan-stars { color: var(--claro); font-size: 11px; letter-spacing: 2px; margin-bottom: 14px; } -.plan-obj { - font-family: var(--font-ui); font-size: 18px; line-height: 1.5; - color: var(--claro); margin-bottom: 22px; min-height: 52px; -} -.plan-feats { list-style: none; flex: 1; margin-bottom: 24px; text-align: left; } -.plan-feats li { - font-family: var(--font-body); font-size: 18px; line-height: 1.5; - padding: 8px 0; border-top: 1px solid rgba(234,240,238,.08); - color: rgba(234,240,238,.7); -} -.plan-feats li:first-child { border-top: none; } -.plan-feats li::before { content: '— '; color: var(--claro); opacity: 1; } -.plan-cta { - font-family: var(--font-ui); font-size: 12px; font-weight: 500; - letter-spacing: .04em; text-align: center; padding: 12px; - border-radius: 2px; text-decoration: none; - border: 1px solid rgba(234,240,238,.15); color: var(--claro); - transition: .25s; -} -.plan-cta:hover { border-color: var(--claro); color: var(--claro); } -.plan-main-cta { display: block; max-width: 300px; margin: 0 auto; text-align: center; } - -/* ===== ACCORDION ===== */ -.acc { border-top: 1px solid rgba(234,240,238,.06); } -.acc-item { - border-bottom: 1px solid rgba(234,240,238,.06); - background: rgba(17, 9, 22, 0.7); /* Fondo sutil para cada item */ - border-radius: 10px; - padding: 2px 0 - -} -.acc-head { - display: flex; - align-items: center; - justify-content: space-between; - padding: 20px 24px; - cursor: pointer; -} -.acc-head-left { display: flex; align-items: center; gap: 16px; } -.acc-num { font-family: var(--font-display); font-style: italic; color: var(--dusty); font-size: 14px; opacity: 1; } -.acc-name { font-family: var(--font-ui); font-size: 26px; font-weight: 400; } -.acc-toggle { - width: 26px; - height: 26px; - border-radius: 100px; - border: 1px solid rgba(234,240,238,.15); - display: flex; - align-items: center; - justify-content: center; - font-size: 14px; - color: var(--claro); - transition: .25s; - line-height: 1; - position: relative; -} -.acc-toggle::before { - content: '+'; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); -} -.acc-item.open .acc-toggle { transform: rotate(45deg); border-color: var(--bordo); color: var(--bordo); } -.acc-body { max-height: 0; overflow: hidden; transition: .35s ease; } -.acc-item.open .acc-body { max-height: 600px; } -.acc-body-inner { - padding: 0 24px 24px 24px; - display: grid; - grid-template-columns: 1fr 1fr; - gap: 16px; -} -.service-row { - font-family: var(--font-ui); font-size: 14px; color: rgba(234,240,238,.8); - padding: 12px 0; border-top: 1px solid rgba(234,240,238,.04); -} -.service-row b { - display: block; - color: var(--claro); - font-family: var(--font-display); - font-style: italic; - font-size: 20px; - margin-bottom: 3px; - font-weight: 400; -} -.service-row .price { color: var(--dusty); font-family: var(--font-display); font-style: italic; font-size: 13px; } - -/* ===== PROCESO ===== */ -.arcade-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 14px; } -.column { position: relative; padding: 0 6px; text-align: center; } -.column:not(:last-child)::after { - content: ''; position: absolute; right: -7px; top: 14%; bottom: 44px; - width: 1px; background: rgba(234,240,238,0.4); -} -.arch { - width: 100%; aspect-ratio: 1/1; max-height: 110px; - border: 1.5px solid rgba(223,189,185,0.67); border-bottom: none; - border-radius: 100px 100px 0 0; - display: flex; align-items: flex-end; justify-content: center; - padding-bottom: 16px; margin-bottom: 16px; - transition: .3s; -} -.column:hover .arch { border-color: rgba(223,189,185,.3); } -.arch .num { - font-family: var(--font-display); - font-style: italic; font-weight: 500; - font-size: 16px; color: var(--claro); - opacity: 0.5; } -.arch.final { background: var(--bordo); - border-color: var(--bordo); } -.arch.final svg { width: 22px; height: 22px; stroke: #fff; fill: none; stroke-width: 2; } -.cat { - font-family: var(--font-ui); font-size: 14px; letter-spacing: .14em; - text-transform: uppercase; color: var(--ligth-teal); font-weight: 600; - margin-bottom: 12px; -} -.column:nth-child(even) .cat { color: var(--bordo); } -.step-title { - font-family: var(--font-display); font-style: italic; font-weight: 500; - font-size: 16px; margin-bottom: 6px; - margin-bottom: 10px; -} -.step-desc { - font-family: var(--font-ui); font-size: 12px; line-height: 1.5; - color: var(--claro); - } - -/* ===== CIFRAS ===== */ -.cifras-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; } -.cifra-card { - background: rgba(17, 9, 22, 0.85); - border: 1px solid rgba(234,240,238,.05); - border-radius: 10px; - padding: 34px 30px; - text-align: center; - backdrop-filter: blur(4px); -} -.cifra-icon { - width: 100px; height: 100px; margin: 0 auto 20px; - border: 1.5px solid rgba(223,189,185,0.67); border-bottom: none; - border-radius: 100px 100px 0 0; -} -.cifra-label { - font-family: var(--font-body); font-size: 16px; letter-spacing: .18em; - text-transform: uppercase; color: var(--claro); font-weight: 500; margin-bottom: 12px; -} -.cifra-value { - font-family: var(--font-display); font-style: italic; font-weight: 500; - font-size: 20px; color: var(--ligth-teal); margin-bottom: 14px; -} -.cifra-desc { - font-family: var(--font-body); font-size: 16px; line-height: 1.6; - color: var(--dusty); -} -.cifra-desc b { color: var(--claro); font-weight: 400; } - -/* ===== COTIZADOR ===== */ -.card { - background: rgba(17, 9, 22, 0.85); - border: 1px solid rgba(234,240,238,.1); - border-radius: 14px; - padding: 48px 52px; - max-width: 800px; - margin: 0 auto; - backdrop-filter: blur(4px); -} -.progress { display: flex; gap: 6px; margin-bottom: 36px; } -.progress .seg { height: 3px; flex: 1; background: rgba(234,240,238,.1); border-radius: 100px; overflow: hidden; } -.progress .seg i { display: block; height: 100%; width: 0%; background: -gradient(90deg, var(--rose-gold-3), var(--bordo)linear); transition: .4s; } -.step { display: none; } -.step.active { display: block; animation: fade .35s ease; } -.q-num { font-family: var(--font-display); font-style: italic; color: var(--dusty); font-size: 18px; margin-bottom: 10px; } -.q-title { font-family: var(--font-display); font-style: italic; font-weight: 500; font-size: 26px; margin-bottom: 28px; } -.options { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 32px; } -.opt { - border: 1px solid rgba(234,240,238,.15); - border-radius: 8px; - padding: 18px 20px; - cursor: pointer; - transition: .2s; - font-family: var(--font-ui); - background: rgba(17, 9, 22, 0.7); /* Fondo semi-transparente para opciones */ -} -.opt:hover { border-color: rgba(223,189,185,.3); } -.opt.selected { - border-color: var(--bordo); - background: rgba(186, 18, 77, 0.2); -} -.opt-title { font-size: 18px; font-weight: 500; color: var(--claro); margin-bottom: 3px; } -.opt-sub { font-size: 16px; color: var(--dusty); } -.nav-row { display: flex; justify-content: space-between; align-items: center; } -.btn-cotizador { - font-family: var(--font-ui); font-size: 13px; font-weight: 500; - padding: 12px 28px; border-radius: 4px; cursor: pointer; transition: .3s; - border: 1px solid var(--bordo); background: transparent; color: var(--bordo); -} -.btn-cotizador:hover:not(:disabled) { background: var(--bordo); color: #fff; } -.btn-cotizador:disabled { opacity: .2; cursor: not-allowed; border-color: #444; color: #666; } -.btn-cotizador-back { - font-family: var(--font-ui); font-size: 13px; font-weight: 500; - padding: 12px 28px; border-radius: 4px; cursor: pointer; transition: .3s; - border: 1px solid transparent; background: transparent; color: var(--dusty); -} -.btn-cotizador-back:hover { color: var(--claro); border-color: rgba(234,240,238,.1); } -.btn-cotizador-restart { - font-family: var(--font-ui); font-size: 13px; font-weight: 500; - padding: 12px 28px; border-radius: 4px; cursor: pointer; transition: .3s; - border: 1px solid var(--bordo); background: transparent; color: var(--bordo); -} -.btn-cotizador-restart:hover { background: var(--bordo); color: #fff; } -.result { display: none; text-align: center; padding-top: 10px; } -.result.active { display: block; animation: fade .4s ease; } -.result-badge { - font-family: var(--font-ui); font-size: 11px; letter-spacing: .14em; - text-transform: uppercase; color: var(--bordo); margin-bottom: 10px; -} -.result-plan { font-family: var(--font-display); font-style: italic; font-weight: 500; font-size: 32px; margin-bottom: 6px; } -.result-price { font-family: var(--font-display); font-style: italic; font-weight: 500; font-size: 22px; color: var(--bordo); margin-bottom: 18px; } -.result-desc { font-family: var(--font-body); font-size: 14px; color: var(--dusty); max-width: 400px; margin: 0 auto 30px; line-height: 1.6; } -.result-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; } - -/* ===== NOSOTROS ===== */ -.team-grid-simple { display: grid; grid-template-columns: 1fr 1fr; gap: 30px; max-width: 800px; margin: 0 auto; } -.team-card-simple { - background: rgba(17, 9, 22, 0.85); - border: 1px solid rgba(234,240,238,.1); - border-radius: 12px; - padding: 40px 32px; - text-align: center; - backdrop-filter: blur(4px); -} -.team-name { - font-family: var(--font-name); font-weight: 500; - font-size: 50px; margin-bottom: 8px; -} -.team-role { - font-family: var(--font-ui); font-size: 16px; font-weight: 400; - letter-spacing: .06em; text-transform: uppercase; color: var(--dusty); - margin-bottom: 12px; opacity: 0.6; -} -.team-detail { - font-family: var(--font-display); - font-weight: 200; - font-size: 16px; - line-height: 1.6; - color: var(--claro); -} -.team-footer { - margin-top: 10px; padding-top: 32px; - border-top: 1px solid rgba(234,240,238,.04); - text-align: center; -} -.team-footer-text { - font-family: var(--font-ui); font-size: 16px; color: var(--dusty); - max-width: 700px; margin: 0 auto; line-height: 1.6; -} - -/* ===== FAQ ===== */ -.faq-grid { border-top: 1px solid rgba(234,240,238,.06); max-width: 900px; margin: 0 auto; } -.faq-item { border-bottom: 1px solid rgba(234,240,238,.06); } -.faq-head { - display: flex; justify-content: space-between; align-items: center; - padding: 20px 4px; cursor: pointer; transition: .2s; -} -.faq-head:hover .faq-q { color: var(--claro); } -.faq-q { - font-family: var(--font-display); font-weight: 200; - font-size: 20px; transition: .2s; -} -.faq-toggle { - font-family: var(--font-body); font-size: 18px; font-weight: 300; - color: var(--rose-gold-1); width: 28px; height: 28px; - display: flex; align-items:center; justify-content: center; - border-radius: 100px; border: 1px solid rgba(234,240,238,.1); - transition: .25s; flex-shrink: 0; -} -.faq-item.open .faq-toggle { border-color: var(--bordo); color: var(--bordo); } -.faq-body { max-height: 0; overflow: hidden; transition: .4s ease; } -.faq-item.open .faq-body { max-height: 100px; } -.faq-body p { - font-family: var(--font-ui); font-size: 16px; line-height: 1.7; - color: var(--claro); padding: 0 4px 14px; max-width: 800px; -} - -/* ===== CONTACTO ===== */ -.contact-grid { display: grid; grid-template-columns: 1.6fr 1fr; gap: 48px; align-items: start; } -.contact-form-wrap { - background: rgba(17, 9, 22, 0.85); - border: 1px solid rgba(234,240,238,.1); - border-radius: 12px; - padding: 40px 36px; - backdrop-filter: blur(4px); -} -.contact-form { display: flex; flex-direction: column; gap: 18px; } -.form-row { display: flex; gap: 18px; } -.form-group { flex: 1; display: flex; flex-direction: column; gap: 4px; } -.form-group.full { flex: 0 0 100%; } -.form-group label { - font-family: var(--font-ui); font-size: 14px; font-weight: 500; - letter-spacing: .04em; text-transform: uppercase; color: rgba(234,240,238,0.8); -} -.form-group .req { color: var(--bordo); } -.form-group input, .form-group textarea { - font-family: var(--font-body); font-size: 16px; font-weight: 300; - padding: 12px 14px; border-radius: 6px; - border: 1px solid rgba(234,240,238,.08); - background: rgba(234,240,238,.03); color: var(--claro); - transition: .25s; width: 100%; -} -.form-group input:focus, .form-group textarea:focus { - outline: none; border-color: var(--bordo); - background: rgba(234,240,238,.06); -} -.filter-tags { display: flex; flex-wrap: wrap; gap: 8px; } -.filter-tag { - font-family: var(--font-ui); font-size: 13px; font-weight: 500; - padding: 6px 16px; border-radius: 100px; - border: 1px solid rgba(234,240,238,.5); background: transparent; - color: rgba(234,240,238,.4); cursor: pointer; transition: .2s; -} -.filter-tag:hover { border-color: var(--claro); color: var(--claro); } -.filter-tag.active { background: var(--bordo); border-color: var(--bordo); color: #fff; } -.checkbox-label { - display: flex; align-items: center; gap: 10px; - font-family: var(--font-body); font-size: 13px; color: rgba(234,240,238,.6); - cursor: pointer; -} -.checkbox-label input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--bordo); } - -.contact-direct { display: flex; flex-direction: column; gap: 16px; } -.contact-card { - display: flex; - align-items: flex-start; - gap: 16px; - padding: 18px 20px; - background: rgba(17, 9, 22, 0.85); - border: 1px solid rgba(234,240,238,.08); - border-radius: 10px; - backdrop-filter: blur(4px); -} -.contact-icon { font-size: 20px; line-height: 1.2; flex-shrink: 0; margin-top: 2px; } -.contact-label { - font-family: var(--font-ui); font-size: 14px; font-weight: 500; - letter-spacing: .08em; text-transform: uppercase; color: var(--claro); opacity: 0.5; -} -.contact-info a { font-family: var(--font-body); font-size: 14px; color: var(--claro); text-decoration: none; } -.contact-info a:hover { color: var(--claro); } -.contact-info span { font-family: var(--font-body); font-size: 13px; color: var(--claro); } -.contact-socials { display: flex; gap: 12px; } -.contact-socials a { - font-family: var(--font-ui); font-size: 13px; font-weight: 400; - color: var(--claro); text-decoration: none; opacity: 1; -} -.contact-socials a:hover { opacity: 1; } - -/* ===== FOOTER ===== */ -.footer { - background: rgba(0,0,0,.7); border-top: 1px solid rgba(234,240,238,.04); - padding: 60px 48px 20px; -} -.footer-inner { - max-width: 1200px; margin: 0 auto; display: grid; - grid-template-columns: 1fr 2fr; gap: 60px; padding-bottom: 40px; - border-bottom: 1px solid rgba(234,240,238,.04); -} -.footer-brand { display: flex; flex-direction: column; gap: 12px; } -.footer-desc { font-family: var(--font-ui); font-size: 16px; line-height: 1.6; color: var(--claro); max-width: 320px; } -.footer-links { display: grid; grid-template-columns: repeat(3, 1fr); gap: 40px; } -.footer-col h4 { - font-family: var(--font-ui); font-size: 12px; font-weight: 700; - letter-spacing: .1em; text-transform: uppercase; color: var(--dusty); opacity: 1; - margin-bottom: 12px; -} -.footer-col a { - display: block; font-family: var(--font-body); font-size: 13px; - color: var(--dusty); text-decoration: none; padding: 4px 0; - transition: .2s; -} -.footer-col a:hover { color: var(--claro); } -.footer-socials { display: flex; gap: 12px; margin-top: 8px; } -.footer-socials a { - font-family: var(--font-ui); font-size: 11px; font-weight: 500; - color: var(--claro); text-decoration: none; padding: 4px 12px; - border: 1px solid rgba(234,240,238,.08); border-radius: 100px; - transition: .2s; -} -.footer-socials a:hover { border-color: var(--claro); color: var(--claro); } -.footer-bottom { - max-width: 1200px; margin: 0 auto; padding-top: 20px; - display: flex; justify-content: space-between; align-items: center; - flex-wrap: wrap; gap: 12px; -} -.footer-bottom span { font-family: var(--font-body); font-size: 12px; color: rgba(234,240,238,.2); } -.footer-legal { display: flex; gap: 20px; } -.footer-legal a { font-family: var(--font-body); font-size: 12px; color: rgba(234,240,238,.2); text-decoration: none; } -.footer-legal a:hover { color: rgba(234,240,238,.5); } - -/* Todas las cards con fondo oscuro y blur */ -.plan-card, -.cifra-card, -.team-card-simple, -.contact-card, -.contact-form-wrap, -.card { - background: rgba(11, 5, 14, 0.85) !important; - backdrop-filter: blur(8px) !important; - -webkit-backdrop-filter: blur(8px) !important; - border: 1px solid rgba(234,240,238,0.08); -} - -/* ===== MENU (fondo claro) ===== */ -.sheet { - background: rgba(234, 240, 238, 0.95) !important; - backdrop-filter: blur(8px) !important; - -webkit-backdrop-filter: blur(8px) !important; - border: 1px solid rgba(34,23,40,0.08) !important; -} - -/* ===== RESPONSIVE ===== */ -@media (max-width: 980px) { - .plans-grid { grid-template-columns: 1fr 1fr; } - .arcade-grid { grid-template-columns: repeat(3, 1fr); row-gap: 40px; } - .column:nth-child(3)::after, .column:nth-child(6)::after { display: none; } - .cifras-grid { grid-template-columns: 1fr; } -} -@media (max-width: 820px) { - .sheet-body { grid-template-columns: 1fr 1fr; } - .sheet-col:last-child { grid-column: 1 / -1; } - .contact-grid { grid-template-columns: 1fr; } - .footer-inner { grid-template-columns: 1fr; gap: 40px; } - .team-grid-simple { grid-template-columns: 1fr; } -} -@media (max-width: 720px) { - header { padding: 20px 22px; } - .hero { padding: 0 30px; } - section { padding: 60px 22px; } - .panel.active { grid-template-columns: 1fr; gap: 30px; } - .plans-grid { grid-template-columns: 1fr; } - .arcade-grid { grid-template-columns: 1fr 1fr; row-gap: 30px; } - .column:nth-child(2n)::after { display: none; } - .options { grid-template-columns: 1fr; } - .card { padding: 32px 24px; } - .acc-body-inner { grid-template-columns: 1fr; } - .footer-links { grid-template-columns: 1fr 1fr; gap: 24px; } - .footer { padding: 40px 22px 16px; } - .footer-bottom { flex-direction: column; text-align: center; } -} -@media (max-width: 520px) { - .sheet { - position: fixed; - left: 0; - right: 0; - bottom: 0; - z-index: 100; - background: rgba(234, 240, 238, 0.95); /* Más opaco */ - border-radius: 22px 22px 0 0; - padding: 10px 36px 30px; - transform: translateY(102%); - transition: transform .4s cubic-bezier(.2,.8,.2,1); - max-height: 55vh; - overflow-y: auto; - color: var(--oscuro); - box-shadow: 0 -8px 40px rgba(0,0,0,.5); - backdrop-filter: blur(8px); } - .sheet-body { grid-template-columns: 1fr; gap: 16px; } - .sheet-col:last-child { grid-column: auto; } - .home-btn { right: 12px; bottom: 12px; font-size: 10px; } -} \ No newline at end of file