/* global React */ /* PHASE 2 (Brand Kit V2) — Awards (left/right split) + Bento Grid (Layout B: char + package). All taglines client-confirmed per BRIEF V2 §6. Do not auto-soften. */ const { useEffect: _useEffect, useRef: _useRef, useState: _useState, useCallback: _useCallback } = React; // ===================================================================== // Character placeholder — SVG mascot stand-ins until final renders land // at assets/char-*.png. The below tries the real asset first; if // it 404s, we fall back to the inline SVG marker. // ===================================================================== function CharMark({ id, size = 220 }) { const marks = { hapimon: { // C.H.O活 — red heart, single smile bg: '#FF3F4F', fg: '#fff', svg: ( ) }, 'hapimon-pkg': { // ハピモン② holding package bg: '#FF3F4F', fg: '#fff', svg: ( C.H.O MONSTER ) }, oimon: { // A.S.E活 — pale blue droplet (温浴) bg: '#7FC9E8', fg: '#fff', svg: ( ) }, 'oimon-throne': { // オイモン王座Ver bg: '#FFE08A', fg: '#0A0A0A', svg: ( {/* throne */} {/* oimon body */} {/* crown */} {/* face */} ) }, seapaz: { // M.I.N活 — シーパーズ眠り (white/violet) bg: '#A78BFA', fg: '#fff', svg: ( {/* ears */} {/* sleeping eyes */} {/* mouth small */} {/* Z's */} Z z ) }, 'seapaz-wake': { // シーパーズ右版 起きたて bg: '#A78BFA', fg: '#fff', svg: ( {/* open eyes */} {/* sparkle */} {/* smile */} ) }, hugmon: { // H.U.G活 placeholder bg: '#F4B8C8', fg: '#fff', svg: ( ? ) }, tinmon: { // T.I.N活 placeholder bg: '#1E3A5F', fg: '#fff', svg: ( ? ) }, akari: { // 白瀬あかり 3D placeholder bg: '#fff', fg: '#0A0A0A', svg: ( {/* hair back */} {/* lab coat */} {/* face */} {/* bangs */} {/* eyes */} {/* smile */} {/* hapimon in arms */} ) } }; const m = marks[id] || marks.hugmon; return ( ); } // ============= Awards row (Brand Kit V2 — left/right split) ============= function AwardsRow() { // Royal-hall loop video — onTimeUpdate fires ~4× per second; if we're within // 100ms of the end, snap back to 0 manually so the loop seam doesn't visibly // pause/snap on browsers that stall a few frames before native re-loop. const onAwardsBgTimeUpdate = (e) => { const v = e.currentTarget; if (!v.duration) return; if (v.duration - v.currentTime < 0.1) { try { v.currentTime = 0; } catch (_) {} } }; return (

— AWARDS · 実績

オイモンが、 AMAZON を制した。

カプサイシン部門 売れ筋ランキング1位 (2026.02.27 時点)

); } // ============= Bento Grid (Brand Kit V2 — Layout B: char + package) ============= const MONSTERS = [ { id: 'cho', sku: 'C.H.O活 MONSTER', sub: 'ハピモン', tag: 'ハピモンが、腸を整え、心まで変える。', badge: { kind: 'collab', label: '白瀬あかりコラボ予告' }, char: 'hapimon', photo: 'assets/hapimon-1.png', video: 'assets/hapimon.webm', pkg: 'assets/cho-pkg-30day.png', bg: 'cho', live: true, }, { id: 'ase', sku: 'A.S.E活 MONSTER', sub: 'オイモン', tag: 'オイモンが、君の内側のめぐりを変える。', badge: { kind: 'award', label: '🏆 AMAZON NO.1' }, char: 'oimon', photo: 'assets/oimon.png', video: 'assets/oimon.webm', pkg: 'assets/ase-pkg-30day.png', bg: 'ase', live: true, }, { id: 'hug', sku: 'H.U.G活 MONSTER', sub: 'ハグモン(仮)', tag: 'ハグモンが、ひとりの夜に味方になる。', badge: { kind: 'soon', label: 'COMING SOON' }, char: 'hugmon', pkg: null, bg: 'hug', live: false, }, { id: 'min', sku: 'M.I.N活 MONSTER', sub: 'シーパーズ', tag: 'シーパーズが、君の朝を変える。', badge: { kind: 'soon', label: 'COMING SOON' }, char: 'seapaz', photo: 'assets/seapaz-center.png', video: 'assets/seapaz-center.webm', pkg: 'assets/min-pkg-30day.png', bg: 'min', live: false, }, { id: 'tin', sku: 'T.I.N活 MONSTER', sub: 'ティンモン(仮)', tag: 'ティンモンが、男の根本を整える。', badge: { kind: 'soon', label: 'COMING SOON' }, char: 'tinmon', pkg: null, bg: 'tin', live: false, }, ]; function MonsterCard({ m }) { const locked = !m.live; const href = locked ? null : `products/${m.id}-katsu-monster.html`; // Whole-card navigation (method B — JS onClick on the
). // // The CSS-only "stretched link" approach was tried first but couldn't // work here: .mm-bento__foot / .mm-bento__head already have // `position: relative; z-index: 2` (set so they sit above the locked // card's diagonal-lattice ::after), so a `.mm-bento__cta::after` // resolves against the foot — not the card — and never reaches the // top half of the tile. Touching those z-indices would risk breaking // the lock overlay; instead we navigate via JS. // // Click rules: // • Locked cards: no handler attached → nothing happens (no error). // • Live cards: handler navigates UNLESS the click started on a // real /