// Winkz Designs 2026 — shared FX & primitives
(function () {
const { useEffect, useRef, useState } = React;
const BRAND_GRAD = 'linear-gradient(120deg,#F23BFE 0%,#79BAFF 52%,#2DE3EA 100%)';
/* Lucide icon */
function Icon({ n, s = 18, color = 'currentColor', strokeWidth = 2, style = {} }) {
const r = useRef(null);
useEffect(() => {
if (r.current && window.lucide && lucide[n]) {
const svg = lucide.createElement(lucide[n]);
svg.setAttribute('width', s); svg.setAttribute('height', s);
svg.setAttribute('stroke', color); svg.setAttribute('stroke-width', strokeWidth);
r.current.innerHTML = svg.outerHTML;
}
});
return ;
}
/* Scroll-driven reveal (transform-only so content is always visible). */
function Reveal({ children, delay = 0, y = 22, style = {}, as = 'div', ...rest }) {
const ref = useRef(null);
const [shown, setShown] = useState(false);
useEffect(() => {
const el = ref.current; if (!el) return;
let alive = true;
const check = () => {
if (!alive || !ref.current) return;
const r = ref.current.getBoundingClientRect();
const vh = window.innerHeight || document.documentElement.clientHeight;
if (r.top < vh * 0.94 && r.bottom > -40) { setShown(true); cleanup(); }
};
const onScroll = () => check();
const cleanup = () => { alive = false; window.removeEventListener('scroll', onScroll); window.removeEventListener('resize', onScroll); };
window.addEventListener('scroll', onScroll, { passive: true });
window.addEventListener('resize', onScroll, { passive: true });
check(); setTimeout(check, 70); setTimeout(check, 260); setTimeout(check, 600);
return cleanup;
}, []);
const El = as;
return (
{children}
);
}
/* Count-up */
function Counter({ to, suffix = '', prefix = '', dur = 1500, style = {} }) {
const ref = useRef(null); const [val, setVal] = useState(0); const done = useRef(false);
useEffect(() => {
const el = ref.current; if (!el) return;
const run = () => {
if (done.current) return;
const r = el.getBoundingClientRect();
const vh = window.innerHeight || document.documentElement.clientHeight;
if (r.top < vh * 0.9 && r.bottom > 0) {
done.current = true; window.removeEventListener('scroll', onScroll);
const start = Date.now();
const tick = () => { const p = Math.min(1, (Date.now() - start) / dur); setVal(Math.round((1 - Math.pow(1 - p, 3)) * to)); if (p < 1) setTimeout(tick, 24); };
tick();
}
};
const onScroll = () => run();
window.addEventListener('scroll', onScroll, { passive: true });
run(); setTimeout(run, 80); setTimeout(run, 260);
return () => window.removeEventListener('scroll', onScroll);
}, [to, dur]);
return {prefix}{val}{suffix};
}
/* Eyebrow chip */
function Eyebrow({ children, center = false }) {
return (
{children}
);
}
function SectionHead({ eyebrow, title, sub, center = false, max = 720 }) {
return (
{eyebrow &&
{eyebrow}}
{title}
{sub &&
{sub}
}
);
}
/* Panel — restrained card: subtle border, faint fill, optional gradient hairline on hover */
function Panel({ children, style = {}, hover = false, pad = 26, active = false, ...rest }) {
const [h, setH] = useState(false);
const lit = h || active;
return (
hover && setH(true)} onMouseLeave={() => hover && setH(false)}
style={{
position: 'relative', borderRadius: 18, padding: 1,
background: lit ? 'linear-gradient(135deg, rgba(242,59,254,0.5), rgba(121,186,255,0.35), rgba(45,227,234,0.5))' : 'rgba(255,255,255,0.09)',
transition: 'transform .4s cubic-bezier(.16,1,.3,1), background .4s ease, box-shadow .4s ease',
transform: h && hover ? 'translateY(-5px)' : 'none',
boxShadow: lit ? '0 24px 60px -32px rgba(45,227,234,0.4)' : '0 10px 34px -26px rgba(0,0,0,0.7)',
...style,
}} {...rest}>
{children}
);
}
/* Horizontal infinite marquee. items: array of nodes; speed in px/s; reverse optional */
function Marquee({ items, speed = 40, reverse = false, style = {}, sep = true }) {
const trackRef = useRef(null);
const [w, setW] = useState(0);
useEffect(() => { if (trackRef.current) setW(trackRef.current.scrollWidth / 2); }, [items]);
const dur = w ? w / speed : 20;
const row = (k) => (
{items.map((it, i) => (
{it}
{sep && }
))}
);
return (
);
}
/* Section wrapper with consistent vertical rhythm */
function Section({ children, id, style = {}, pad = 110 }) {
return ;
}
/* Gradient text helper */
function Grad({ children, style = {} }) {
return {children};
}
Object.assign(window, { Icon, Reveal, Counter, Eyebrow, SectionHead, Panel, Marquee, Section, Grad, BRAND_GRAD });
})();