/* global React */
const { useEffect: pUseEffect, useRef: pUseRef, useState: pUseState } = React;
/* ---------- Compass dingbat (inspired by the brand mark — original) ---------- */
function Compass({ size = 18, spin = false }) {
return (
);
}
/* ---------- Arrow ---------- */
function Arrow({ size = 14 }) {
return (
);
}
/* ---------- Button ---------- */
function Btn({ children, variant = 'primary', onClick, arrow = true, href }) {
const Tag = href ? 'a' : 'button';
return (
{children}
{arrow && }
);
}
/* ---------- Scroll reveal ---------- */
function Reveal({ children, delay = 0, as: Tag = 'div', className = '', style = {} }) {
const ref = pUseRef(null);
const [shown, setShown] = pUseState(false);
pUseEffect(() => {
const el = ref.current;
if (!el) return;
const io = new IntersectionObserver((entries) => {
entries.forEach(e => {
if (e.isIntersecting) { setTimeout(() => setShown(true), delay); io.unobserve(el); }
});
}, { threshold: 0.12, rootMargin: '0px 0px -60px' });
io.observe(el);
return () => io.disconnect();
}, [delay]);
return (
{children}
);
}
/* ---------- Placeholder image ---------- */
function Placeholder({ label, children, aspect = '16/10', tone = 'default', style = {} }) {
const tones = {
default: {},
navy: { background: 'linear-gradient(135deg, var(--navy-700), var(--navy-900))', color: 'var(--bg)' },
accent: { background: 'linear-gradient(135deg, var(--accent), var(--navy-800))', color: '#fff' },
cream: { background: 'linear-gradient(135deg, var(--bg-alt), var(--bg))' },
};
return (
{label && {label}}
{children || '[ imagen real del cliente ]'}
);
}
/* ---------- Counter animation ---------- */
function Counter({ to, duration = 1400 }) {
const [n, setN] = pUseState(0);
const ref = pUseRef(null);
pUseEffect(() => {
const el = ref.current;
if (!el) return;
const io = new IntersectionObserver((entries) => {
entries.forEach(e => {
if (e.isIntersecting) {
const start = performance.now();
const step = (t) => {
const p = Math.min(1, (t - start) / duration);
const eased = 1 - Math.pow(1 - p, 3);
setN(Math.round(eased * to));
if (p < 1) requestAnimationFrame(step);
};
requestAnimationFrame(step);
io.disconnect();
}
});
}, { threshold: 0.3 });
io.observe(el);
return () => io.disconnect();
}, [to, duration]);
return {n};
}
Object.assign(window, { Compass, Arrow, Btn, Reveal, Placeholder, Counter });