/* global React */
function Icon({ name, size = 20, stroke = 1.75, style }) {
const paths = {
'arrow-right': <>>,
'arrow-up-right': <>>,
'arrow-down-right': <>>,
'check': <>>,
'target': <>>,
'chart': <>>,
'zap': <>>,
'users': <>>,
'mail': <>>,
'calendar': <>>,
'play': <>>,
'menu': <>>,
'sparkles': <>>,
'brain': <>>,
'megaphone': <>>,
'search': <>>,
'graduation': <>>,
'film': <>>,
'home': <>>,
'shopping': <>>,
'credit-card': <>>,
'heart': <>>,
'scale': <>>,
'server': <>>,
'rocket': <>>,
'globe': <>>,
'briefcase': <>>,
'compass': <>>,
'message': <>>,
'clipboard': <>>,
'quote': <>>,
};
return (
);
}
function Button({ variant = 'primary', size = 'md', children, icon, iconLeft, ...p }) {
const base = {
fontFamily: 'var(--font-body)', fontWeight: 600, border: 0, cursor: 'pointer',
display: 'inline-flex', alignItems: 'center', gap: 8, lineHeight: 1,
borderRadius: 999, letterSpacing: '-0.005em',
transition: 'transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out)',
whiteSpace: 'nowrap',
};
const sizes = {
sm: { padding: '9px 16px', fontSize: 13 },
md: { padding: '13px 22px', fontSize: 15 },
lg: { padding: '16px 28px', fontSize: 16 },
};
const variants = {
cta: { background: 'var(--cta)', color: 'var(--teal-900)', boxShadow: 'var(--shadow-cta)' },
primary: { background: 'var(--brand)', color: '#fff', boxShadow: 'var(--shadow-brand)' },
ghost: { background: 'transparent', color: 'var(--brand)', border: '1px solid var(--teal-200)' },
text: { background: 'transparent', color: 'var(--brand)', padding: '8px 4px' },
inverse: { background: '#fff', color: 'var(--teal-800)' },
dark: { background: 'var(--teal-900)', color: '#fff' },
};
return (
);
}
function Eyebrow({ children, dark, color }) {
return (
{children}
);
}
function Badge({ children, tone = 'brand' }) {
const tones = {
brand: { bg: 'var(--teal-50)', fg: 'var(--teal-700)' },
accent: { bg: 'var(--cyan-50)', fg: 'var(--cyan-800)' },
cta: { bg: 'var(--yellow-50)', fg: 'var(--yellow-800)' },
neutral: { bg: 'var(--ink-100)', fg: 'var(--ink-700)' },
dark: { bg: 'rgba(255,255,255,0.1)', fg: 'rgba(255,255,255,0.92)' },
};
const t = tones[tone];
return {children};
}
function Droplets({ color = 'var(--teal-100)', opacity = 0.55, style, size = 180 }) {
return (
);
}
// Container shorthand
function Container({ children, style = {}, className, maxW = 1200, ...p }) {
const defaultPadding = className ? {} : { padding: '0 32px' };
return (
{children}
);
}
function useWindowWidth() {
const [width, setWidth] = React.useState(
typeof window !== 'undefined' ? window.innerWidth : 1200
);
React.useEffect(() => {
const handler = () => setWidth(window.innerWidth);
window.addEventListener('resize', handler, { passive: true });
return () => window.removeEventListener('resize', handler);
}, []);
return width;
}
/* ------------------------------------------------------------------ *
* useInView — fires callback once when element crosses viewport edge *
* ------------------------------------------------------------------ */
function useInView(ref, { threshold = 0.12, once = true } = {}) {
const [visible, setVisible] = React.useState(false);
React.useEffect(() => {
if (!ref.current) return;
if (typeof IntersectionObserver === 'undefined') {
setVisible(true);
return;
}
const obs = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setVisible(true);
if (once) obs.disconnect();
}
},
{ threshold }
);
obs.observe(ref.current);
return () => obs.disconnect();
}, []);
return visible;
}
/* ------------------------------------------------------------------ *
* Reveal — scroll-triggered entrance wrapper *
* *
* Props: *
* dir 'up' | 'left' | 'right' default 'up' *
* delay 0-6 (maps to rv-d1…rv-d6 CSS classes) *
* scale bool use rv-scale variant instead of translate *
* fast bool shorter 360ms transition *
* tag string wrapper element type, default 'div' *
* className / style forwarded to wrapper *
* ------------------------------------------------------------------ */
function Reveal({ children, dir = 'up', delay = 0, scale = false, fast = false, tag = 'div', className = '', style = {} }) {
const ref = React.useRef(null);
const visible = useInView(ref);
const dirClass = dir === 'left' ? 'rv-left' : dir === 'right' ? 'rv-right' : '';
const delayClass = delay > 0 ? `rv-d${delay}` : '';
const scaleClass = scale ? 'rv-scale' : '';
const fastClass = fast ? 'rv-fast' : '';
const cls = ['rv', dirClass, scaleClass, fastClass, delayClass, visible ? 'is-visible' : '', className]
.filter(Boolean).join(' ');
return React.createElement(tag, { ref, className: cls, style }, children);
}
Object.assign(window, { Icon, Button, Eyebrow, Badge, Droplets, Container, useWindowWidth, useInView, Reveal });