/* ========================================================================== MY MONSTERS — shop.jsx (Phase 4-B) /shop page: hero → 3-channel grid → FAQ → footer ========================================================================== */ const { useState: _useShopS } = React; function ShopHero() { return (

WHERE TO BUY · 09

購入チャネルから、
モンスターを呼べ。

); } function ShopChannels() { const channels = [ { brand: 'RAKUTEN', brandJp: '楽天市場', channel: 'rakuten', pitch: 'ポイントが貯まる、楽天ユーザーへ。', soonMeta: '6月中公開予定', perks: ['楽天ポイント還元', '楽天スーパーセール対応', 'お買い物マラソン参加可'], cta: '6月中公開予定', href: '#', live: false }, { brand: 'AMAZON', brandJp: 'Amazon.co.jp', channel: 'amazon', pitch: '翌日配送、Prime対応。', trophy: true, perks: ['Prime会員 送料無料', '定期おトク便対応', 'Amazon NO.1 受賞商品(A.S.E活)'], cta: 'Amazonで購入する', href: 'https://amzn.asia/d/08kIElEd', live: true }, { brand: 'MY MONSTERS', brandJp: '自社EC(準備中)', pitch: 'COMING SOON.', soonMeta: '2026 年内ローンチ予定', perks: ['限定パッケージ先行販売', 'モンスターランド会員特典', '直送オリジナル定期便'], cta: 'COMING SOON', href: '#', live: false } ]; return (
{channels.map((c, i) => ( { if (!c.live) e.preventDefault(); }} target={c.live ? '_blank' : undefined} rel={c.live ? 'noopener noreferrer' : undefined} >
{c.brand} {c.brandJp}

{c.pitch}

{c.soonMeta && {c.soonMeta}}
    {c.perks.map((p, j) =>
  • {p}
  • )}
{c.cta} {c.live && →}
))}
); } function ShopFaq() { const items = window.MM_SHOP_FAQ; const [open, setOpen] = _useShopS(0); return (

— FREQUENTLY ASKED QUESTIONS

気になる、購入のこと。

); } function ShopBackLink() { return ( ); } function ShopPage() { const openShop = () => { /* already here */ }; // Fixed namiki (tree-lined avenue) backdrop — same behavior as the homepage // land-tour: a position:fixed image that only shows while the WHERE TO BUY // range (back link → hero → channels) is on screen. IntersectionObserver // toggles .is-active; outside the range the backdrop fades to opacity:0. React.useEffect(() => { const range = document.querySelector('.shop-landtour'); const bg = document.querySelector('.shop-landtour__bg'); if (!range || !bg) return; let raf = 0; const update = () => { raf = 0; const r = range.getBoundingClientRect(); const vh = window.innerHeight || document.documentElement.clientHeight; // Active while any part of the WHERE TO BUY range is within the viewport; // hidden once it has fully scrolled past (FAQ / footer below). const active = r.top < vh && r.bottom > 0; bg.classList.toggle('is-hidden', !active); }; const onScroll = () => { if (!raf) raf = requestAnimationFrame(update); }; window.addEventListener('scroll', onScroll, { passive: true }); window.addEventListener('resize', onScroll, { passive: true }); // IntersectionObserver as an enhancement (silent in some iframes, so the // scroll listener above is the real driver). let io; try { io = new IntersectionObserver((entries) => { entries.forEach((e) => bg.classList.toggle('is-hidden', !e.isIntersecting)); }, { threshold: 0 }); io.observe(range); } catch (err) {} update(); return () => { window.removeEventListener('scroll', onScroll); window.removeEventListener('resize', onScroll); if (raf) cancelAnimationFrame(raf); if (io) io.disconnect(); }; }, []); return (
); } Object.assign(window, { ShopPage, ShopBackLink, ShopHero, ShopChannels, ShopFaq });