// sections.jsx — Pantone Print Lab · todas las secciones
const { useState, useEffect, useRef } = React;
/* ════════════════════════ DATOS ════════════════════════ */
const BRAND_PANTONES = [
{ code: '2768', label: 'Dark Blue Horizon', hex: '050F4B', rgb: '05 · 15 · 75', cmyk: '100 · 90 · 13 · 71', color: '#050F4B' },
{ code: '2175', label: 'Blue Horizon', hex: '005FFF', rgb: '00 · 95 · 255', cmyk: '99 · 47 · 00 · 00', color: '#005FFF' },
{ code: '299', label: 'Light Blue', hex: '00C8FF', rgb: '00 · 200 · 255',cmyk: '86 · 08 · 00 · 00', color: '#00C8FF' },
{ code: '2706', label: 'White Blue', hex: 'D2E1F0', rgb: '210 · 225 · 240',cmyk: '19 · 10 · 00 · 00', color: '#D2E1F0' },
];
/* ════════════════════════ LOGO ════════════════════════ */
function LogoMark({ size = 32, color = 'currentColor' }) {
return (
);
}
function Logo({ light = false }) {
return (
);
}
/* ════════════════════════ HEADER ════════════════════════ */
function Header({ onJump }) {
const [open, setOpen] = useState(false);
const links = [
['Quiénes Somos', 'quienes-somos', false],
['Impresión', 'impresion', false],
['Promocionales', 'promocionales', false],
['Gran Formato', 'gran-formato', false],
['Blog', 'blog', 'external'],
['Contacto', 'contacto', 'external'],
];
return (
);
}
/* ════════════════════════ HERO ════════════════════════ */
function Hero({ onJump }) {
const slides = [
{
img: 'assets/hero-1.png',
headline: 'Imprimimos',
italic: 'ideas',
tail: 'con propósito.',
sub: 'Empaques, papelería, gran formato y merchandising corporativo.',
},
{
img: 'assets/hero-3.png',
headline: 'Empaques que',
italic: 'cuentan',
tail: 'tu historia.',
sub: 'Cajas, bolsas, etiquetas y papel de seda — troquelados y personalizados para tu marca.',
},
{
img: 'assets/hero-2.png',
headline: 'Identidad de marca',
italic: 'para',
tail: 'restaurantes.',
sub: 'Cartas, individuales, porta-cubiertos y posavasos. Piezas pensadas para la mesa.',
},
];
const [idx, setIdx] = useState(0);
useEffect(() => {
const id = setInterval(() => setIdx(i => (i + 1) % slides.length), 5500);
return () => clearInterval(id);
}, []);
const s = slides[idx];
return (
{/* Imagen de productos full bleed */}
{slides.map((sl, i) => (
))}
{/* Overlay para legibilidad del texto */}
{/* Bottom fade para stats */}
{/* Contenido encima */}
{/* TOP */}
Imprenta · Guayaquil
{String(idx + 1).padStart(2, '0')} / {String(slides.length).padStart(2, '0')}
{/* MIDDLE: headline */}
{s.headline}
{s.italic} {s.tail}
{s.sub}
window.openWAQuote && window.openWAQuote()}>
Cotizar por WhatsApp
→
onJump('impresion')}>Ver impresión
{/* BOTTOM: stats + slider dots */}
{[
{ n: '15+', l: 'Años' },
{ n: '50+', l: 'Tiraje mínimo' },
{ n: '24h', l: 'Cotización' },
].map(st => (
{st.n}
{st.l}
))}
{/* Slider dots */}
{slides.map((_, i) => (
setIdx(i)}
aria-label={`Slide ${i + 1}`}
style={{
appearance: 'none', border: 'none', cursor: 'pointer',
width: idx === i ? 44 : 14, height: 6, borderRadius: 999,
background: idx === i ? 'var(--cyan)' : 'rgba(255,255,255,0.4)',
transition: 'all 0.3s ease',
padding: 0,
}}/>
))}
);
}
function ArrowDown() {
return (
);
}
function BrandPantoneStrip() {
return (
PALETA OFICIAL · 4 PANTONES
FIG. 01
{BRAND_PANTONES.map((p, i) =>
)}
);
}
function PantoneCard({ code, label, hex, rgb, cmyk, color, delay = 0, dark = false }) {
return (
PANTONE®
{label}
HEX {hex}
RGB {rgb}
PANTONE {code}C
CMYK {cmyk}
);
}
/* ════════════════════════ TICKER ════════════════════════ */
function HexIcon({ size = 22, color = 'currentColor' }) {
return (
);
}
function Ticker() {
const items = [
'Offset', 'Digital', 'Gran formato', 'Empaques',
'Etiquetas', 'Papelería', 'Promocionales',
'Roll-ups', 'Vinilos', 'Cajas', 'Volantes',
];
return (
{[...items, ...items, ...items].map((it, i) => (
{it}
))}
);
}
/* ════════════════════════ EDIFICIO HQ ════════════════════════ */
function Edificio() {
const [tilt, setTilt] = useState({ x: 0, y: 0 });
const ref = useRef(null);
const onMove = (e) => {
if (!ref.current) return;
const r = ref.current.getBoundingClientRect();
const cx = r.left + r.width / 2;
const cy = r.top + r.height / 2;
const dx = (e.clientX - cx) / r.width;
const dy = (e.clientY - cy) / r.height;
setTilt({ x: dy * -3, y: dx * 5 });
};
const reset = () => setTilt({ x: 0, y: 0 });
return (
{/* Gradient overlay */}
{/* Halo cyan */}
{/* TOP LEFT badge */}
Nuestra sede · Guayaquil
{/* BOTTOM */}
Printing
Visions .
Visítanos
Av. de las Américas #904
y Carlos Luis Plaza Dañín
Guayaquil — Ecuador
);
}
/* ════════════════════════ SOSTENIBILIDAD ════════════════════════ */
function Sostenibilidad() {
return (
{/* Card verde */}
Compromiso ambiental
Crecer
responsablemente
{[
{ n: '-40%', l: 'Residuos' },
{ n: '100%', l: 'Tintas eco' },
{ n: '+15', l: 'Años reciclando' },
].map(s => (
))}
{/* Texto */}
Sostenibilidad
Imprimimos con conciencia .
Integramos procesos responsables que optimizan recursos y reducen el impacto
ambiental , sin comprometer calidad ni eficiencia.
Porque hoy, crecer también implica hacerlo de forma inteligente. Cada decisión
en la imprenta —desde el papel hasta los acabados— se piensa con un futuro
más limpio en mente.
{[
{ icon: '🌱', t: 'Papel reciclado', d: 'Certificado FSC en empaques' },
{ icon: '💧', t: 'Tintas a base de agua', d: 'Sin solventes agresivos' },
{ icon: '♻️', t: 'Reciclaje activo', d: 'Recortes y residuos clasificados' },
{ icon: '⚡', t: 'Energía optimizada', d: 'Equipos de bajo consumo' },
].map(c => (
))}
);
}
/* ════════════════════════ QUIÉNES SOMOS ════════════════════════ */
function QuienesSomos() {
return (
{/* Top: title left + lead right */}
Quiénes somos · EST. 2010
Una imprenta con propósito .
Somos Role Machine — una imprenta guayaquileña con quince años
convirtiendo ideas en piezas tangibles. Trabajamos con marcas, agencias
y emprendedores que buscan calidad y atención al detalle.
Empaques, gran formato, papelería corporativa, merchandising y soluciones
para restaurantes. Asesoría en cada etapa: desde el arte hasta el acabado.
{/* Mini stats grid (compacto) + collage de fotos */}
{[
{ n: '15+', l: 'Años de experiencia', s: '2010 — 2026' },
{ n: '5k+', l: 'Proyectos entregados', s: 'Marcas y agencias' },
{ n: '50+', l: 'Tiraje mínimo', s: 'Flexible para makers' },
{ n: '24h', l: 'Tiempo de cotización', s: 'Por WhatsApp o email' },
].map((s, i) => (
))}
{/* Collage de fotos del equipo + edificio */}
Detrás de cada impresión
{[
'assets/edificio.png',
'assets/equipo-01-administrativo.png',
'assets/equipo-03-heidelberg.png',
'assets/equipo-04-uv.png',
'assets/equipo-02-gran-formato.png',
'assets/equipo-05-acabados.png',
'assets/equipo-06-diseno.png',
'assets/equipo-07-canon.png',
'assets/equipo-08-heidelberg2.png',
].map((src, i) => (
e.preventDefault()}/>
))}
{/* CLIENTES MARQUEE */}
Nuestros clientes · 100+ marcas
Marcas, agencias y empresas que confían en nosotros
{(() => {
const logos = Array.from({ length: 26 }, (_, i) => `assets/clientes/${String(i + 1).padStart(2, '0')}.png`);
const loop = [...logos, ...logos];
return loop.map((src, i) => (
));
})()}
{/* TECNOLOGÍA / MÁQUINAS */}
Tecnología · Maquinaria de impresión
Equipos de clase mundial al servicio de tu marca
{[
{ name: 'Heidelberg', img: 'assets/maq-heidelberg.png' },
{ name: 'Canon', img: 'assets/maq-canon.png' },
{ name: 'Mimaki', img: 'assets/maq-mimaki.png' },
{ name: 'Shinohara', img: 'assets/maq-shinohara.png' },
].map(t => (
))}
);
}
/* ════════════════════════ SERVICIOS / IMPRESIÓN ════════════════════════ */
function Servicios({ onJump }) {
const cats = [
{ id: '01', code: 'IMP-01', name: 'Empaques', italic: 'a medida', desc: 'Cajas plegables, etiquetas troqueladas, bolsas kraft, papel antigrasa.', color: 'var(--blue)', textColor: '#fff', tags: ['Cajas plegables', 'Etiquetas', 'Antigrasa', 'Bolsas'], img: 'assets/imp-01-empaques.png' },
{ id: '02', code: 'IMP-02', name: 'Papelería', italic: 'corporativa', desc: 'Tarjetas, cuadernos, carpetas, sobres y hojas membretadas.', color: 'var(--navy)', textColor: '#fff', tags: ['Tarjetas', 'Cuadernos', 'Membretes', 'Carpetas'], img: 'assets/imp-02-papeleria.png' },
{ id: '03', code: 'IMP-03', name: 'Publicitaria', italic: 'masiva', desc: 'Volantes, trípticos, menús, afiches, revistas y libros.', color: 'var(--cyan)', textColor: 'var(--navy)', tags: ['Volantes', 'Trípticos', 'Afiches', 'Menús'], img: 'assets/imp-03-publicitaria.png' },
{ id: '04', code: 'IMP-04', name: 'Restaurantes', italic: 'menús', desc: 'Cartas, individuales, manteles personalizados, manga, vasos.', color: 'var(--pale)', textColor: 'var(--navy)', tags: ['Cartas', 'Individuales', 'Vasos', 'Mangas'], img: 'assets/imp-04-restaurantes.png' },
{ id: '05', code: 'IMP-05', name: 'Alto relieve UV', italic: 'Mimaki', desc: 'UV 3D selectivo, relieve, brillo y textura premium. Etiquetas y empaques con efectos táctiles.', color: 'var(--blue)', textColor: '#fff', tags: ['UV 3D', 'Selectivo', 'Relieve', 'Mimaki'], img: 'assets/imp-05-uv.png' },
];
return (
);
}
function ServicioCard({ id, code, name, italic, desc, color, textColor, tags, img }) {
const [hover, setHover] = useState(false);
return (
setHover(true)}
onMouseLeave={() => setHover(false)}
style={{
background: color,
color: textColor,
borderRadius: 18,
minHeight: 520,
display: 'flex', flexDirection: 'column',
transition: 'transform 0.3s ease, box-shadow 0.3s ease',
transform: hover ? 'translateY(-6px)' : 'translateY(0)',
boxShadow: hover ? '0 24px 60px rgba(5,15,75,0.25)' : '0 6px 24px rgba(5,15,75,0.10)',
position: 'relative', overflow: 'hidden',
}}>
{/* Imagen al medio-arriba */}
{/* top labels overlay sobre imagen */}
{/* Cuerpo */}
{name}
{italic}
{desc}
{tags.map(t => (
{t}
))}
);
}
function ArrowDiag({ color }) {
return (
);
}
/* ════════════════════════ PROMOCIONALES ════════════════════════ */
function Promocionales() {
const items = [
{ id: 'cuadernos', name: 'Cuadernos · Libretas', desc: 'Pasta dura, suave o anillada. A5 / A6. Personalizables.', refs: 8, color: 'var(--navy)', textColor: '#fff', img: 'assets/promo-01-cuadernos.png' },
{ id: 'termos', name: 'Tomatodos · Termos', desc: 'Acero inoxidable, doble pared, 350–750ml.', refs: 12, color: 'var(--cyan)', textColor: 'var(--navy)', img: 'assets/promo-02-termos.png' },
{ id: 'bolsos', name: 'Bolsos · Sport bag', desc: 'Tote bags, mochilas ejecutivas, neceseres.', refs: 6, color: 'var(--blue)', textColor: '#fff', img: 'assets/promo-03-bolsos.png' },
{ id: 'plumas', name: 'Plumas · Bolígrafos', desc: 'Ejecutivos, ecológicos, metálicos, gel.', refs: 9, color: 'var(--navy)', textColor: '#fff', img: 'assets/promo-04-plumas.png' },
{ id: 'gorras', name: 'Gorras · Textiles', desc: 'Bordado o sublimación. Trucker caps y más.', refs: 5, color: 'var(--blue)', textColor: '#fff', img: 'assets/promo-05-gorras.png' },
{ id: 'llaveros', name: 'Llaveros · Pop sockets',desc: 'Metálicos, cuero o silicona. Láser o tampografía.', refs: 7, color: 'var(--navy)', textColor: '#fff', img: 'assets/promo-06-llaveros.png' },
{ id: 'calendarios',name: 'Calendarios', desc: 'Triangulares, de pared, pasta dura o suave.', refs: 4, color: 'var(--cyan)', textColor: 'var(--navy)', img: 'assets/promo-07-calendarios.png' },
{ id: 'bolsas', name: 'Bolsas · Empaques', desc: 'Kraft con y sin asas, papel de regalo, cajas premium.', refs: 6, color: 'var(--blue)', textColor: '#fff', img: 'assets/promo-08-bolsas.png' },
];
return (
);
}
function DescargarCatalogoCard() {
const [hover, setHover] = useState(false);
return (
setHover(true)}
onMouseLeave={() => setHover(false)}
style={{
background: '#fff',
color: 'var(--navy)',
borderRadius: 14,
minHeight: 320,
display: 'flex', flexDirection: 'column',
transition: 'transform 0.25s ease, box-shadow 0.25s ease',
transform: hover ? 'translateY(-4px)' : 'translateY(0)',
boxShadow: hover ? '0 24px 60px rgba(5,15,75,0.25)' : '0 6px 24px rgba(5,15,75,0.10)',
position: 'relative', overflow: 'hidden',
border: '1px solid rgba(5,15,75,0.08)',
}}>
{/* Imagen */}
Descargar catálogo
Recibe el catálogo completo de promocionales por WhatsApp.
);
}
function PromoCard({ name, desc, refs, color, textColor, img }) {
const [hover, setHover] = useState(false);
return (
setHover(true)}
onMouseLeave={() => setHover(false)}
style={{
background: color,
color: textColor,
borderRadius: 14,
minHeight: 320,
display: 'flex', flexDirection: 'column',
transition: 'transform 0.25s ease, box-shadow 0.25s ease',
transform: hover ? 'translateY(-4px)' : 'translateY(0)',
boxShadow: hover ? '0 18px 50px rgba(5,15,75,0.18)' : '0 4px 18px rgba(5,15,75,0.06)',
position: 'relative', overflow: 'hidden',
}}>
{/* Imagen */}
{img && (
)}
{/* Cuerpo */}
);
}
/* ════════════════════════ GRAN FORMATO ════════════════════════ */
function GranFormato() {
const items = [
{ id: 'rollup', name: 'Roll-up Lonas', spec: 'Brillo · Mate · PET', img: 'assets/gf-01-rollup.png' },
{ id: 'banner', name: 'Banner X', spec: 'Brillo · Mate', img: 'assets/gf-02-banner.png' },
{ id: 'counter', name: 'Counter', spec: 'PVC reforzado', img: 'assets/gf-03-counter.png' },
{ id: 'backing', name: 'Backing', spec: 'Aluminio + Lona', img: 'assets/gf-04-backing.png' },
{ id: 'anforas', name: 'Ánforas publicitarias', spec: 'Cartón corrugado', img: 'assets/gf-05-anforas.png' },
{ id: 'señaletica',name: 'Señalética', spec: 'PVC · Acrílico · Vinil', img: 'assets/gf-06-senaletica.png' },
{ id: 'arenado', name: 'Arenado', spec: 'Vinil esmerilado', img: 'assets/gf-07-arenado.png' },
{ id: 'vinil', name: 'Vinil de corte', spec: 'Polimérico', img: 'assets/gf-08-vinil.png' },
{ id: 'ruleta', name: 'Ruletas', spec: 'MDF + impresión', img: 'assets/gf-09-ruletas.png' },
{ id: 'exhibidor', name: 'Exhibidores', spec: 'Cartón · PVC', img: 'assets/gf-10-exhibidores.png' },
{ id: 'dummies', name: 'Dummies', spec: 'Producto de exhibición', img: 'assets/gf-11-dummies.png' },
];
return (
);
}
function BigStats() {
return (
{[
{ n: '15+', l: 'Años imprimiendo' },
{ n: '50+', l: 'Tiraje mínimo' },
{ n: '24h', l: 'Cotización' },
].map(s => (
{s.n}
{s.l}
))}
);
}
function GFCard({ name, spec, img, idx, total }) {
const [hover, setHover] = useState(false);
return (
setHover(true)}
onMouseLeave={() => setHover(false)}
style={{
display: 'flex', flexDirection: 'column',
cursor: 'default',
borderRight: '1px solid rgba(255,255,255,0.15)',
borderBottom: '1px solid rgba(255,255,255,0.15)',
background: 'var(--navy)',
overflow: 'hidden',
position: 'relative',
alignSelf: 'start',
}}>
{/* Imagen */}
{img && (
)}
{/* Texto */}
);
}
/* ════════════════════════ BLOG ════════════════════════ */
function Blog() {
const posts = [
{
id: 'alto-relieve-uv-mimaki',
cat: 'Tecnología',
date: '20 may 2026',
title: 'Etiquetas de alto relieve UV con tecnología Mimaki',
excerpt: 'Stickers UV, etiquetas con textura 3D, brillo selectivo y acabados premium. La última tecnología Mimaki llegó a Role Machine.',
cover: 'var(--blue)',
img: 'assets/blog-05-uv.png',
readTime: '5 min',
featured: true,
},
{
id: 'material-empaque',
cat: 'Tendencias',
date: '12 may 2026',
title: 'Cómo elegir el material correcto para tu empaque',
excerpt: 'Couché, kraft, sulfato o cartulina rígida. Cada sustrato cambia la personalidad de tu producto. Te contamos cuándo usar cada uno.',
cover: 'var(--blue)',
img: 'assets/blog-01-material.png',
readTime: '4 min',
featured: true,
},
{
id: 'sangrado-area-segura',
cat: 'Guía técnica',
date: '28 abr 2026',
title: 'Sangrado y área segura: lo básico antes de imprimir',
excerpt: 'Los 3mm que hacen la diferencia entre un trabajo profesional y uno que se ve descuidado al cortar.',
cover: 'var(--navy)',
img: 'assets/blog-02-sangrado.png',
readTime: '3 min',
},
{
id: 'smile-caso',
cat: 'Casos de estudio',
date: '15 abr 2026',
title: 'Smile Estética Dental: 4 años imprimiendo material corporativo',
excerpt: 'Cómo construimos una relación de confianza con una de las clínicas dentales más reconocidas de Guayaquil.',
cover: 'var(--cyan)',
img: 'assets/blog-03-smile.png',
readTime: '5 min',
},
{
id: 'top-promocionales-2026',
cat: 'Promocionales',
date: '02 abr 2026',
title: 'Top 5 promocionales corporativos para 2026',
excerpt: 'Termos, libretas ecológicas y tote bags lideran la demanda este año. Te mostramos las tendencias.',
cover: 'var(--blue)',
img: 'assets/blog-04-promos.png',
readTime: '6 min',
},
];
return (
);
}
function BlogCard({ id, cat, date, title, excerpt, cover, img, readTime, featured, idx }) {
const [hover, setHover] = useState(false);
return (
setHover(true)}
onMouseLeave={() => setHover(false)}
style={{
background: 'var(--paper)',
border: '1px solid var(--line)',
borderRadius: 18,
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
transition: 'transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease',
transform: hover ? 'translateY(-4px)' : 'translateY(0)',
boxShadow: hover ? '0 18px 50px rgba(5,15,75,0.15)' : '0 4px 18px rgba(5,15,75,0.04)',
borderColor: hover ? 'var(--line-2)' : 'var(--line)',
cursor: 'pointer',
color: 'inherit', textDecoration: 'none',
}}>
{/* Cover */}
{img && (
)}
{/* Cat chip */}
{cat}
{/* Body */}
{date}
·
{readTime} de lectura
{title}
{excerpt}
);
}
function Proceso() {
const steps = [
{ n: '01', t: 'Cuéntanos tu proyecto', d: 'Envíanos un brief o referencias por WhatsApp. Te respondemos en menos de 24 horas.', img: 'assets/proceso-01.svg' },
{ n: '02', t: 'Cotización y materiales', d: 'Asesoría sobre sustrato, acabado, tiraje y plazos. Cotización formal por escrito.', img: 'assets/proceso-02.svg' },
{ n: '03', t: 'Aprobación de arte', d: 'Revisamos archivos, verificamos sangrado y áreas seguras. Prueba digital incluida.', img: 'assets/proceso-03.svg' },
{ n: '04', t: 'Impresión y entrega', d: 'Offset, digital o gran formato según tu trabajo. Entrega 48–96 hrs a todo Ecuador.', img: 'assets/proceso-04.svg' },
];
return (
4 pasos · del brief al envío
Cómo funciona .
{steps.map((s, i) => {
const bg = i === 0 ? 'var(--blue)' : i === 1 ? 'var(--cyan)' : i === 2 ? 'var(--pale)' : 'var(--navy)';
const fg = i === 1 || i === 2 ? 'var(--navy)' : '#fff';
return (
{/* Top: número + paso */}
{s.n}
PASO
{/* Imagen central */}
{/* Texto abajo */}
);
})}
);
}
/* ════════════════════════ TESTIMONIOS ════════════════════════ */
function Testimonios() {
const ts = [
{ q: 'Quería agradecerles, estamos encantados con su trabajo. Material de excelente calidad y atención excepcional.', a: 'Grupo Carrera Villacis', r: 'CEO' },
{ q: 'En Role encontré lo que necesitaba: calidad y cuidado en cada detalle. Decidí realizar grandes pedidos con ellos.', a: 'WENS Consulting', r: 'CEO' },
{ q: 'Llevamos desde 2022 imprimiendo nuestros cuadernos y agendas. Quedan recomendados al 100%.', a: 'Pharmedic', r: 'Comunicación' },
];
return (
15 años, miles de tirajes
Lo que dicennuestros clientes .
{ts.map((t, i) => (
"
{t.q}
))}
);
}
/* ════════════════════════ CONTACTO (FORMULARIO) ════════════════════════ */
function Contacto() {
const [submitting, setSubmitting] = useState(false);
const [sent, setSent] = useState(false);
const [form, setForm] = useState({ email: '', nombre: '', empresa: '', mensaje: '' });
const update = (k, v) => setForm(f => ({ ...f, [k]: v }));
const handleSubmit = (e) => {
e.preventDefault();
if (submitting) return;
setSubmitting(true);
// Por ahora abre WhatsApp pre-llenado. Cuando tengas backend, cambiar por fetch().
const text = `Hola Role Machine, soy ${form.nombre}` +
(form.empresa ? ` de ${form.empresa}` : '') +
`.\n\n${form.mensaje}\n\nContacto: ${form.email}`;
const url = `https://wa.me/593962865530?text=${encodeURIComponent(text)}`;
window.open(url, '_blank');
setTimeout(() => { setSent(true); setSubmitting(false); }, 600);
};
return (
);
}
function FormField({ label, required, value, onChange, type = 'text', placeholder, textarea }) {
const [focused, setFocused] = useState(false);
const inputStyle = {
width: '100%',
appearance: 'none',
border: focused ? '1.5px solid var(--blue)' : '1.5px solid var(--line-2)',
borderRadius: 999,
padding: '14px 20px',
fontFamily: 'var(--sans)', fontSize: 14,
color: 'var(--ink)',
background: '#fff',
outline: 'none',
transition: 'border-color 0.18s ease, box-shadow 0.18s ease',
boxShadow: focused ? '0 0 0 4px rgba(0,95,255,0.10)' : 'none',
resize: textarea ? 'vertical' : 'none',
minHeight: textarea ? 120 : undefined,
fontWeight: 400,
};
if (textarea) {
inputStyle.borderRadius = 14;
inputStyle.paddingTop = 14;
inputStyle.paddingBottom = 14;
}
return (
{label} {required && * }
{textarea ? (
);
}
/* ════════════════════════ BOLSA DE TRABAJO ════════════════════════ */
function BolsaTrabajo() {
const [form, setForm] = useState({ nombre: '', email: '', telefono: '', puesto: '', experiencia: '', mensaje: '' });
const [sent, setSent] = useState(false);
const update = (k, v) => setForm(f => ({ ...f, [k]: v }));
const handleSubmit = (e) => {
e.preventDefault();
const text = `Hola, me interesa postular a Role Machine.\n\n` +
`Nombre: ${form.nombre}\n` +
`Email: ${form.email}\n` +
`Teléfono: ${form.telefono}\n` +
`Puesto de interés: ${form.puesto}\n` +
`Años de experiencia: ${form.experiencia}\n\n` +
`${form.mensaje}\n\n` +
`*Adjuntaré mi CV en el siguiente mensaje.`;
const url = `https://wa.me/593962865530?text=${encodeURIComponent(text)}`;
window.open(url, '_blank');
setSent(true);
};
const vacantes = [
{ titulo: 'Diseñador gráfico', tipo: 'Tiempo completo', area: 'Diseño' },
{ titulo: 'Operador de prensa offset', tipo: 'Tiempo completo', area: 'Producción' },
{ titulo: 'Asesor comercial', tipo: 'Tiempo completo', area: 'Ventas' },
{ titulo: 'Auxiliar de acabados', tipo: 'Tiempo completo', area: 'Producción' },
];
return (
{/* Izquierda: contexto + vacantes */}
Bolsa de trabajo · Únete al equipo
Trabaja connosotros .
Buscamos personas apasionadas por la impresión, el diseño y el detalle.
Si te identificas con nuestros valores, postula y conversemos.
{/* Vacantes abiertas */}
Vacantes abiertas · {vacantes.length}
{vacantes.map((v, i) => (
{v.titulo}
{v.area}
{v.tipo}
))}
¿No ves tu puesto? Envíanos tu CV de todas formas. Siempre buscamos buen talento.
{/* Derecha: formulario de postulación */}
);
}
function PuestoSelect({ value, onChange, vacantes }) {
const [focused, setFocused] = useState(false);
return (
Puesto de interés *
onChange(e.target.value)}
onFocus={() => setFocused(true)} onBlur={() => setFocused(false)}
required
style={{
width: '100%', appearance: 'none',
border: focused ? '1.5px solid var(--blue)' : '1.5px solid var(--line-2)',
borderRadius: 999, padding: '14px 20px',
fontFamily: 'var(--sans)', fontSize: 14,
color: value ? 'var(--ink)' : 'var(--muted)',
background: '#fff',
outline: 'none',
transition: 'border-color 0.18s ease',
backgroundImage: 'url("data:image/svg+xml;utf8, ")',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'right 18px center',
paddingRight: 40,
}}>
Selecciona un puesto
{vacantes.map((v, i) => {v.titulo} )}
Otro / Postulación espontánea
);
}
/* ════════════════════════ FOOTER ════════════════════════ */
function AnimatedSlogan() {
return (
{[0, 1].map(group => (
Tu marca
se imprime
mejor
en role
))}
);
}
function Footer() {
return (
);
}
function TypographicSlogan() {
return (
{/* Hex decorativo de fondo */}
tu {' '}
marca
se {' '}
imprime
mejor {' '}
en {' '}
role.
);
}
function SocialLink({ icon, handle, href }) {
return (
{handle}
);
}
function SocialIcon({ kind }) {
const s = { width: 16, height: 16, fill: 'currentColor' };
if (kind === 'instagram') return (
);
if (kind === 'facebook') return (
);
if (kind === 'linkedin') return (
);
if (kind === 'tiktok') return (
);
if (kind === 'whatsapp') return (
);
return null;
}
function PhoneIcon() {
return (
);
}
function MailIcon() {
return (
);
}
function PinIcon() {
return (
);
}
function FootCol({ title, items }) {
return (
);
}
function FootballPopup() {
const [stage, setStage] = useState('idle'); // idle, animation, popup, hidden
const [email, setEmail] = useState('');
const [sent, setSent] = useState(false);
const [submitting, setSubmitting] = useState(false);
useEffect(() => {
const dismissed = sessionStorage.getItem('rm_football_popup');
if (dismissed) return;
const t1 = setTimeout(() => setStage('animation'), 5000);
const t2 = setTimeout(() => setStage('confetti'), 7600);
const t3 = setTimeout(() => setStage('popup'), 8400);
return () => { clearTimeout(t1); clearTimeout(t2); clearTimeout(t3); };
}, []);
const close = () => {
setStage('hidden');
sessionStorage.setItem('rm_football_popup', '1');
};
const handleSubmit = async (e) => {
e.preventDefault();
if (!email || submitting) return;
setSubmitting(true);
try {
await fetch('https://api.web3forms.com/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
body: JSON.stringify({
access_key: 'f5469a22-bfca-4389-b823-c660dae5de53',
subject: '⚽ Catálogo Mundialista · Cliente quiere el catálogo',
from_name: 'Role Machine — Mundialista',
message: `🏆 ¡Nuevo cliente quiere el catálogo mundialista!\n\nEl cliente con correo: ${email}\nha solicitado recibir el catálogo mundialista de productos branded (balones, camisetas, gorras, etc).\n\n👉 Acción: enviarle el catálogo PDF al correo proporcionado.`,
email,
tipo: 'Cliente quiere catálogo mundialista',
}),
});
setSent(true);
} catch (err) {}
setSubmitting(false);
};
if (stage === 'idle' || stage === 'hidden') return null;
return (
<>
{/* ANIMATION: jugador patea el balón, gol */}
{(stage === 'animation' || stage === 'confetti') && (
{/* Arco realista (izquierda) */}
{/* Jugador (espejado, viene de la derecha) */}
{/* Balón volando (de derecha a izquierda) */}
{/* GOL text flash */}
¡GOL!
{/* CONFETTI (azul + amarillo) */}
{stage === 'confetti' && (
{Array.from({ length: 60 }).map((_, i) => {
const left = Math.random() * 100;
const delay = Math.random() * 0.5;
const duration = 1.6 + Math.random() * 1.4;
const size = 8 + Math.random() * 8;
const colors = ['#FFCE00', '#0F47AF', '#005FFF', '#ED1C24', '#00C8FF'];
const color = colors[Math.floor(Math.random() * colors.length)];
const rot = Math.random() * 360;
return (
);
})}
)}
)}
{/* POPUP */}
{stage === 'popup' && (
e.stopPropagation()} style={{
position: 'relative',
width: '100%', maxWidth: 520,
background: '#fff',
color: 'var(--navy)',
borderRadius: 22,
padding: 'clamp(28px, 4.5vw, 44px)',
overflow: 'hidden',
boxShadow: '0 24px 60px rgba(5,15,75,0.30)',
animation: 'fbPopIn 0.5s cubic-bezier(.22,.9,.3,1.2)',
}}>
{/* Top accent: bandera Ecuador */}
{/* Close */}
×
{sent ? (
) : (
{/* Mini bandera */}
La pasión del fútbol
vívela con tu marca
Recibe el catálogo mundialista con productos branded para tu negocio:
balones, camisetas, gorras y más — personalizados con tu marca.
⏱ Los tiempos de producción se agotan antes del Mundial. Pide el tuyo hoy.
)}
)}
>
);
}
const WA_MUNDIAL = 'https://wa.me/593962865530?text=' + encodeURIComponent('Quiero el catálogo mundialista');
function PlayerEcuador() {
return (
{/* Cabeza */}
{/* Cuerpo (camiseta amarilla Ecuador) */}
{/* Detalle azul y rojo (banda) */}
{/* Mangas */}
{/* Logo / número */}
EC
{/* Piernas (shorts azules) */}
{/* Medias amarillas */}
{/* Zapatos */}
{/* Brazos */}
);
}
function GoalNet() {
return (
{/* Perspectiva trasera (red) — tono más claro */}
{/* Red trasera (líneas diagonales) */}
{Array.from({ length: 16 }).map((_, i) => {
const t = i / 15;
const x = 60 + (280 - 60) * t;
return ;
})}
{Array.from({ length: 8 }).map((_, i) => {
const t = i / 7;
const y = 55 + (200 - 55) * t;
return ;
})}
{/* Postes principales (frente) — blancos grosor 6 */}
{/* Suelo / sombra */}
);
}
function FootballSVG() {
return (
{/* Balón blanco con sombreado */}
{/* Pentágonos negros (clásico) */}
{/* Líneas conectoras (hexágonos) */}
);
}
/* ════════════════════════ WHATSAPP QUOTE MODAL ════════════════════════ */
function WhatsAppQuoteModal() {
const [open, setOpen] = useState(false);
const [form, setForm] = useState({
tipo: 'empresa',
nombre: '', empresa: '', email: '', necesito: '',
fechaEntrega: '', tieneArte: '',
});
const [sent, setSent] = useState(false);
useEffect(() => {
const handler = () => { setOpen(true); setSent(false); };
window.addEventListener('open-wa-quote', handler);
return () => window.removeEventListener('open-wa-quote', handler);
}, []);
const update = (k, v) => setForm(f => ({ ...f, [k]: v }));
const close = () => setOpen(false);
const valid = form.nombre && form.email && form.necesito && form.fechaEntrega && form.tieneArte &&
(form.tipo === 'persona' || (form.tipo === 'empresa' && form.empresa));
const send = (e) => {
e && e.preventDefault();
if (!valid) return;
const tipoLabel = form.tipo === 'empresa' ? 'Empresa' : 'Persona natural';
const text =
`Hola Role Machine, quiero cotizar un proyecto.
📋 Tipo: ${tipoLabel}
👤 Nombre: ${form.nombre}${form.tipo === 'empresa' ? `\n🏢 Empresa: ${form.empresa}` : ''}
📧 Email: ${form.email}
📅 Fecha de entrega deseada: ${form.fechaEntrega}
🎨 Arte/diseño: ${form.tieneArte}
💬 Lo que necesito:
${form.necesito}`;
const url = `https://wa.me/593962865530?text=${encodeURIComponent(text)}`;
if (typeof window.fbq === 'function') {
try { window.fbq('track', 'Lead', { content_name: 'Cotización WhatsApp', content_category: tipoLabel }); } catch (e) {}
}
window.open(url, '_blank');
setSent(true);
};
if (!open) return null;
const fieldStyle = (focused = false) => ({
width: '100%', appearance: 'none',
border: '1.5px solid var(--line-2)',
borderRadius: 10, padding: '11px 14px',
fontFamily: 'var(--sans)', fontSize: 13.5,
color: 'var(--ink)', background: '#fff',
outline: 'none', boxSizing: 'border-box',
});
return (
e.stopPropagation()} style={{
position: 'relative',
width: '100%', maxWidth: 520,
background: '#fff', color: 'var(--ink)',
borderRadius: 20, padding: 'clamp(24px, 4vw, 36px)',
overflow: 'hidden', boxShadow: '0 24px 60px rgba(5,15,75,0.30)',
animation: 'fbPopIn 0.4s cubic-bezier(.22,.9,.3,1.2)',
marginTop: 30, marginBottom: 30,
}}>
{/* Close */}
×
{sent ? (
¡Abriendo WhatsApp!
Si no se abrió automáticamente, haz clic abajo.
send(e)} className="btn btn-primary" style={{ justifyContent: 'center' }}>
Abrir WhatsApp →
{ setSent(false); setForm({ tipo: 'empresa', nombre: '', empresa: '', email: '', necesito: '', fechaEntrega: '', tieneArte: '' }); close(); }}
style={{ appearance: 'none', background: 'transparent', border: 'none', color: 'var(--muted)', fontSize: 13, cursor: 'pointer', padding: 8 }}>
Cerrar
) : (
)}
);
}
// Helper global para abrir el modal desde cualquier botón
if (typeof window !== 'undefined') {
window.openWAQuote = () => window.dispatchEvent(new Event('open-wa-quote'));
}
function InstagramFeed() {
return (
Instagram · Últimos trabajos
Mira nuestro
último trabajo .
Cada semana imprimimos algo nuevo. Síguenos en Instagram para ver el detrás
de cámaras y las marcas que confían en Role Machine.
Síguenos @rolemachine →
{/* Elfsight Instagram Feed */}
);
}
Object.assign(window, {
Header, Hero, Ticker, QuienesSomos, Servicios, Promocionales, GranFormato, Sostenibilidad, Proceso, Blog, InstagramFeed, Testimonios, Contacto, BolsaTrabajo, FootballPopup, WhatsAppQuoteModal, Footer,
});