/* Kit-local helpers for the NOTHUMAN site. Loaded before the section files. */ const VS = window.VamshotDesignSystem_18ef2a; const vsReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches; const vsTouch = window.matchMedia('(hover:none),(pointer:coarse)').matches; const vsMQ = { mobile: '(max-width:767px)', handheld: '(max-width:900px)', tablet: '(max-width:1024px)' }; /* One rAF loop for every scroll-driven effect on the page. All reads happen in the same frame, so nothing interleaves read/write and thrashes layout. */ const vsScroll = (function () { const subs = new Set(); let raf = 0; const flush = function () { raf = 0; const y = window.scrollY, h = window.innerHeight; subs.forEach(function (fn) { fn(y, h); }); }; const schedule = function () { if (!raf) raf = requestAnimationFrame(flush); }; window.addEventListener('scroll', schedule, { passive: true }); window.addEventListener('resize', schedule); return { add: function (fn) { subs.add(fn); schedule(); return function () { subs.delete(fn); }; }, ping: schedule }; })(); const vsClamp = function (v, a, b) { a = a === undefined ? 0 : a; b = b === undefined ? 1 : b; return Math.min(b, Math.max(a, v)); }; const vsRange = function (p, a, b) { return vsClamp((p - a) / (b - a)); }; function useReveal() { const ref = React.useRef(null); React.useEffect(function () { const el = ref.current; if (!el) return undefined; const io = new IntersectionObserver(function (entries) { entries.forEach(function (e) { if (e.isIntersecting) { e.target.classList.add('is-in'); io.unobserve(e.target); } }); }, { threshold: 0.12, rootMargin: '0px 0px -6% 0px' }); el.querySelectorAll('.vs-r,.vs-line,.vs-mask').forEach(function (n) { io.observe(n); }); if (el.classList.contains('vs-r')) io.observe(el); return function () { io.disconnect(); }; }, []); return ref; } function Reveal({ children, delay, style, className, ...rest }) { return
{children}
; } function Line({ delay, accent, style }) { return
; } /* 0 -> 1 across the scrollable travel of a tall section. Rides the shared rAF bus; pass enabled=false (mobile, reduced motion) to opt out entirely. */ function useProgress(ref, enabled) { const live = enabled !== false; const [p, setP] = React.useState(0); React.useEffect(function () { const el = ref.current; if (!el || !live) return undefined; let last = -1; return vsScroll.add(function (y, h) { const r = el.getBoundingClientRect(); const total = r.height - h; const next = total > 0 ? vsClamp(-r.top / total) : 0; if (Math.abs(next - last) < 0.0015) return; last = next; setP(next); }); }, [ref, live]); return live ? p : 0; } function useMedia(query) { const [match, setMatch] = React.useState(function () { return window.matchMedia(query).matches; }); React.useEffect(function () { const mq = window.matchMedia(query); const on = function () { setMatch(mq.matches); }; mq.addEventListener('change', on); return function () { mq.removeEventListener('change', on); }; }, [query]); return match; } /* Image treatments — cool, desaturated, high contrast, grain-forward. */ const vsTones = { cool: 'grayscale(0.45) contrast(1.14) brightness(0.9) saturate(0.8)', mono: 'grayscale(1) contrast(1.16) brightness(0.86)', deep: 'grayscale(0.9) contrast(1.3) brightness(0.62)' }; function Media({ src, alt, ratio, tone, label, position, fill, style, imgStyle, mask, cursor }) { const [hover, setHover] = React.useState(false); return (
{alt ); } function Marks({ children, style }) { return {children}; } /* One-word-sentence stack — the brand's list form. */ function SentenceStack({ items, color, size, style }) { return (
{items.map(function (t, i) { const accent = typeof t !== 'string'; return {accent ? t.text : t}; })}
); } function Shell({ id, children, ruled, style, innerStyle }) { const ref = useReveal(); return (
{children}
); } /* ₹ counters, Indian grouping, counted up once in view. */ function vsIndian(n) { const s = String(n); if (s.length <= 3) return s; const last = s.slice(-3); let rest = s.slice(0, -3), out = ''; while (rest.length > 2) { out = ',' + rest.slice(-2) + out; rest = rest.slice(0, -2); } return (rest ? rest + out : out.slice(1)) + ',' + last; } function CountUp({ value, prefix, accent, style }) { const ref = React.useRef(null); const [n, setN] = React.useState(vsReduced ? value : 0); React.useEffect(function () { if (vsReduced) return undefined; const el = ref.current; if (!el) return undefined; let raf = 0; const io = new IntersectionObserver(function (entries) { if (!entries[0].isIntersecting) return; io.disconnect(); const start = performance.now(), dur = 1600; const tick = function (t) { const k = vsClamp((t - start) / dur); setN(Math.round(value * (1 - Math.pow(1 - k, 3)))); if (k < 1) raf = requestAnimationFrame(tick); }; raf = requestAnimationFrame(tick); }, { threshold: 0.6 }); io.observe(el); return function () { io.disconnect(); cancelAnimationFrame(raf); }; }, [value]); return ( {(prefix || '') + vsIndian(n)} ); } Object.assign(window, { VS, vsReduced, vsTouch, vsMQ, vsScroll, vsClamp, vsRange, useReveal, Reveal, Line, useProgress, useMedia, Media, Marks, SentenceStack, Shell, CountUp, vsTones });