Update_02
@@ -0,0 +1,558 @@
|
||||
"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;
|
||||
|
||||
// ===== EVENTOS CON COLORES DE MARCA =====
|
||||
canvas.addEventListener("mousemove", function (e) {
|
||||
console.log("Mouse moviéndose:", e.clientX, e.clientY);
|
||||
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;
|
||||
pointers[0].dx = (e.offsetX - pointers[0].x) * 10.0;
|
||||
pointers[0].dy = (e.offsetY - pointers[0].y) * 10.0;
|
||||
pointers[0].x = e.offsetX;
|
||||
pointers[0].y = e.offsetY;
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
@@ -0,0 +1,674 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Amor & Roma — Estudio Creativo</title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- ===== CANVAS PARA EFECTO DE HUMO ===== -->
|
||||
<canvas id="fluidCanvas"></canvas>
|
||||
|
||||
<!-- ===== OVERLAY ===== -->
|
||||
<div class="overlay" id="overlay" onclick="toggleMenu()"></div>
|
||||
|
||||
<!-- ===== MENU BOTTOM SHEET ===== -->
|
||||
<nav class="sheet" id="sheet">
|
||||
<div class="sheet-handle"></div>
|
||||
<div class="sheet-top">
|
||||
<div class="logo">
|
||||
<a href="index.html">
|
||||
<img src="logo_ciruela.png" alt="Amor & Roma" class="logo-img">
|
||||
</a>
|
||||
</div>
|
||||
<button class="close-btn" onclick="toggleMenu()">✕</button>
|
||||
</div>
|
||||
<div class="sheet-body">
|
||||
<div class="sheet-col">
|
||||
<div class="sheet-col-title">Soluciones Web</div>
|
||||
<a href="#servicios" onclick="toggleMenu()" class="sheet-link">
|
||||
<span class="sheet-link-icon">⊞</span>
|
||||
<span class="sheet-link-main">Diseño Web</span>
|
||||
<span class="sheet-link-desc">Sitios informativos modernos</span>
|
||||
</a>
|
||||
<a href="#servicios" onclick="toggleMenu()" class="sheet-link">
|
||||
<span class="sheet-link-icon">⊞</span>
|
||||
<span class="sheet-link-main">E-commerce</span>
|
||||
<span class="sheet-link-desc">Tiendas online con todas las funcionalidades</span>
|
||||
</a>
|
||||
<a href="#servicios" onclick="toggleMenu()" class="sheet-link">
|
||||
<span class="sheet-link-icon">⊞</span>
|
||||
<span class="sheet-link-main">Google Ads</span>
|
||||
<span class="sheet-link-desc">Publicidad en Search y Display</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="sheet-col">
|
||||
<div class="sheet-col-title">Redes Sociales</div>
|
||||
<a href="#servicios" onclick="toggleMenu()" class="sheet-link">
|
||||
<span class="sheet-link-icon">⊞</span>
|
||||
<span class="sheet-link-main">Community Manager</span>
|
||||
<span class="sheet-link-desc">Administración profesional de redes</span>
|
||||
</a>
|
||||
<a href="#servicios" onclick="toggleMenu()" class="sheet-link">
|
||||
<span class="sheet-link-icon">⊞</span>
|
||||
<span class="sheet-link-main">Creación de Contenido</span>
|
||||
<span class="sheet-link-desc">Contenido original y atractivo</span>
|
||||
</a>
|
||||
<a href="#servicios" onclick="toggleMenu()" class="sheet-link">
|
||||
<span class="sheet-link-icon">⊞</span>
|
||||
<span class="sheet-link-main">Meta Ads</span>
|
||||
<span class="sheet-link-desc">Publicidad en Facebook e Instagram</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="sheet-col">
|
||||
<div class="sheet-col-title">Branding</div>
|
||||
<a href="#servicios" onclick="toggleMenu()" class="sheet-link">
|
||||
<span class="sheet-link-icon">⊞</span>
|
||||
<span class="sheet-link-main">Diseño de Logos</span>
|
||||
<span class="sheet-link-desc">Personalizados y profesionales</span>
|
||||
</a>
|
||||
<a href="#servicios" onclick="toggleMenu()" class="sheet-link">
|
||||
<span class="sheet-link-icon">⊞</span>
|
||||
<span class="sheet-link-main">Identidad de Marca</span>
|
||||
<span class="sheet-link-desc">Creación y desarrollo de marca</span>
|
||||
</a>
|
||||
<a href="#contacto" onclick="toggleMenu()" class="sheet-link highlight">
|
||||
<span class="sheet-link-icon">✉</span>
|
||||
<span class="sheet-link-main">Contacto</span>
|
||||
<span class="sheet-link-desc">Empezá tu proyecto</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- ===== HEADER ===== -->
|
||||
<header>
|
||||
<div class="logo">
|
||||
<img src="logo_frio.png" alt="Amor & Roma" class="logo-img">
|
||||
</div>
|
||||
<button class="menu-btn" onclick="toggleMenu()" aria-label="Abrir menú">
|
||||
<span class="bars"><span></span><span></span><span></span></span>
|
||||
<span class="menu-label">Menú</span>
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<!-- ===== HERO ===== -->
|
||||
<section class="hero" id="inicio">
|
||||
<div class="hero-content">
|
||||
<div class="eyebrow">Estudio Creativo · Agencia Boutique</div>
|
||||
<h1>Marcas con <span class="grad-word">esencia,</span><br>construidas con <span class="grad-word">estrategia.</span></h1>
|
||||
<p>Branding, diseño web y marketing digital para negocios que quieren crecer sin perder lo que los hace únicos.</p>
|
||||
<div class="hero-actions">
|
||||
<a href="#servicios" class="btn btn-solid">Ver servicios</a>
|
||||
<a href="#contacto" class="btn btn-outline">Contactanos</a>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#servicios" class="home-btn" aria-label="Ir a servicios">✦</a>
|
||||
<div class="scroll-hint"><div class="line"></div>Scroll</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== SERVICIOS ===== -->
|
||||
<section class="servicios" id="servicios">
|
||||
<div class="eyebrow">Lo que hacemos</div>
|
||||
<h2>Servicios pensados para marcas con <span class="grad-word">esencia.</span></h2>
|
||||
<p class="lede">Cuatro disciplinas que trabajan juntas, no por separado — cada proyecto se arma con la combinación justa para tu marca.</p>
|
||||
<div class="tabs">
|
||||
<button class="tab active" onclick="showTab(0,this)"><span class="num">01</span>Branding</button>
|
||||
<button class="tab" onclick="showTab(1,this)"><span class="num">02</span>Diseño Web</button>
|
||||
<button class="tab" onclick="showTab(2,this)"><span class="num">03</span>Marketing Digital</button>
|
||||
<button class="tab" onclick="showTab(3,this)"><span class="num">04</span>IA & Automatización</button>
|
||||
</div>
|
||||
<div class="panel active" data-panel="0">
|
||||
<div class="panel-copy">
|
||||
<h3>Identidad con <em>alma,</em><br>no solo con estilo.</h3>
|
||||
<p>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.</p>
|
||||
<a href="#contacto" class="btn btn-outline">Quiero mi identidad de marca →</a>
|
||||
</div>
|
||||
<div class="panel-list">
|
||||
<div class="item"><span class="icon-min">✦</span> Naming y concepto de marca</div>
|
||||
<div class="item"><span class="icon-min">✦</span> Diseño de logo e isotipo</div>
|
||||
<div class="item"><span class="icon-min">✦</span> Paleta, tipografía y manual de marca</div>
|
||||
<div class="item"><span class="icon-min">✦</span> Tono de voz y guía de comunicación</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel" data-panel="1">
|
||||
<div class="panel-copy">
|
||||
<h3>Sitios que <em>convierten,</em><br>no solo que se ven bien.</h3>
|
||||
<p>Diseño y desarrollo de sitios web a medida — rápidos, responsivos y pensados para que quien llega, actúe.</p>
|
||||
<a href="#contacto" class="btn btn-outline">Quiero mi sitio web →</a>
|
||||
</div>
|
||||
<div class="panel-list">
|
||||
<div class="item"><span class="icon-min">✦</span> Landing pages y sitios institucionales</div>
|
||||
<div class="item"><span class="icon-min">✦</span> UX/UI a medida</div>
|
||||
<div class="item"><span class="icon-min">✦</span> Optimización SEO técnica</div>
|
||||
<div class="item"><span class="icon-min">✦</span> E-commerce y tiendas online</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel" data-panel="2">
|
||||
<div class="panel-copy">
|
||||
<h3>Presencia <em>constante,</em><br>estrategia real.</h3>
|
||||
<p>Gestión de redes, contenido y pauta — con reportes claros para que sepas siempre qué está funcionando y por qué.</p>
|
||||
<a href="#contacto" class="btn btn-outline">Quiero mi estrategia digital →</a>
|
||||
</div>
|
||||
<div class="panel-list">
|
||||
<div class="item"><span class="icon-min">✦</span> Community management</div>
|
||||
<div class="item"><span class="icon-min">✦</span> Publicidad en Meta e Instagram Ads</div>
|
||||
<div class="item"><span class="icon-min">✦</span> Estrategia de contenido y calendario</div>
|
||||
<div class="item"><span class="icon-min">✦</span> Reportes mensuales de performance</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel" data-panel="3">
|
||||
<div class="panel-copy">
|
||||
<h3>Tecnología al servicio<br>de <em>tu tiempo.</em></h3>
|
||||
<p>Automatizamos lo repetitivo para que tu equipo se enfoque en lo estratégico — sin perder el trato cercano con tus clientes.</p>
|
||||
<a href="#contacto" class="btn btn-outline">Quiero automatizar procesos →</a>
|
||||
</div>
|
||||
<div class="panel-list">
|
||||
<div class="item"><span class="icon-min">✦</span> Chatbots y respuestas automáticas</div>
|
||||
<div class="item"><span class="icon-min">✦</span> Automatización de leads y seguimiento</div>
|
||||
<div class="item"><span class="icon-min">✦</span> Integraciones con CRM y WhatsApp</div>
|
||||
<div class="item"><span class="icon-min">✦</span> Consultoría en IA aplicada a tu negocio</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#planes" class="home-btn" aria-label="Ir a planes">✦</a>
|
||||
</section>
|
||||
|
||||
<!-- ===== PLANES ===== -->
|
||||
<section class="planes" id="planes">
|
||||
<div class="eyebrow">Inversión</div>
|
||||
<h2>Un plan para cada <span class="grad-word">etapa</span> de tu marca.</h2>
|
||||
<p class="lede">Cuatro niveles pensados para acompañar tu crecimiento — desde presencia digital consistente hasta gestión integral de marca.</p>
|
||||
<div class="plans-grid">
|
||||
<div class="plan-card">
|
||||
<div class="plan-name">Esencial</div>
|
||||
<div class="plan-stars">★</div>
|
||||
<div class="plan-obj">Establecer una presencia digital profesional y consistente.</div>
|
||||
<ul class="plan-feats">
|
||||
<li>2 redes sociales</li>
|
||||
<li>8 publicaciones + 8 historias / mes</li>
|
||||
<li>1 diseño de marca (logo)</li>
|
||||
<li>Reunión mensual de estrategia</li>
|
||||
<li>Reporte mensual de métricas</li>
|
||||
</ul>
|
||||
<a href="#contacto" class="plan-cta">+Info</a>
|
||||
</div>
|
||||
<div class="plan-card">
|
||||
<div class="plan-name">Impulso</div>
|
||||
<div class="plan-stars">★★</div>
|
||||
<div class="plan-obj">Aumentar visibilidad, interacción y generación de leads calificados.</div>
|
||||
<ul class="plan-feats">
|
||||
<li>2 redes · 12 publicaciones + 4 reels</li>
|
||||
<li>Logo + paleta de colores</li>
|
||||
<li>1 campaña Meta Ads + retargeting</li>
|
||||
<li>Automatización de respuestas frecuentes</li>
|
||||
<li>Gestión de Meta Business Suite</li>
|
||||
</ul>
|
||||
<a href="#contacto" class="plan-cta">+Info</a>
|
||||
</div>
|
||||
<div class="plan-card reco">
|
||||
<div class="badge">Más Popular</div>
|
||||
<div class="plan-name">Premium</div>
|
||||
<div class="plan-stars">★★★</div>
|
||||
<div class="plan-obj">Consolidar y expandir la empresa comercialmente.</div>
|
||||
<ul class="plan-feats">
|
||||
<li>3 redes · 16 publicaciones + 8 reels</li>
|
||||
<li>Sesión de fotos/video quincenal</li>
|
||||
<li>2 campañas Meta Ads + Google Ads</li>
|
||||
<li>Respuestas con IA 24/7</li>
|
||||
<li>Reporte semanal + reunión mensual</li>
|
||||
<li>Soporte prioritario</li>
|
||||
</ul>
|
||||
<a href="#contacto" class="plan-cta">+Info</a>
|
||||
</div>
|
||||
<div class="plan-card">
|
||||
<div class="plan-name">Elite</div>
|
||||
<div class="plan-stars">★★★★</div>
|
||||
<div class="plan-obj">Máximo posicionamiento y gestión integral de marca.</div>
|
||||
<ul class="plan-feats">
|
||||
<li>4 redes · 20 publicaciones + 16 reels</li>
|
||||
<li>Dirección creativa integral de marca</li>
|
||||
<li>3 campañas + TikTok Ads + Google Ads</li>
|
||||
<li>Estrategia 360° con planificación mensual</li>
|
||||
<li>Gestión de reputación online</li>
|
||||
</ul>
|
||||
<a href="#contacto" class="plan-cta">+Info</a>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#cotizador" class="btn btn-outline plan-main-cta">Consulta tu plan ideal</a>
|
||||
<a href="#proceso" class="home-btn" aria-label="Ir a proceso">✦</a>
|
||||
</section>
|
||||
|
||||
<!-- ===== SERVICIOS A LA CARTA ===== -->
|
||||
<section class="servicios-carta" id="servicios-carta">
|
||||
<div class="eyebrow">Servicios a la carta</div>
|
||||
<h2>Para complementar cualquier <span class="grad-word">plan,</span><br>o contratar de forma <span class="grad-word">independiente.</span></h2>
|
||||
<p class="lede">Elegí los servicios que necesitás, sin compromiso mensual. Todo lo que tu marca necesita, a tu ritmo.</p>
|
||||
<div class="acc" id="acc">
|
||||
<div class="acc-item open">
|
||||
<div class="acc-head" onclick="toggleAcc(this)">
|
||||
<div class="acc-head-left"><span class="acc-num">01</span><span class="acc-name">Diseño Web & Desarrollo</span></div>
|
||||
<div class="acc-toggle">+</div>
|
||||
</div>
|
||||
<div class="acc-body">
|
||||
<div class="acc-body-inner">
|
||||
<div class="service-row"><b>Landing Page Profesional</b>Diseño de una sección, UI/UX + SEO básico <span class="price">Desde $350.000</span></div>
|
||||
<div class="service-row"><b>Sitio Institucional (hasta 7 secciones)</b>Inicio, Servicios, Nosotros, Blog, Contacto <span class="price">Desde $600.000</span></div>
|
||||
<div class="service-row"><b>E-commerce</b>Tienda online autoadministrable con pasarela de pago <span class="price">Desde $900.000</span></div>
|
||||
<div class="service-row"><b>Mantenimiento Web</b>Backups, seguridad y soporte técnico <span class="price">Desde $50.000/mes</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="acc-item">
|
||||
<div class="acc-head" onclick="toggleAcc(this)">
|
||||
<div class="acc-head-left"><span class="acc-num">02</span><span class="acc-name">Branding e Identidad Visual</span></div>
|
||||
<div class="acc-toggle">+</div>
|
||||
</div>
|
||||
<div class="acc-body">
|
||||
<div class="acc-body-inner">
|
||||
<div class="service-row"><b>Diseño de Logotipo</b>3 propuestas + revisiones <span class="price">Desde $180.000</span></div>
|
||||
<div class="service-row"><b>Manual de Marca Completo</b>Logo, paleta, tipografías, tono de voz <span class="price">Desde $300.000</span></div>
|
||||
<div class="service-row"><b>Rediseño de Identidad Visual</b>Actualización de marca existente <span class="price">A cotizar</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="acc-item">
|
||||
<div class="acc-head" onclick="toggleAcc(this)">
|
||||
<div class="acc-head-left"><span class="acc-num">03</span><span class="acc-name">Publicidad Digital Avanzada</span></div>
|
||||
<div class="acc-toggle">+</div>
|
||||
</div>
|
||||
<div class="acc-body">
|
||||
<div class="acc-body-inner">
|
||||
<div class="service-row"><b>Campaña Google Ads</b>Búsqueda y display <span class="price">Desde $150.000/mes</span></div>
|
||||
<div class="service-row"><b>Campaña TikTok Ads</b>Alcance a audiencias jóvenes <span class="price">Desde $120.000/mes</span></div>
|
||||
<div class="service-row"><b>Auditoría de Campañas</b>Análisis y oportunidades de mejora <span class="price">Desde $90.000</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="acc-item">
|
||||
<div class="acc-head" onclick="toggleAcc(this)">
|
||||
<div class="acc-head-left"><span class="acc-num">04</span><span class="acc-name">Diseño Digital & Gráfico</span></div>
|
||||
<div class="acc-toggle">+</div>
|
||||
</div>
|
||||
<div class="acc-body">
|
||||
<div class="acc-body-inner">
|
||||
<div class="service-row"><b>Infografías</b>Comunicación visual de datos y procesos <span class="price">Desde $80.000/u</span></div>
|
||||
<div class="service-row"><b>Plantillas para Redes</b>Set editable de 5 piezas <span class="price">Desde $100.000</span></div>
|
||||
<div class="service-row"><b>Material Impreso</b>Flyers, folletos, tarjetas <span class="price">A cotizar</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="acc-item">
|
||||
<div class="acc-head" onclick="toggleAcc(this)">
|
||||
<div class="acc-head-left"><span class="acc-num">05</span><span class="acc-name">Producción Audiovisual</span></div>
|
||||
<div class="acc-toggle">+</div>
|
||||
</div>
|
||||
<div class="acc-body">
|
||||
<div class="acc-body-inner">
|
||||
<div class="service-row"><b>Sesión Fotográfica</b>Producto, instalaciones o equipo <span class="price">A cotizar</span></div>
|
||||
<div class="service-row"><b>Reel / Video Corto</b>Hasta 30 segundos, con edición <span class="price">Desde $120.000</span></div>
|
||||
<div class="service-row"><b>Pack de 3 Reels</b>Contenido consistente de alto impacto <span class="price">Desde $300.000</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#cifras" class="home-btn" aria-label="Ir a cifras">✦</a>
|
||||
</section>
|
||||
|
||||
<!-- ===== PROCESO ===== -->
|
||||
<section class="proceso" id="proceso">
|
||||
<div class="eyebrow">Cómo trabajamos</div>
|
||||
<h2>Tu proyecto, paso a paso, y sin <span class="grad-word">sorpresas.</span></h2>
|
||||
<p class="lede">Un proceso claro y colaborativo — sabés exactamente qué pasa en cada etapa, sin plantillas genéricas.</p>
|
||||
<div class="arcade-grid">
|
||||
<div class="column">
|
||||
<div class="arch"><span class="num">01</span></div>
|
||||
<div class="cat">Contacto</div>
|
||||
<div class="step-title">Reunión de brief</div>
|
||||
<div class="step-desc">Nos contás tu marca y objetivos.</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="arch"><span class="num">02</span></div>
|
||||
<div class="cat">Propuesta</div>
|
||||
<div class="step-title">Plan de trabajo</div>
|
||||
<div class="step-desc">Entregables, inversión y tiempos.</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="arch"><span class="num">03</span></div>
|
||||
<div class="cat">Diseño</div>
|
||||
<div class="step-title">Dirección de arte</div>
|
||||
<div class="step-desc">Concepto visual a tu aprobación.</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="arch"><span class="num">04</span></div>
|
||||
<div class="cat">Producción</div>
|
||||
<div class="step-title">Desarrollo</div>
|
||||
<div class="step-desc">Construimos con seguimiento.</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="arch"><span class="num">05</span></div>
|
||||
<div class="cat">Revisión</div>
|
||||
<div class="step-title">Ajustes finales</div>
|
||||
<div class="step-desc">Tu feedback moldea el resultado.</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="arch final"><svg viewBox="0 0 24 24" stroke="currentColor" fill="none" stroke-width="2.4"><path d="M5 12l5 5L19 7"/></svg></div>
|
||||
<div class="cat">Lanzamiento</div>
|
||||
<div class="step-title">Entrega</div>
|
||||
<div class="step-desc">Accesos y capacitación completa.</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#cifras" class="home-btn" aria-label="Ir a cifras">✦</a>
|
||||
</section>
|
||||
|
||||
<!-- ===== CIFRAS ===== -->
|
||||
<section class="cifras" id="cifras">
|
||||
<div class="eyebrow">Inversión & tiempos</div>
|
||||
<h2>Transparencia antes de la <span class="grad-word">primera reunión.</span></h2>
|
||||
<p class="lede">Los números, dichos de entrada — no como parte de una negociación, sino como punto de partida.</p>
|
||||
<div class="cifras-grid">
|
||||
<div class="cifra-card">
|
||||
<div class="cifra-icon"></div>
|
||||
<div class="cifra-label">Inversión</div>
|
||||
<div class="cifra-value">Desde $250.000/mes</div>
|
||||
<div class="cifra-desc">Planes desde <b>$250.000</b> (Esencial) hasta <b>$1.000.000</b> (Elite). El armado inicial —branding, sitio web— se presupuesta por proyecto.</div>
|
||||
</div>
|
||||
<div class="cifra-card">
|
||||
<div class="cifra-icon"></div>
|
||||
<div class="cifra-label">Tiempos</div>
|
||||
<div class="cifra-value">15–30 días</div>
|
||||
<div class="cifra-desc">Presencia digital lista en <b>15-30 días</b>. Resultados de posicionamiento sostenido en <b>3-6 meses</b>. Sin promesas de magia inmediata.</div>
|
||||
</div>
|
||||
<div class="cifra-card">
|
||||
<div class="cifra-icon"></div>
|
||||
<div class="cifra-label">Contrato</div>
|
||||
<div class="cifra-value">3 meses · luego mensual</div>
|
||||
<div class="cifra-desc">Compromiso mínimo de <b>3 meses</b> para que la estrategia tome forma, luego renovación mensual. Cancelación <b>con 30 días de aviso</b>.</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#cotizador" class="home-btn" aria-label="Ir a cotizador">✦</a>
|
||||
</section>
|
||||
|
||||
<!-- ===== COTIZADOR ===== -->
|
||||
<section class="cotizador" id="cotizador">
|
||||
<div class="eyebrow">Cotizador</div>
|
||||
<h2>¿Cuál es tu <span class="grad-word">plan ideal</span><span class="signopreg">?</span></h2>
|
||||
<p class="lede">3 preguntas rápidas y te decimos qué plan se ajusta mejor a tu marca.</p>
|
||||
<div class="card">
|
||||
<div class="progress">
|
||||
<div class="seg"><i id="p1"></i></div>
|
||||
<div class="seg"><i id="p2"></i></div>
|
||||
<div class="seg"><i id="p3"></i></div>
|
||||
</div>
|
||||
<div class="step active" data-step="0">
|
||||
<div class="q-num">Pregunta 01</div>
|
||||
<div class="q-title">¿Cómo describirías el momento de tu negocio?</div>
|
||||
<div class="options" data-q="0">
|
||||
<div class="opt" data-val="1"><div class="opt-title">Recién empezando</div><div class="opt-sub">Necesito presencia digital desde cero</div></div>
|
||||
<div class="opt" data-val="2"><div class="opt-title">En crecimiento</div><div class="opt-sub">Ya tengo redes, quiero más alcance</div></div>
|
||||
<div class="opt" data-val="3"><div class="opt-title">Establecido</div><div class="opt-sub">Busco consolidar y vender más</div></div>
|
||||
<div class="opt" data-val="4"><div class="opt-title">Consolidado</div><div class="opt-sub">Quiero gestión integral de marca</div></div>
|
||||
</div>
|
||||
<div class="nav-row"><span></span><button class="btn btn-cotizador" onclick="next()" disabled id="next0">Siguiente →</button></div>
|
||||
</div>
|
||||
<div class="step" data-step="1">
|
||||
<div class="q-num">Pregunta 02</div>
|
||||
<div class="q-title">¿Qué es lo que más necesitás hoy?</div>
|
||||
<div class="options" data-q="1">
|
||||
<div class="opt" data-val="1"><div class="opt-title">Presencia en redes</div><div class="opt-sub">Contenido consistente y profesional</div></div>
|
||||
<div class="opt" data-val="2"><div class="opt-title">Más leads y ventas</div><div class="opt-sub">Publicidad digital que convierta</div></div>
|
||||
<div class="opt" data-val="3"><div class="opt-title">Producción de contenido</div><div class="opt-sub">Fotos, video y piezas de calidad</div></div>
|
||||
<div class="opt" data-val="4"><div class="opt-title">Todo integrado</div><div class="opt-sub">Estrategia 360° gestionada por otros</div></div>
|
||||
</div>
|
||||
<div class="nav-row"><button class="btn btn-cotizador-back" onclick="prev()">← Atrás</button><button class="btn btn-cotizador" onclick="next()" disabled id="next1">Siguiente →</button></div>
|
||||
</div>
|
||||
<div class="step" data-step="2">
|
||||
<div class="q-num">Pregunta 03</div>
|
||||
<div class="q-title">¿Cuál es tu presupuesto mensual aproximado?</div>
|
||||
<div class="options" data-q="2">
|
||||
<div class="opt" data-val="1"><div class="opt-title">Hasta $300.000</div><div class="opt-sub">ARS / mes</div></div>
|
||||
<div class="opt" data-val="2"><div class="opt-title">$300.000 – $450.000</div><div class="opt-sub">ARS / mes</div></div>
|
||||
<div class="opt" data-val="3"><div class="opt-title">$450.000 – $700.000</div><div class="opt-sub">ARS / mes</div></div>
|
||||
<div class="opt" data-val="4"><div class="opt-title">Más de $700.000</div><div class="opt-sub">ARS / mes</div></div>
|
||||
</div>
|
||||
<div class="nav-row"><button class="btn btn-cotizador-back" onclick="prev()">← Atrás</button><button class="btn btn-cotizador" onclick="showResult()" disabled id="next2">Ver resultado →</button></div>
|
||||
</div>
|
||||
<div class="result" id="result">
|
||||
<div class="result-badge">Tu plan recomendado</div>
|
||||
<div class="result-plan" id="rp-name">—</div>
|
||||
<div class="result-price" id="rp-price">—</div>
|
||||
<p class="result-desc" id="rp-desc">—</p>
|
||||
<div class="result-actions">
|
||||
<a class="btn btn-solid" href="#contacto">Quiero este plan</a>
|
||||
<button class="btn btn-cotizador-restart" onclick="restart()">Volver a empezar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#nosotros" class="home-btn" aria-label="Ir a nosotros">✦</a>
|
||||
</section>
|
||||
|
||||
<!-- ===== NOSOTROS ===== -->
|
||||
<section class="quienes" id="nosotros">
|
||||
<div class="eyebrow">Nosotros</div>
|
||||
<h2>Un equipo chico, con <span class="grad-word">mucha energía.</span></h2>
|
||||
<p class="lede">Creemos que las marcas se construyen con escucha, estrategia y mucho amor por lo que hacemos.</p>
|
||||
<div class="team-grid team-grid-simple">
|
||||
<div class="team-card-simple">
|
||||
<div class="team-name">Patricia Pugliese</div>
|
||||
<div class="team-role">Estrategia & Creatividad</div>
|
||||
<div class="team-detail">Investigación, branding, identidad visual y todo lo que da forma a una marca con personalidad.</div>
|
||||
</div>
|
||||
<div class="team-card-simple">
|
||||
<div class="team-name">Francisco Anfuso</div>
|
||||
<div class="team-role">Desarrollo & Tecnología</div>
|
||||
<div class="team-detail">Diseño web, desarrollo, automatizaciones y soluciones técnicas que funcionan sin complicaciones.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="team-footer">
|
||||
<p class="team-footer-text">Y como todo equipo en crecimiento, sumamos colaboradores según el proyecto — diseñadores, redactores y especialistas que se suman cuando hace falta.</p>
|
||||
</div>
|
||||
<a href="#faq" class="home-btn" aria-label="Ir a FAQ">✦</a>
|
||||
</section>
|
||||
|
||||
<!-- ===== FAQ ===== -->
|
||||
<section class="faq" id="faq">
|
||||
<div class="eyebrow">Preguntas Frecuentes</div>
|
||||
<h2>Todo lo que necesitás saber <span class="grad-word">antes de empezar.</span></h2>
|
||||
<p class="lede">Respondemos las dudas más comunes para que llegues con confianza al primer encuentro.</p>
|
||||
<div class="faq-grid">
|
||||
<div class="faq-item open">
|
||||
<div class="faq-head" onclick="toggleFaq(this)">
|
||||
<span class="faq-q">¿Cómo funciona el proceso de trabajo?</span>
|
||||
<span class="faq-toggle">−</span>
|
||||
</div>
|
||||
<div class="faq-body"><p>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.</p></div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<div class="faq-head" onclick="toggleFaq(this)">
|
||||
<span class="faq-q">¿Qué incluye exactamente cada plan?</span>
|
||||
<span class="faq-toggle">+</span>
|
||||
</div>
|
||||
<div class="faq-body"><p>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.</p></div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<div class="faq-head" onclick="toggleFaq(this)">
|
||||
<span class="faq-q">¿Puedo contratar servicios sueltos sin un plan mensual?</span>
|
||||
<span class="faq-toggle">+</span>
|
||||
</div>
|
||||
<div class="faq-body"><p>¡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.</p></div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<div class="faq-head" onclick="toggleFaq(this)">
|
||||
<span class="faq-q">¿Qué resultados puedo esperar?</span>
|
||||
<span class="faq-toggle">+</span>
|
||||
</div>
|
||||
<div class="faq-body"><p>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.</p></div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<div class="faq-head" onclick="toggleFaq(this)">
|
||||
<span class="faq-q">¿Trabajan con negocios de cualquier rubro?</span>
|
||||
<span class="faq-toggle">+</span>
|
||||
</div>
|
||||
<div class="faq-body"><p>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.</p></div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<div class="faq-head" onclick="toggleFaq(this)">
|
||||
<span class="faq-q">¿Cómo facturan? ¿Hay algún costo de inicio?</span>
|
||||
<span class="faq-toggle">+</span>
|
||||
</div>
|
||||
<div class="faq-body"><p>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).</p></div>
|
||||
</div>
|
||||
<div class="faq-item">
|
||||
<div class="faq-head" onclick="toggleFaq(this)">
|
||||
<span class="faq-q">¿Puedo cambiar de plan o cancelar cuando quiera?</span>
|
||||
<span class="faq-toggle">+</span>
|
||||
</div>
|
||||
<div class="faq-body"><p>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.</p></div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#contacto" class="home-btn" aria-label="Ir a contacto">✦</a>
|
||||
</section>
|
||||
|
||||
<!-- ===== CONTACTO ===== -->
|
||||
<section class="contacto" id="contacto">
|
||||
<div class="eyebrow">Contacto</div>
|
||||
<h2>¿Empezamos a <span class="grad-word">construir</span> tu marca?</h2>
|
||||
<p class="lede">Completá el formulario o escribinos directo — te respondemos en menos de 24 horas.</p>
|
||||
<div class="contact-grid">
|
||||
<div class="contact-form-wrap">
|
||||
<form class="contact-form" id="contactForm" onsubmit="return handleSubmit(event)">
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label for="nombre">Nombre completo <span class="req">*</span></label>
|
||||
<input type="text" id="nombre" name="nombre" required placeholder="Tu nombre">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email">Email <span class="req">*</span></label>
|
||||
<input type="email" id="email" name="email" required placeholder="tu@email.com">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label for="empresa">Empresa / Emprendimiento</label>
|
||||
<input type="text" id="empresa" name="empresa" placeholder="Nombre de tu marca">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="telefono">Teléfono</label>
|
||||
<input type="tel" id="telefono" name="telefono" placeholder="+54 9 388 000-0000">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group full">
|
||||
<label for="servicio">¿Qué servicio te interesa? <span class="req">*</span></label>
|
||||
<div class="filter-tags" id="servicioFilter">
|
||||
<button type="button" class="filter-tag active" data-value="todos" onclick="selectFilter(event)">Todos</button>
|
||||
<button type="button" class="filter-tag" data-value="branding" onclick="selectFilter(event)">Branding</button>
|
||||
<button type="button" class="filter-tag" data-value="web" onclick="selectFilter(event)">Diseño Web</button>
|
||||
<button type="button" class="filter-tag" data-value="marketing" onclick="selectFilter(event)">Marketing Digital</button>
|
||||
<button type="button" class="filter-tag" data-value="ia" onclick="selectFilter(event)">IA & Automatización</button>
|
||||
<button type="button" class="filter-tag" data-value="otro" onclick="selectFilter(event)">Otro</button>
|
||||
</div>
|
||||
<input type="hidden" id="servicioSeleccionado" name="servicio" value="todos">
|
||||
<input type="text" id="servicioOtro" name="servicio_otro" placeholder="Especificá cuál..." style="display:none; margin-top:10px; width:100%;">
|
||||
</div>
|
||||
<div class="form-group full">
|
||||
<label for="mensaje">¿Qué necesitás? <span class="req">*</span></label>
|
||||
<textarea id="mensaje" name="mensaje" required placeholder="Contanos sobre tu proyecto, tus objetivos y lo que estás buscando..." rows="5"></textarea>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group" style="flex:1;">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" required>
|
||||
<span>Acepto la <a href="#" style="color:var(--bordo);">política de privacidad</a></span>
|
||||
</label>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-solid" style="padding:14px 44px;">Enviar mensaje</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="contact-direct">
|
||||
<div class="contact-card">
|
||||
<div class="contact-icon">📧</div>
|
||||
<div class="contact-info">
|
||||
<div class="contact-label">Email</div>
|
||||
<a href="mailto:contacto@amoryroma.com.ar">contacto@amoryroma.com.ar</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="contact-card">
|
||||
<div class="contact-icon">💬</div>
|
||||
<div class="contact-info">
|
||||
<div class="contact-label">WhatsApp</div>
|
||||
<a href="https://wa.me/5493886118304" target="_blank">+54 9 388 611-8304</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="contact-card">
|
||||
<div class="contact-icon">📱</div>
|
||||
<div class="contact-info">
|
||||
<div class="contact-label">Redes</div>
|
||||
<div class="contact-socials">
|
||||
<a href="https://www.instagram.com/amoryroma.creativo/" target="_blank">Instagram</a>
|
||||
<a href="https://www.linkedin.com/in/patricia-pugliese/" target="_blank">LinkedIn</a>
|
||||
<a href="https://web.facebook.com/amoryroma.creativo" target="_blank">Facebook</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="contact-card">
|
||||
<div class="contact-icon">📍</div>
|
||||
<div class="contact-info">
|
||||
<div class="contact-label">Argentina</div>
|
||||
<span style="font-size:13px; color:var(--dusty);">Trabajamos remoto worldwide</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#inicio" class="home-btn" aria-label="Volver arriba">✦</a>
|
||||
</section>
|
||||
|
||||
<!-- ===== FOOTER ===== -->
|
||||
<footer class="footer">
|
||||
<div class="footer-inner">
|
||||
<div class="footer-brand">
|
||||
<div class="footer-logo"><img src="logo_frio.png" alt="Amor & Roma" style="height:36px;width:auto;"></div>
|
||||
<p class="footer-desc">Branding, diseño web y marketing digital para marcas con esencia.</p>
|
||||
</div>
|
||||
<div class="footer-links">
|
||||
<div class="footer-col">
|
||||
<h4>Navegación</h4>
|
||||
<a href="#servicios">Servicios</a>
|
||||
<a href="#planes">Planes</a>
|
||||
<a href="#nosotros">Nosotros</a>
|
||||
<a href="#cifras">Cifras</a>
|
||||
<a href="#faq">FAQ</a>
|
||||
<a href="#contacto">Contacto</a>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<h4>Servicios</h4>
|
||||
<a href="#servicios">Branding</a>
|
||||
<a href="#servicios">Diseño Web</a>
|
||||
<a href="#servicios">Marketing Digital</a>
|
||||
<a href="#servicios">IA & Automatización</a>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<h4>Contacto</h4>
|
||||
<a href="mailto:contacto@amoryroma.com.ar">contacto@amoryroma.com.ar</a>
|
||||
<a href="https://wa.me/5493886118304" target="_blank">+54 9 388 611-8304</a>
|
||||
<div class="footer-socials">
|
||||
<a href="https://www.instagram.com/amoryroma.creativo/" target="_blank" aria-label="Instagram">IG</a>
|
||||
<a href="https://www.linkedin.com/in/patricia-pugliese/" target="_blank" aria-label="LinkedIn">IN</a>
|
||||
<a href="https://web.facebook.com/amoryroma.creativo" target="_blank" aria-label="Facebook">FB</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<span>© 2026 Amor & Roma — Estudio Creativo. Todos los derechos reservados.</span>
|
||||
<span class="footer-legal"><a href="#">Política de privacidad</a><a href="#">Términos y condiciones</a></span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- ===== SCRIPTS ===== -->
|
||||
<script src="scripts.js"></script>
|
||||
<script src="fluid.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 210 KiB |
|
After Width: | Height: | Size: 214 KiB |
|
After Width: | Height: | Size: 212 KiB |
|
After Width: | Height: | Size: 215 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 197 KiB |
@@ -0,0 +1,150 @@
|
||||
// ===== 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 = '−';
|
||||
}
|
||||
}
|
||||
|
||||
// ===== COTIZADOR =====
|
||||
const answers = [null, null, null];
|
||||
let current = 0;
|
||||
|
||||
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 updateProgress() {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
document.getElementById('p' + (i + 1)).style.width = i <= current ? '100%' : '0%';
|
||||
}
|
||||
}
|
||||
|
||||
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 + ' <small>/ mes</small>';
|
||||
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 = '';
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 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;
|
||||
}
|
||||
@@ -0,0 +1,650 @@
|
||||
/* ===== 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;
|
||||
--dusty: #a79bab;
|
||||
--claro: #EAF0EE;
|
||||
--rosa: #DFBDB9;
|
||||
--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 {
|
||||
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(--rosa); color: var(--rosa); }
|
||||
.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,.6);
|
||||
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: 16px; 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: 12px; 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: 16px; color: var(--oscuro); line-height: 1.2; grid-column: 1;
|
||||
}
|
||||
.sheet-link-desc {
|
||||
font-family: var(--font-ui); font-size: 13px; color: var(--dusty);
|
||||
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: 300; font-style: italic;
|
||||
font-size: clamp(40px, 6vw, 72px); 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: 18px; line-height: 1.7;
|
||||
color: var(--claro); max-width: 560px; margin: 0 auto 26px; opacity: 0.8;
|
||||
font-weight: 300;
|
||||
}
|
||||
.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(--rosa); color: var(--rosa); }
|
||||
.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,.3);
|
||||
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,.2); }
|
||||
|
||||
/* ===== 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: rgba(234,240,238,.4);
|
||||
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(--rosa); 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(234,240,238,.03); border: 1px solid rgba(234,240,238,.06);
|
||||
border-radius: 10px; padding: 30px 24px; display: flex; flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
.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,.05);
|
||||
}
|
||||
.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: 24px; margin-bottom: 4px;
|
||||
}
|
||||
.plan-stars { color: var(--rosa); font-size: 11px; letter-spacing: 2px; margin-bottom: 14px; }
|
||||
.plan-obj {
|
||||
font-family: var(--font-ui); font-size: 12px; line-height: 1.5;
|
||||
color: rgba(234,240,238,.5); 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-ui); font-size: 12px; line-height: 1.5;
|
||||
padding: 8px 0; border-top: 1px solid rgba(234,240,238,.06);
|
||||
color: rgba(234,240,238,.7);
|
||||
}
|
||||
.plan-feats li:first-child { border-top: none; }
|
||||
.plan-feats li::before { content: '— '; color: var(--rosa); opacity: 0.5; }
|
||||
.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(--rosa); color: var(--rosa); }
|
||||
.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); }
|
||||
.acc-head {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
padding: 20px 4px; 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: 0.5; }
|
||||
.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(--rosa); transition: .25s;
|
||||
}
|
||||
.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 4px 26px; display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
|
||||
.service-row {
|
||||
font-family: var(--font-ui); font-size: 16px; color: rgba(234,240,238,.6);
|
||||
padding: 12px 0; border-top: 1px solid rgba(234,240,238,.04);
|
||||
}
|
||||
.service-row b { display: block; color: var(--claro); font-size: 14px; margin-bottom: 3px; font-weight: 500; }
|
||||
.service-row .price { color: var(--rosa); 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,.06);
|
||||
}
|
||||
.arch {
|
||||
width: 100%; aspect-ratio: 1/1; max-height: 100px;
|
||||
border: 2px solid rgba(234,240,238,.06); 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: 20px; color: var(--rosa); 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: 10px; letter-spacing: .14em;
|
||||
text-transform: uppercase; color: var(--ligth-teal); font-weight: 500;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.column:nth-child(even) .cat { color: var(--bordo); }
|
||||
.step-title {
|
||||
font-family: var(--font-display); font-style: italic; font-weight: 500;
|
||||
font-size: 15px; margin-bottom: 6px;
|
||||
}
|
||||
.step-desc {
|
||||
font-family: var(--font-ui); font-size: 12px; line-height: 1.5;
|
||||
color: var(--dusty);
|
||||
}
|
||||
|
||||
/* ===== CIFRAS ===== */
|
||||
.cifras-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
|
||||
.cifra-card {
|
||||
background: rgba(234,240,238,.02); border: 1px solid rgba(234,240,238,.06);
|
||||
border-radius: 10px; padding: 34px 30px; text-align: center;
|
||||
}
|
||||
.cifra-icon {
|
||||
width: 44px; height: 56px; margin: 0 auto 20px;
|
||||
border: 2px solid rgba(234,240,238,.06); border-bottom: none;
|
||||
border-radius: 22px 22px 0 0;
|
||||
}
|
||||
.cifra-label {
|
||||
font-family: var(--font-ui); font-size: 16px; letter-spacing: .18em;
|
||||
text-transform: uppercase; color: var(--ligth-teal); font-weight: 500; margin-bottom: 12px;
|
||||
}
|
||||
.cifra-value {
|
||||
font-family: var(--font-display); font-style: italic; font-weight: 500;
|
||||
font-size: 24px; color: var(--claro); 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(234,240,238,.03); border: 1px solid rgba(234,240,238,.06);
|
||||
border-radius: 14px; padding: 48px 52px; max-width: 800px; margin: 0 auto;
|
||||
}
|
||||
.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: linear-gradient(90deg, var(--rose-gold-3), var(--bordo)); 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(--rosa); font-size: 14px; margin-bottom: 10px; }
|
||||
.q-title { font-family: var(--font-display); font-style: italic; font-weight: 500; font-size: 22px; margin-bottom: 28px; }
|
||||
.options { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 32px; }
|
||||
.opt {
|
||||
border: 1px solid rgba(234,240,238,.1); border-radius: 8px; padding: 18px 20px;
|
||||
cursor: pointer; transition: .2s; font-family: var(--font-ui);
|
||||
}
|
||||
.opt:hover { border-color: rgba(223,189,185,.3); }
|
||||
.opt.selected { border-color: var(--bordo); background: rgba(186,18,77,.05); }
|
||||
.opt-title { font-size: 14px; font-weight: 500; color: var(--claro); margin-bottom: 3px; }
|
||||
.opt-sub { font-size: 12px; 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(234,240,238,.02); border: 1px solid rgba(234,240,238,.06);
|
||||
border-radius: 12px; padding: 40px 32px; text-align: center;
|
||||
}
|
||||
.team-name {
|
||||
font-family: var(--font-name); font-weight: 500;
|
||||
font-size: 30px; margin-bottom: 8px;
|
||||
}
|
||||
.team-role {
|
||||
font-family: var(--font-ui); font-size: 13px; font-weight: 400;
|
||||
letter-spacing: .06em; text-transform: uppercase; color: var(--rosa);
|
||||
margin-bottom: 12px; opacity: 0.6;
|
||||
}
|
||||
.team-detail {
|
||||
font-family: var(--font-ui); font-size: 13px; 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(--rosa); }
|
||||
.faq-q {
|
||||
font-family: var(--font-ui); font-weight: 400;
|
||||
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-body); font-size: 15px; 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(234,240,238,.02); border: 1px solid rgba(234,240,238,.06);
|
||||
border-radius: 12px; padding: 40px 36px;
|
||||
}
|
||||
.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: 11px; font-weight: 500;
|
||||
letter-spacing: .04em; text-transform: uppercase; color: rgba(234,240,238,.5);
|
||||
}
|
||||
.form-group .req { color: var(--bordo); }
|
||||
.form-group input, .form-group textarea {
|
||||
font-family: var(--font-body); font-size: 14px; 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: 11px; font-weight: 500;
|
||||
padding: 6px 16px; border-radius: 100px;
|
||||
border: 1px solid rgba(234,240,238,.1); background: transparent;
|
||||
color: rgba(234,240,238,.4); cursor: pointer; transition: .2s;
|
||||
}
|
||||
.filter-tag:hover { border-color: var(--rosa); 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(234,240,238,.02);
|
||||
border: 1px solid rgba(234,240,238,.04); border-radius: 10px;
|
||||
}
|
||||
.contact-icon { font-size: 20px; line-height: 1.2; flex-shrink: 0; margin-top: 2px; }
|
||||
.contact-label {
|
||||
font-family: var(--font-ui); font-size: 13px; 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(--rosa); }
|
||||
.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,.2); 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-display); font-size: 16px; line-height: 1.6; color: var(--dusty); 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: 10px; font-weight: 700;
|
||||
letter-spacing: .1em; text-transform: uppercase; color: var(--rosa); opacity: 0.4;
|
||||
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(--rosa); color: var(--rosa); }
|
||||
.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); }
|
||||
|
||||
/* ===== 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 { max-height: 70vh; padding: 10px 16px 20px; border-radius: 16px 16px 0 0; }
|
||||
.sheet-body { grid-template-columns: 1fr; gap: 16px; }
|
||||
.sheet-col:last-child { grid-column: auto; }
|
||||
.home-btn { right: 12px; bottom: 12px; font-size: 10px; }
|
||||
}
|
||||