// Homepage, Shop, Product Detail
function useInView(threshold = 0.12) {
const ref = React.useRef(null);
const [visible, setVisible] = React.useState(false);
React.useEffect(() => {
const obs = new IntersectionObserver(([e]) => {
if (e.isIntersecting) { setVisible(true); obs.disconnect(); }
}, { threshold });
if (ref.current) obs.observe(ref.current);
return () => obs.disconnect();
}, []);
return [ref, visible];
}
function ProductCard({ p, vp, goto, addToCart, wishlist, toggleWish }) {
const [hover, setHover] = React.useState(false);
const [imgHover, setImgHover] = React.useState(false);
const [heartPop, setHeartPop] = React.useState(false);
const isMobile = vp === 'mobile';
const handleWish = (e) => { e.stopPropagation(); toggleWish(p.id); setHeartPop(true); setTimeout(() => setHeartPop(false), 420); };
const isWished = wishlist.includes(p.id);
return (
setHover(true)} onMouseLeave={() => setHover(false)} className="card-hover" style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
setImgHover(true)} onMouseLeave={() => setImgHover(false)} style={{ position: 'relative', aspectRatio: '4/5', borderRadius: 8, overflow: 'hidden', background: 'var(--surface)', cursor: 'pointer' }} onClick={() => goto('Product', p.id)}>
{p.img
?
:
{p.name} {p.weight}
}
{p.badge &&
{p.badge}
}
{(hover || isMobile) && (
{ e.stopPropagation(); addToCart(p); }}
style={{ position: 'absolute', bottom: 12, left: 12, right: 12, padding: '11px 12px', background: 'var(--ink)', color: 'var(--bg)', borderRadius: 999, fontSize: 12, fontWeight: 500, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6, animation: 'quickAddIn 0.22s cubic-bezier(0.22,1,0.36,1)' }}>
Quick add — ₹{p.price}
)}
goto('Product', p.id)} style={{ textAlign: 'left', fontSize: 15, fontWeight: 500, letterSpacing: '-0.01em', lineHeight: 1.3 }}>{p.name}
₹{p.price}
{p.mrp > p.price && ₹{p.mrp} }
{p.tagline}
{p.rating} · {p.reviews.toLocaleString()}
);
};
function useCounter(target, active, duration = 1400) {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
if (!active) return;
const num = parseInt(target);
const start = performance.now();
const tick = (now) => {
const p = Math.min((now - start) / duration, 1);
const ease = 1 - Math.pow(1 - p, 3);
setCount(Math.round(ease * num));
if (p < 1) requestAnimationFrame(tick);
};
requestAnimationFrame(tick);
}, [active]);
return count;
}
// ============ HOMEPAGE ============
function HomePage({ vp, goto, addToCart, wishlist, toggleWish, openQuiz, onIngredientSelect }) {
const isMobile = vp === 'mobile';
const isTablet = vp === 'tablet';
const heroProduct = window.PRODUCTS[0];
const [concernRef, concernVisible] = useInView();
const [bestsellerRef, bestsellerVisible] = useInView();
const [ingredientRef, ingredientVisible] = useInView();
const [reviewRef, reviewVisible] = useInView();
const [journalRef, journalVisible] = useInView();
const [ctaRef, ctaVisible] = useInView();
const [statsRef, statsVisible] = useInView();
const c0 = useCounter('40', statsVisible);
const c1 = useCounter('53', statsVisible);
const c2 = useCounter('6', statsVisible);
const c3 = useCounter('100', statsVisible);
const counters = [`${c0}+`, `${c1}`, `${c2}`, `${c3}%`];
const stats = [['40+', 'herbs per formula'], ['53', 'herbs in Shahi Kalp'], ['6', 'products available'], ['100%', 'cold-processed']];
const setSelectedIngredient = (h) => onIngredientSelect && onIngredientSelect(h);
return (
{/* HERO */}
Heritage batch · winter '26
Rooted in Nature,
Refined for You .
40+ traditional Ayurvedic herbs, cold-processed to preserve every compound. NK Herbal — Mumbai's trusted name in classical wellness formulations.
goto('Product', heroProduct.id)}>Shop {heroProduct.name} — ₹{heroProduct.price.toLocaleString('en-IN')}
Find my paste in 60s
{stats.map(([n, l], i) => {
const n2 = counters[i];
return (
);
})}
Batch NK-101 · Muejaza For Men
Cold-processed · 40+ herbs · 300 g
goto('Ingredients')}/>
{/* SOCIAL PROOF TICKER */}
{[0,1].map(k => (
{[
{ name: 'Rajesh D.', city: 'Mumbai', text: 'Best product for men\'s health. Noticed energy difference in 2 weeks.' },
{ name: 'Priya S.', city: 'Delhi', text: 'Shahi Kalp has become my daily ritual. Sleep is so much better.' },
{ name: 'Jitendar P.', city: 'Bengaluru', text: 'Good quality and fast delivery. Will definitely reorder.' },
{ name: 'Amit K.', city: 'Pune', text: 'The Kashmiri Shilajit quality is unmatched. Authentic resin.' },
{ name: 'Sunita R.', city: 'Chennai', text: 'Finally an Ayurvedic brand that explains what\'s inside the jar.' },
].map((r, i) => (
★★★★★
"{r.text}"
— {r.name}, {r.city}
·
))}
))}
{/* SHOP BY CONCERN */}
What can we help with today?
goto('Shop')} className="mono" style={{ color: 'var(--muted)', textDecoration: 'underline' }}>all concerns →
{window.CONCERNS.map(c => (
goto('Shop')} className="concern-card" style={{ padding: '24px 16px', background: 'var(--surface)', border: '1px solid var(--line-soft)', borderRadius: 12, display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: 24, textAlign: 'left', minHeight: 140, transition: 'all 0.25s' }}
onMouseEnter={e => { e.currentTarget.style.borderColor = 'var(--ink)'; e.currentTarget.style.background = 'var(--bg)'; }}
onMouseLeave={e => { e.currentTarget.style.borderColor = 'var(--line-soft)'; e.currentTarget.style.background = 'var(--surface)'; }}>
{c.label}
{c.count} products
))}
{/* BEST SELLERS */}
Best sellers
The jars on every shelf.
goto('Shop')} className="btn btn-ghost">Shop all
{window.PRODUCTS.slice(0, 4).map((p, i) => (
))}
{/* HERITAGE / STORY BLOCK */}
Est. 1962 · Kasaragod, Kerala
Our grandfather refused to use a pressure cooker.
He believed slow heat changed the medicine — not the chemistry on paper, but what your body felt at the third teaspoon, the third month. We have not changed his mind.
Every jar still takes 21 days, three vaidyas, one wood fire, and a frankly inconvenient amount of patience.
goto('About')} className="btn" style={{ background: 'var(--primary-ink)', color: 'var(--primary)' }}>The full story
{/* BENTO GRID */}
Why NK Herbal
{/* Large tile */}
Cold-processed
40+ herbs per formula
Every formulation is cold-processed to preserve heat-sensitive compounds lost in conventional cooking.
{/* Cert tile */}
FSSAI
Approved & registered
{['ISO 9001', 'Non-GMO', 'Cruelty Free'].map(c => {c} )}
{/* Shipping tile */}
Free delivery
Pan India · all orders
{/* Save tile */}
Save ₹499
Use code SAVE499 on first order
{/* Review tile */}
{'★★★★★'}
"Best product for men's health. Noticed energy difference in 2 weeks."
Rajesh D. · Mumbai · verified
{/* INGREDIENT SHELF */}
The herb shelf
Sourcing is the recipe.
goto('Ingredients')} className="btn btn-ghost">Every ingredient
{window.HERO_INGREDIENTS.map((h, i) => (
setSelectedIngredient(h)} style={{ textAlign: 'left', padding: 0, opacity: ingredientVisible ? 1 : 0, transform: ingredientVisible ? 'translateY(0)' : 'translateY(16px)', transition: `opacity 0.45s cubic-bezier(0.22,1,0.36,1) ${i * 60}ms, transform 0.45s cubic-bezier(0.22,1,0.36,1) ${i * 60}ms` }}>
{h.img
?
: {h.name}
}
{h.name}
{h.latin}
{h.role}
))}
{/* REVIEWS */}
Verified customer reviews
4.5 out of five
{window.REVIEWS.map((r, i) => (
))}
{/* WHATSAPP CTA */}
Mon–Sat · 10 am – 7 pm IST
Have a question? Chat with us.
Not sure which formula is right for you? Our team is on WhatsApp — ask about ingredients, dosage, or anything else before you order.
WhatsApp us
{[
{ q: 'Which formula suits me?', a: 'Tell us your health goal and we\'ll point you to the right one.' },
{ q: 'What\'s in each jar?', a: 'Full ingredient lists, sourcing, and lab reports — no secrets.' },
{ q: 'Delivery & returns?', a: 'Free shipping across India · 7-day return policy.' },
].map(({ q, a }) => (
))}
{/* JOURNAL TEASERS */}
The journal
Slower reading.
goto('Journal')} className="btn btn-ghost">All notes
{window.JOURNAL.map(j => (
goto('Journal')} style={{ textAlign: 'left' }}>
{j.cat}
{j.cat}
{j.read}
{j.title}
{j.excerpt}
))}
);
};
function HoverArrowBtn({ onClick }) {
const [hov, setHov] = React.useState(false);
return (
setHov(true)} onMouseLeave={() => setHov(false)}
style={{ width: 36, height: 36, borderRadius: 999, border: `1px solid ${hov ? 'var(--ink)' : 'var(--line)'}`, background: hov ? 'var(--ink)' : 'transparent', color: hov ? 'var(--bg)' : 'var(--ink)', display: 'flex', alignItems: 'center', justifyContent: 'center', overflow: 'hidden', position: 'relative', transition: 'all 0.25s cubic-bezier(0.22,1,0.36,1)' }}>
);
}
function CheckItem({ label }) {
const [checked, setChecked] = React.useState(false);
return (
setChecked(c => !c)} style={{ display: 'flex', gap: 10, alignItems: 'center', fontSize: 14, textAlign: 'left', transition: 'opacity 0.2s' }}>
{checked && }
{label}
);
}
function SortDropdown({ value, onChange }) {
const [open, setOpen] = React.useState(false);
const ref = React.useRef(null);
const options = [
{ v: 'featured', l: 'Featured' },
{ v: 'rating', l: 'Top rated' },
{ v: 'price-low', l: 'Price: low → high' },
{ v: 'price-high', l: 'Price: high → low' },
];
const selected = options.find(o => o.v === value);
React.useEffect(() => {
const handler = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
document.addEventListener('mousedown', handler);
return () => document.removeEventListener('mousedown', handler);
}, []);
return (
setOpen(o => !o)} style={{ display: 'inline-flex', alignItems: 'center', gap: 8, padding: '9px 16px', borderRadius: 999, border: '1px solid var(--line)', background: 'var(--bg)', fontSize: 13, fontWeight: 500, color: 'var(--ink)', letterSpacing: '-0.01em', transition: 'border-color 0.2s' }}
onMouseEnter={e => e.currentTarget.style.borderColor = 'var(--ink)'}
onMouseLeave={e => e.currentTarget.style.borderColor = 'var(--line)'}>
{selected.l}
{open && (
{options.map(o => (
{ onChange(o.v); setOpen(false); }}
style={{ display: 'block', width: '100%', textAlign: 'left', padding: '11px 16px', fontSize: 13, fontWeight: o.v === value ? 500 : 400, color: o.v === value ? 'var(--primary)' : 'var(--ink)', background: o.v === value ? 'var(--surface)' : 'transparent', transition: 'background 0.15s' }}
onMouseEnter={e => { if (o.v !== value) e.currentTarget.style.background = 'var(--surface)'; }}
onMouseLeave={e => { if (o.v !== value) e.currentTarget.style.background = 'transparent'; }}>
{o.l}
))}
)}
);
};
// ============ SHOP LISTING ============
function ShopPage({ vp, goto, addToCart, wishlist, toggleWish }) {
const isMobile = vp === 'mobile';
const isTablet = vp === 'tablet';
const [filter, setFilter] = React.useState('all');
const [sort, setSort] = React.useState('featured');
const [openFilter, setOpenFilter] = React.useState(false);
const [maxPrice, setMaxPrice] = React.useState(15000);
const [gridKey, setGridKey] = React.useState(0);
const applyFilter = (f) => { setFilter(f); setGridKey(k => k + 1); };
// Only animate grid on release, not on every slider tick
const handlePriceChange = (e) => setMaxPrice(Number(e.target.value));
const handlePriceRelease = () => setGridKey(k => k + 1);
let products = window.PRODUCTS.filter(p => (filter === 'all' || p.concerns.includes(filter)) && p.price <= maxPrice);
if (sort === 'price-low') products = [...products].sort((a, b) => a.price - b.price);
if (sort === 'price-high') products = [...products].sort((a, b) => b.price - a.price);
if (sort === 'rating') products = [...products].sort((a, b) => b.rating - a.rating);
return (
Home / Shop / All pastes
Every formula, in one place.
Six formulations. 40–53 herbs each. Cold-processed, preservative-free, FSSAI approved.
{/* Sidebar filter */}
{!isMobile && (
Filter by concern
{[{id:'all',label:'All pastes'}, ...window.CONCERNS].map(c => (
applyFilter(c.id)} style={{ textAlign: 'left', padding: '10px 0', fontSize: 15, color: filter === c.id ? 'var(--ink)' : 'var(--ink-2)', fontWeight: filter === c.id ? 500 : 400, display: 'flex', justifyContent: 'space-between', borderBottom: filter === c.id ? '1px solid var(--ink)' : '1px solid transparent', transition: 'all 0.2s' }}>
{c.label}
{c.count || window.PRODUCTS.length}
))}
Price
Suitable for
{['Diabetics', 'Kids 3+', 'Pregnancy-safe', 'Vegan'].map(t => (
))}
)}
{products.length} pastes
{isMobile && setOpenFilter(true)} className="btn btn-ghost btn-sm">Filters }
{products.length ? products.map((p, i) => (
)) : (
—
No products in this range
)}
{/* Bundle banner mid-grid */}
Bundle & save · ₹3,001 off
The wellness duo.
Muejaza + Shahi Kalp. Complete daily wellness for the whole family, cold-processed and FSSAI approved.
Get the combo — ₹8,999
{window.PRODUCTS.slice(0, 3).map(p =>
{p.name.split(' ')[0]}
)}
{/* Mobile filter sheet */}
{openFilter && isMobile && (
Filters
setOpenFilter(false)}>
Concern
{[{id:'all',label:'All pastes'}, ...window.CONCERNS].map(c => (
{ setFilter(c.id); setOpenFilter(false); }} style={{ textAlign: 'left', padding: '14px 0', fontSize: 16, borderBottom: '1px solid var(--line-soft)', color: filter === c.id ? 'var(--ink)' : 'var(--ink-2)' }}>{c.label}
))}
setOpenFilter(false)}>Apply
)}
);
};
function MagnifierImage({ src, alt, onZoom }) {
const [lens, setLens] = React.useState(null);
const ref = React.useRef(null);
const LENS = 150, ZOOM = 2.8;
const onMove = (e) => {
const r = ref.current.getBoundingClientRect();
setLens({ x: e.clientX - r.left, y: e.clientY - r.top, w: r.width, h: r.height });
};
return (
setLens(null)} onClick={() => onZoom && onZoom(src)}>
{lens && (
)}
);
};
// ============ PRODUCT DETAIL ============
function ProductPage({ vp, goto, addToCart, wishlist, toggleWish, productId, onStickyATC, openQuiz, onZoom }) {
const isMobile = vp === 'mobile';
const isTablet = vp === 'tablet';
const p = window.PRODUCTS.find(x => x.id === productId) || window.PRODUCTS[0];
const [qty, setQty] = React.useState(1);
const [variantIdx, setVariantIdx] = React.useState(0);
const [tab, setTab] = React.useState('how');
const [heartPop, setHeartPop] = React.useState(false);
const handleWish = () => { toggleWish(p.id); setHeartPop(true); setTimeout(() => setHeartPop(false), 420); };
const [activeImg, setActiveImg] = React.useState(0);
const [showStickyATC, setShowStickyATC] = React.useState(false);
const atcRef = React.useRef(null);
const atcSeenRef = React.useRef(false);
// Tab indicator — moved to component level to fix hooks-in-IIFE violation
const TABS = [['how','How to take'], ['ingr','Ingredients'], ['science','The science'], ['faq','FAQ']];
const tabRefs = React.useRef([]);
const [indicatorStyle, setIndicatorStyle] = React.useState({ left: 0, width: 0 });
React.useEffect(() => {
const idx = TABS.findIndex(([id]) => id === tab);
const el = tabRefs.current[idx];
if (el) setIndicatorStyle({ left: el.offsetLeft, width: el.offsetWidth });
}, [tab]);
React.useEffect(() => {
const obs = new IntersectionObserver(([e]) => {
if (e.isIntersecting) atcSeenRef.current = true;
if (atcSeenRef.current) setShowStickyATC(!e.isIntersecting);
}, { threshold: 0 });
if (atcRef.current) obs.observe(atcRef.current);
return () => { obs.disconnect(); onStickyATC && onStickyATC(null); };
}, []);
React.useEffect(() => {
if (onStickyATC) onStickyATC(showStickyATC ? { p, price, qty, addToCart, goto } : null);
}, [showStickyATC, price, qty]);
// Track recently viewed in localStorage
React.useEffect(() => {
const key = 'nkh_viewed';
const existing = JSON.parse(localStorage.getItem(key) || '[]');
const updated = [p.id, ...existing.filter(x => x !== p.id)].slice(0, 4);
localStorage.setItem(key, JSON.stringify(updated));
}, [p.id]);
const isWished = wishlist.includes(p.id);
const activeVariant = p.variants ? p.variants[variantIdx] : null;
const price = activeVariant ? activeVariant.price : p.price;
const mrp = activeVariant ? activeVariant.mrp : p.mrp;
const weight = activeVariant ? activeVariant.label : p.weight;
return (
goto('Home')}>Home / goto('Shop')}>Shop / {p.name}
{/* Gallery */}
{!isMobile && (
{[0].map(i => (
setActiveImg(i)} style={{ width: 64, height: 80, borderRadius: 4, border: activeImg === i ? '1.5px solid var(--ink)' : '1px solid var(--line)', overflow: 'hidden', background: 'var(--surface)' }}>
{p.img
?
: {i+1}
}
))}
)}
{p.img
?
: {p.name}No image yet
}
openQuiz && openQuiz()} title="Find similar products" style={{ width: 40, height: 40, borderRadius: 999, background: 'var(--bg)', border: '1px solid var(--line)', display: 'flex', alignItems: 'center', justifyContent: 'center', transition: 'background 0.2s, transform 0.2s' }}
onMouseEnter={e => { e.currentTarget.style.background = 'var(--surface)'; e.currentTarget.style.transform = 'rotate(30deg)'; }}
onMouseLeave={e => { e.currentTarget.style.background = 'var(--bg)'; e.currentTarget.style.transform = 'rotate(0deg)'; }}>
{isMobile && p.img && (
)}
{/* Info */}
{p.badge &&
{p.badge} }
{p.name}
{p.tagline}
{p.rating} · {p.reviews.toLocaleString()} reviews
{p.description}
{p.variants ? (
Size
{p.variants.map((v, i) => (
setVariantIdx(i)} style={{ flex: 1, padding: 14, borderRadius: 8, border: variantIdx === i ? '1.5px solid var(--ink)' : '1px solid var(--line)', background: variantIdx === i ? 'var(--surface)' : 'transparent', textAlign: 'left' }}>
{v.label}
₹{v.price.toLocaleString('en-IN')}
))}
) : (
{p.weight}
· one size
)}
₹{(price * qty).toLocaleString('en-IN')}
MRP ₹{mrp.toLocaleString('en-IN')} · inclusive of all taxes
setQty(Math.max(1, qty - 1))} style={{ padding: 12 }}>
{qty}
setQty(qty + 1)} style={{ padding: 12 }}>
{ addToCart(p, qty); }}>Add to basket
{ addToCart(p, qty); goto('Checkout'); }}>Buy now
{[['Ships in 24h', 'Cold-chain dispatch'], ['Free shipping', 'Across India'], ['Lab-tested', 'Every batch'], ['Returns', '7-day, no questions']].map(([t, s]) => (
))}
{/* Batch transparency */}
Current batch
Batch #NK-{Math.abs(p.id.charCodeAt(0) * 7 % 900) + 100} · Made Jan 2026
FSSAI approved · ISO 9001-2015 · Lab-tested
View report ↗
{/* Tabs */}
{TABS.map(([id, l], i) => (
tabRefs.current[i] = el} onClick={() => setTab(id)} style={{ padding: '16px 0', fontSize: 15, fontWeight: tab === id ? 500 : 400, color: tab === id ? 'var(--ink)' : 'var(--muted)', whiteSpace: 'nowrap', transition: 'color 0.2s' }}>{l}
))}
{tab === 'how' && (
{[
{ n: '01', t: 'Morning, on an empty stomach', d: 'One teaspoon (5g) by itself, or stirred into warm milk for kids and elders. Wait 20 minutes before food.' },
{ n: '02', t: 'Daily, through cool months', d: 'Take consistently from late September through March. In summer, halve the dose or switch to evening with cold milk.' },
{ n: '03', t: 'Pair with the morning ritual', d: 'Works best alongside warm water and twenty minutes of gentle movement. Avoid heavy fats or curd directly after.' },
].map(s => (
))}
)}
{tab === 'ingr' && (
The full list — every herb, every quantity, every source. Nothing on the label that is not in the jar.
{window.HERO_INGREDIENTS.concat(window.HERO_INGREDIENTS).map((h, i) => (
))}
)}
{tab === 'science' && (
The classical text Charaka Samhita describes chyawanprash as a rasayana — a formulation that improves the body's capacity to do its own work. We have not tried to improve on that idea.
What we have done is publish our lab work: heavy-metal panels for every batch, microbiology results, vitamin-C retention curves after the slow cook. Every batch number on the jar links to a one-page report.
See batch {412} lab report
)}
{tab === 'faq' && (
{[
['Is it safe for diabetics?', 'The classic recipe contains jaggery and honey. For diabetics, choose our Sugar-Free version (sweetened with whole dates) or consult our vaidya for a personalised plan.'],
['Can children take it?', 'Yes — but use the Kids formulation for ages 3+. The classic is calibrated for adolescents and adults.'],
['Why does the taste vary slightly between batches?', 'Because the herbs vary. Amla in November is different from amla in February. We let the difference through; we do not flatten it with flavoring.'],
['How long does an open jar keep?', 'Refrigerated, 6 months. At room temperature (below 25°C), 3 months. Always use a dry spoon.'],
].map(([q, a]) => (
{q}
{a}
))}
)}
{/* You might also like */}
You might also like
{window.PRODUCTS.filter(x => x.id !== p.id).slice(0, 4).map(pp =>
)}
{/* Recently viewed */}
{(() => {
const viewed = JSON.parse(localStorage.getItem('nkh_viewed') || '[]').filter(id => id !== p.id);
const viewedProducts = viewed.map(id => window.PRODUCTS.find(x => x.id === id)).filter(Boolean);
if (!viewedProducts.length) return null;
return (
Recently viewed
{viewedProducts.slice(0, 4).map(pp =>
)}
);
})()}
);
}
window.ProductCard = ProductCard;
window.HomePage = HomePage;
window.ShopPage = ShopPage;
window.ProductPage = ProductPage;