/* My Vital Cell website kit — shared parts: Logo, image components, Header, Footer */ function VCLogo({ dark = false, size = 54 }) { const c = dark ? '#FF5670' : '#DC2743'; return (
MY VITAL CELL
ELEVATING WELLNESS
); } /* Constellation overlay — echoes the cellular-network motif */ function MoleculeField({ color = 'rgba(220,39,67,0.85)', opacity = 1, dense = false, linkDistance = 34, speed = 1, nodeScale = 1 }) { const svgRef = React.useRef(null); const linesRef = React.useRef(null); const dotsRef = React.useRef(null); const ptsRef = React.useRef(null); React.useEffect(() => { // Seed points in a 100x100 virtual space with slow drift velocities const N = dense ? 14 : 9; const rand = (a, b) => a + Math.random() * (b - a); const pts = Array.from({ length: N }, () => ({ x: rand(6, 94), y: rand(6, 94), vx: rand(-0.05, 0.05) * speed, vy: rand(-0.05, 0.05) * speed, r: (Math.random() < 0.35 ? 1.05 : 0.7) * nodeScale, phase: Math.random() * Math.PI * 2, })); ptsRef.current = pts; const svg = svgRef.current; if (!svg) return; const NS = 'http://www.w3.org/2000/svg'; // Build dots const dotsG = dotsRef.current; while (dotsG.firstChild) dotsG.removeChild(dotsG.firstChild); const dotEls = pts.map((p) => { const c = document.createElementNS(NS, 'circle'); c.setAttribute('r', p.r); c.setAttribute('fill', color); dotsG.appendChild(c); return c; }); // Build line pool for all possible pairs const linesG = linesRef.current; while (linesG.firstChild) linesG.removeChild(linesG.firstChild); const pairs = []; for (let i = 0; i < N; i++) for (let j = i + 1; j < N; j++) pairs.push([i, j]); const lineEls = pairs.map(() => { const l = document.createElementNS(NS, 'line'); l.setAttribute('stroke', color); l.setAttribute('stroke-width', String(0.28 * nodeScale)); l.setAttribute('stroke-linecap', 'round'); linesG.appendChild(l); return l; }); let raf = 0; const tick = (t) => { for (let i = 0; i < pts.length; i++) { const p = pts[i]; p.x += p.vx; p.y += p.vy; if (p.x < 4 || p.x > 96) p.vx *= -1; if (p.y < 4 || p.y > 96) p.vy *= -1; const pulse = 0.75 + 0.25 * Math.sin(t * 0.0012 * speed + p.phase); dotEls[i].setAttribute('cx', p.x.toFixed(2)); dotEls[i].setAttribute('cy', p.y.toFixed(2)); dotEls[i].setAttribute('opacity', pulse.toFixed(3)); } for (let k = 0; k < pairs.length; k++) { const [a, b] = pairs[k]; const pa = pts[a], pb = pts[b]; const dx = pa.x - pb.x, dy = pa.y - pb.y; const d = Math.sqrt(dx * dx + dy * dy); const el = lineEls[k]; if (d < linkDistance) { const strength = 1 - d / linkDistance; const fade = 0.35 + 0.55 * Math.sin(t * 0.0006 * speed + (a + b)); const o = Math.max(0, Math.min(1, strength * (0.35 + 0.65 * Math.abs(fade)))); el.setAttribute('x1', pa.x.toFixed(2)); el.setAttribute('y1', pa.y.toFixed(2)); el.setAttribute('x2', pb.x.toFixed(2)); el.setAttribute('y2', pb.y.toFixed(2)); el.setAttribute('opacity', o.toFixed(3)); } else { el.setAttribute('opacity', '0'); } } raf = requestAnimationFrame(tick); }; raf = requestAnimationFrame(tick); return () => cancelAnimationFrame(raf); }, [color, dense, linkDistance, speed, nodeScale]); return ( ); } /* Real photography component — replaces VCImage's wash placeholder. Falls back to constellation overlay if no src. */ function VCPhoto({ src, alt = '', overlay = 'none', ken = false, style = {}, className = '' }) { const overlays = { none: null, ink: 'linear-gradient(180deg, rgba(15,15,18,0.0) 50%, rgba(15,15,18,0.55) 100%)', warm: 'linear-gradient(180deg, rgba(40,12,16,0.0) 55%, rgba(40,12,16,0.45) 100%)', soft: 'linear-gradient(180deg, rgba(255,255,255,0.0) 60%, rgba(255,255,255,0.35) 100%)', }; return (
{alt} {overlays[overlay] && (
)}
); } /* Branded image placeholder — retained as a fallback when no photo is supplied. */ function VCImage({ tone = 'cool', label, style = {}, children }) { const washes = { cool: 'linear-gradient(135deg, #e9eaee 0%, #f4f1f3 55%, #eceef1 100%)', warm: 'linear-gradient(135deg, #f6ece4 0%, #f8f0ea 50%, #f0e7e2 100%)', skin: 'linear-gradient(135deg, #f6ece9 0%, #f8f1ef 45%, #efe6e6 100%)', crimson: 'linear-gradient(135deg, #2a1418 0%, #4a1822 60%, #2a1014 100%)', ink: 'linear-gradient(135deg, #16161a 0%, #22222a 100%)', }; return (
{label && (
{label}
)} {children}
); } /* ---------- Cart store (shared, event-driven, localStorage-backed) ---------- */ (function initCartStore() { if (window.VC_CART) return; const KEY = 'mvc_cart_v2'; const load = () => { try { return JSON.parse(localStorage.getItem(KEY) || '[]'); } catch { return []; } }; const save = (items) => { try { localStorage.setItem(KEY, JSON.stringify(items)); } catch {} // Mirror count to legacy key for anything still reading it const count = items.reduce((s, it) => s + (it.qty || 1), 0); try { localStorage.setItem('mvc_cart_count', String(count)); } catch {} window.dispatchEvent(new CustomEvent('vc-cart-change', { detail: { items, count } })); }; const priceFor = (name) => { // Explicit override wins (e.g. Bacteriostatic Water = $5) const overrides = (window.VC_PRICE_OVERRIDE) || {}; if (Object.prototype.hasOwnProperty.call(overrides, name)) return overrides[name]; // Deterministic pseudo-price: $180–$420 in $10 steps based on name hash let h = 0; for (let i = 0; i < name.length; i++) h = (h * 31 + name.charCodeAt(i)) >>> 0; return 180 + (h % 25) * 10; }; window.VC_CART = { KEY, get: load, count: () => load().reduce((s, it) => s + (it.qty || 1), 0), subtotal: () => load().reduce((s, it) => s + (it.price || 0) * (it.qty || 1), 0), price: priceFor, add: (item) => { const items = load(); const key = item.name; const found = items.find((x) => x.name === key); if (found) found.qty = (found.qty || 1) + (item.qty || 1); else items.push({ name: item.name, catLabel: item.catLabel || '', formula: item.formula || '', price: item.price != null ? item.price : priceFor(item.name), qty: item.qty || 1 }); save(items); window.dispatchEvent(new CustomEvent('vc-cart-open')); }, setQty: (name, qty) => { const items = load().map((it) => it.name === name ? { ...it, qty: Math.max(1, qty) } : it); save(items); }, remove: (name) => save(load().filter((it) => it.name !== name)), clear: () => save([]), }; })(); function CartDrawer({ open, onClose, onNav }) { const [items, setItems] = React.useState(() => window.VC_CART.get()); const [toast, setToast] = React.useState(''); React.useEffect(() => { const h = () => setItems(window.VC_CART.get()); window.addEventListener('vc-cart-change', h); return () => window.removeEventListener('vc-cart-change', h); }, []); React.useEffect(() => { if (open) document.body.style.overflow = 'hidden'; else document.body.style.overflow = ''; window.dispatchEvent(new CustomEvent('vc-cart-visibility', { detail: { open } })); return () => { document.body.style.overflow = ''; }; }, [open]); const subtotal = items.reduce((s, it) => s + (it.price || 0) * (it.qty || 1), 0); const fmt = (n) => '$' + n.toFixed(2); return ( <>
); } function Header({ page, onNav }) { const { IconButton } = window.VitalCellDesignSystem_fbb4ec; const [cartCount, setCartCount] = React.useState(() => window.VC_CART.count()); const [cartOpen, setCartOpen] = React.useState(false); const [menuOpen, setMenuOpen] = React.useState(false); React.useEffect(() => { const h = (e) => setCartCount(e.detail?.count ?? window.VC_CART.count()); const openH = () => setCartOpen(true); window.addEventListener('vc-cart-change', h); window.addEventListener('vc-cart-open', openH); return () => { window.removeEventListener('vc-cart-change', h); window.removeEventListener('vc-cart-open', openH); }; }, []); React.useEffect(() => { window.lucide && window.lucide.createIcons(); }, [cartOpen, cartCount, menuOpen]); React.useEffect(() => { setMenuOpen(false); }, [page]); const items = [ { k: 'home', t: 'Home' }, { k: 'compounds', t: 'Compounds' }, { k: 'science', t: 'Learn' }, { k: 'about', t: 'About' }, { k: 'contact', t: 'Contact' }, ]; return (
onNav('home')} style={{ cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 14 }}>
MY VITAL CELL
ELEVATING WELLNESS
Beta
{menuOpen && (
{items.map((it) => ( { onNav(it.k); setMenuOpen(false); }} style={{ display: 'block', padding: '14px 6px', borderBottom: '1px solid var(--color-border)', cursor: 'pointer', fontFamily: 'var(--font-body)', fontWeight: 700, fontSize: '14px', letterSpacing: '0.16em', textTransform: 'uppercase', color: page === it.k ? 'var(--color-accent)' : 'var(--color-ink-strong)', textDecoration: 'none' }}>{it.t} ))}
)} setCartOpen(false)} onNav={onNav} />
); } function Footer({ onNav }) { const cols = [ { h: 'Compounds', k: 'compounds', items: ['Regeneration', 'Recovery', 'Metabolic', 'Longevity', 'Cognitive'] }, { h: 'Learn', k: 'science', items: ['Cellular basics', 'Research themes', 'Education', 'Quality standards'] }, { h: 'Company', k: 'about', items: ['About', 'Insights journal', 'Press', 'Careers', 'Contact'] }, ]; const linkFor = (label) => { const l = label.toLowerCase(); if (l.includes('insight')) return 'insights'; if (l.includes('quality')) return 'quality'; if (l.includes('about')) return 'about'; if (l.includes('contact')) return 'contact'; if (l.includes('research')|| l.includes('science') || l.includes('education')) return 'science'; return 'compounds'; }; return ( ); } Object.assign(window, { VCLogo, MoleculeField, VCImage, VCPhoto, Header, Footer });