/* global React, ReactDOM */
const { useState, useEffect, useRef, useContext, createContext } = React;

// ────────────────────────────────────────────────────────────
// Design tokens
// ────────────────────────────────────────────────────────────
const C = {
  cream: '#F4EFE6',
  creamDeep: '#EBE3D4',
  ink: '#1A1A1A',
  ink70: 'rgba(26,26,26,0.7)',
  ink50: 'rgba(26,26,26,0.5)',
  ink30: 'rgba(26,26,26,0.3)',
  ink15: 'rgba(26,26,26,0.15)',
  teal: '#2C7A7B',
  tealDeep: '#1F5757',
  tealInk: '#16403F',
  tealMist: 'rgba(44,122,123,0.08)',
};

const F = {
  jp: '"Shippori Mincho", "Noto Serif JP", "Hiragino Mincho ProN", serif',
  brand: '"Cormorant Garamond", "EB Garamond", serif',
  mono: '"JetBrains Mono", "SFMono-Regular", ui-monospace, monospace',
};

// ────────────────────────────────────────────────────────────
// Brand-kit decorations — catalog + Tweaks context
// Each deco has a stable id so the Tweaks UI can target it.
// Defaults can be overridden per-id via localStorage.
// ────────────────────────────────────────────────────────────
// 4 cat poses available for any cat decoration. Used in the Tweaks
// panel POSE picker — user can swap a cat's pose without editing code.
const CAT_POSES = ['cat-sit', 'cat-walk', 'cat-jump', 'cat-curl'];
// All 7 brand-kit images — any slot can be assigned any image via Tweaks.
const ALL_KINDS = ['cat-sit','cat-walk','cat-jump','cat-curl','tarot-moon','tarot-cup','tarot-sun'];

// User-confirmed per-band tweak values (from Tweaks panel COPY CSS).
// These are reference values — actual application via localStorage; band-
// specific defaults to be wired up later when band system is implemented.
//
//   ── スマホ全域 (xs + sm, 320〜819px) — finalized 2026-05-13 ──
//   [data-deco-id="hero-tarot-moon"]  translate(0,    0) rot 18 scale 1.35 opacity 0.55
//   [data-deco-id="hero-cat-sit"]     translate(-8,   0) rot  0 scale 2.40 opacity 0.90
//   [data-deco-id="about-cat-walk"]   translate(-57, 31) rot  0 scale 2.40 opacity 0.55
//   [data-deco-id="menu-morning"]     translate(-27,  0) rot  0 scale 1.55 opacity 0.85
//   [data-deco-id="menu-lunch"]       translate(-41, -8) rot  0 scale 1.95 opacity 0.70
//   [data-deco-id="menu-sweets"]      translate(-40,  0) rot  0 scale 2.25 opacity 0.80
//   [data-deco-id="menu-drinks"]      translate(-36,  0) rot  0 scale 2.40 opacity 0.90
//   [data-deco-id="footer-cat-sit"]   translate(-79,  0) rot  0 scale 2.15 opacity 0.86

// Helper: convert a 375px-baseline size to a fluid clamp() string.
// Decorations shrink ~15% at narrow widths (~320), grow ~25% at wide
// widths (~480+), and stay readable across the mobile range (320–819).
const fluidSize = (base) => {
  const min = Math.round(base * 0.85);
  const vw = (base / 3.75).toFixed(1);
  const max = Math.round(base * 1.25);
  return `clamp(${min}px, ${vw}vw, ${max}px)`;
};
// Helper: anchor-axis value that scales with viewport (for top/left where
// content height also scales). Pass the 375px baseline pixel value.
const fluidAxis = (base) => {
  // grow proportionally to viewport, with min 0.85x and max 1.5x of baseline
  const v = base / 3.75; // vw at baseline 375
  const lo = Math.round(base * 0.85);
  const hi = Math.round(base * 1.5);
  if (base < 0) return `clamp(${hi}px, ${v.toFixed(1)}vw, ${lo}px)`;
  return `clamp(${lo}px, ${v.toFixed(1)}vw, ${hi}px)`;
};

const DECO_DEFAULTS = {
  'hero-tarot-moon':    { section: 'hero',    label: 'Tarot — Moon', kind: 'tarot-moon', size: fluidSize(150), ratio: 1.5, rotate:  18, opacity: 0.54, color: 'teal',  anchor: { top: -10,            right: fluidAxis(-28) } },
  'hero-cat-sit':       { section: 'hero',    label: 'Cat — Sit',    kind: 'cat-sit',    size: fluidSize(170), ratio: 1,   rotate:   0, opacity: 0.9,  color: 'teal',  anchor: { top: fluidAxis(230), right: fluidAxis(-18) } },

  'about-tarot-cup':    { section: 'about',   label: 'Tarot — Cup',  kind: 'tarot-cup',  size: fluidSize(140), ratio: 1.5, rotate: -22, opacity: 0.54, color: 'teal',  anchor: { top: 40,             left:  fluidAxis(-38) } },
  'about-cat-walk':     { section: 'about',   label: 'Cat — Walk',   kind: 'cat-walk',   size: fluidSize(110), ratio: 1,   rotate:   0, opacity: 0.55, color: 'teal',  anchor: { top: 28,             right: fluidAxis(-8)  } },

  // Menu cats are rendered INSIDE each accordion block (not at the
  // section level) so that their position follows the corresponding
  // header (モーニング / ランチ / スイーツ / ドリンク) regardless of which
  // blocks are expanded or folded.
  'menu-morning':       { section: 'menu',    label: 'Morning',      kind: 'cat-curl',   size: fluidSize(130), ratio: 1,   rotate:   0, opacity: 0.54, color: 'teal',  perBlock: 'morning', anchor: { top: 0, right: fluidAxis(-20) } },
  'menu-lunch':         { section: 'menu',    label: 'Lunch',        kind: 'cat-walk',   size: fluidSize(110), ratio: 1,   rotate:   0, opacity: 0.54, color: 'teal',  perBlock: 'lunch',   anchor: { top: 0, right: fluidAxis(-16) } },
  'menu-sweets':        { section: 'menu',    label: 'Sweets',       kind: 'cat-sit',    size: fluidSize(100), ratio: 1,   rotate:   0, opacity: 0.54, color: 'teal',  perBlock: 'sweets',  anchor: { top: 0, right: fluidAxis(-10) } },
  'menu-drinks':        { section: 'menu',    label: 'Drinks',       kind: 'cat-jump',   size: fluidSize(110), ratio: 1,   rotate:   0, opacity: 0.54, color: 'teal',  perBlock: 'drinks',  anchor: { top: 0, right: fluidAxis(-12) } },

  'gallery-tarot-moon': { section: 'gallery', label: 'Tarot — Moon', kind: 'tarot-moon', size: fluidSize(130), ratio: 1.5, rotate: -16, opacity: 0.54, color: 'teal',  anchor: { top: 30,             right: fluidAxis(-28) } },
  'gallery-cat-curl':   { section: 'gallery', label: 'Cat — Curl',   kind: 'cat-curl',   size: fluidSize(120), ratio: 1,   rotate:   0, opacity: 0.85, color: 'teal',  anchor: { bottom: fluidAxis(80), left: fluidAxis(-22) } },

  'info-cat-curl':      { section: 'info',    label: 'Cat — Curl',   kind: 'cat-curl',   size: fluidSize(140), ratio: 1,   rotate:   0, opacity: 0.68, color: 'cream', anchor: { bottom: fluidAxis(70), right: fluidAxis(-28) } },
  'info-cat-walk':      { section: 'info',    label: 'Cat — Walk',   kind: 'cat-walk',   size: fluidSize(88),  ratio: 1,   rotate:   0, opacity: 0.68, color: 'cream', anchor: { top: 40,             left: fluidAxis(-10) } },

  'footer-cat-sit':     { section: 'footer',  label: 'Cat — Sit',    kind: 'cat-sit',    size: fluidSize(72),  ratio: 1,   rotate:   0, opacity: 0.45, color: 'teal',  anchor: { top: 18,             right: fluidAxis(-6)  } },
};

// Mobile band defaults — baked-in tweaks finalized 2026-05-15.
// User tweaks (from Tweaks panel) override these if present.
const MOBILE_BAND_DEFAULTS = {
  'hero-cat-sit':       { x:  -54, y:    0, scale: 2.05, opacity: 0.90 },
  'about-cat-walk':     { x: -141, y:  -68, scale: 2.25, opacity: 0.55 },
  'menu-morning':       { x:  -84, y:  -35, scale: 1.70, opacity: 0.54 },
  'menu-lunch':         { x:  -85, y:  -29, scale: 1.75, opacity: 0.54 },
  'menu-sweets':        { x:  -80, y:  -13, scale: 1.55, opacity: 0.54 },
  'menu-drinks':        { x:  -68, y:  -20, scale: 1.65, opacity: 0.54 },
  'info-cat-curl':      { x: -112, y: -243, scale: 2.00, opacity: 0.68 },
  'info-cat-walk':      { x:  200, y:  -67, scale: 2.05, opacity: 0.68 },
  'footer-cat-sit':     { enabled: false },
};

const TWEAKS_KEY = 'cafemicio-mobile-deco-tweaks-v1';
const TweaksContext = createContext({
  tweaks: {},
  update: () => {}, resetOne: () => {}, resetAll: () => {},
});

function TweaksProvider({ children }) {
  const [tweaks, setTweaks] = useState(() => {
    try {
      const raw = JSON.parse(localStorage.getItem(TWEAKS_KEY) || '{}');
      // One-time migration: clear stale state once new band defaults
      // are baked in — users start fresh from MOBILE_BAND_DEFAULTS.
      const MIGRATION = 'cafemicio-mobile-band-defaults-v1';
      if (!localStorage.getItem(MIGRATION)) {
        localStorage.setItem(MIGRATION, '1');
        localStorage.removeItem(TWEAKS_KEY);
        return {};
      }
      return raw;
    } catch { return {}; }
  });
  useEffect(() => {
    try { localStorage.setItem(TWEAKS_KEY, JSON.stringify(tweaks)); } catch {}
  }, [tweaks]);
  const update = (id, patch) =>
    setTweaks(t => ({ ...t, [id]: { ...(t[id] || {}), ...patch } }));
  const resetOne = (id) =>
    setTweaks(t => { const n = { ...t }; delete n[id]; return n; });
  const resetAll = () => setTweaks({});
  return (
    <TweaksContext.Provider value={{ tweaks, update, resetOne, resetAll }}>
      {children}
    </TweaksContext.Provider>
  );
}

function BrandDeco({ id }) {
  const { tweaks } = useContext(TweaksContext);
  const def = DECO_DEFAULTS[id];
  if (!def) return null;
  // Merge: MOBILE_BAND_DEFAULTS (code-baked) + user tweaks (user wins)
  const bd = MOBILE_BAND_DEFAULTS[id] || {};
  const us = tweaks[id] || {};
  const t = { ...bd, ...us };
  if (t.enabled === false) return null;

  const baseColor = def.color === 'cream' ? C.cream : C.teal;
  // footer-cat-sit X is anchored to "cafemicio" brand text via JS in Footer,
  // so any saved user x tweak is intentionally ignored. Y / scale are
  // also locked to a fixed value so the cat sits consistently above the
  // brand text at all viewports.
  const tx = (id === 'footer-cat-sit') ? 0 : (t.x != null ? t.x : 0);
  const ty = (id === 'footer-cat-sit') ? -150 : (t.y != null ? t.y : 0);
  const scale = (id === 'footer-cat-sit') ? 3.0 : (t.scale != null ? t.scale : 1);
  const rot = t.rot != null ? t.rot : def.rotate;
  const opacity = t.opacity != null ? t.opacity : def.opacity;
  // Image kind can be overridden via Tweaks (any of the 7 brand assets).
  // `pose` is the legacy/back-compat field used by the IMAGE picker.
  const kind = (t.pose && ALL_KINDS.includes(t.pose)) ? t.pose : def.kind;
  const isTarot = kind && kind.startsWith('tarot-');
  const aspectRatio = isTarot ? 1.5 : 1;
  const url = `/assets/brand-kit/individual/${kind}-mask.png`;

  // Width can be a number (px) or a CSS string (e.g. clamp()).
  // Height = width * aspectRatio. Aspect derives from the *current* kind
  // (1 for cats, 1.5 for tarot) so swapping a cat slot to a tarot
  // automatically gives the right portrait-card proportion.
  const widthCss = typeof def.size === 'number' ? `${def.size}px` : def.size;
  const heightCss = aspectRatio === 1
    ? widthCss
    : (typeof def.size === 'number'
        ? `${def.size * aspectRatio}px`
        : `calc(${widthCss} * ${aspectRatio})`);

  return (
    <div aria-hidden data-deco-id={id} style={{
      position: 'absolute',
      ...def.anchor,
      width: widthCss,
      height: heightCss,
      backgroundColor: baseColor,
      WebkitMaskImage: `url("${url}")`,
              maskImage: `url("${url}")`,
      WebkitMaskRepeat: 'no-repeat',  maskRepeat: 'no-repeat',
      WebkitMaskPosition: 'center',   maskPosition: 'center',
      WebkitMaskSize: 'contain',      maskSize: 'contain',
      transform: `translate(${tx}px, ${ty}px) rotate(${rot}deg) scale(${scale})`,
      transformOrigin: 'center',
      opacity,
      pointerEvents: 'none',
      zIndex: 0,
    }} />
  );
}

// ────────────────────────────────────────────────────────────
// Tiny illustrations
// ────────────────────────────────────────────────────────────
const CatSilhouette = ({ size = 36, color = C.teal, opacity = 1, style }) => (
  <svg width={size} height={size} viewBox="0 0 64 64" style={{ opacity, ...style }} aria-hidden>
    {/* Sitting cat silhouette — simple geometric */}
    <path d="M20 14 L24 28 L40 28 L44 14 L41 22 L38 21 L36 17 L28 17 L26 21 L23 22 Z"
      fill={color} />
    <path d="M20 28 Q14 32 14 42 Q14 54 22 56 L42 56 Q50 54 50 42 Q50 32 44 28 Z"
      fill={color} />
    <path d="M50 42 Q60 40 60 32 Q56 36 50 38" fill={color} />
    <circle cx="27" cy="36" r="1.6" fill={C.cream} />
    <circle cx="37" cy="36" r="1.6" fill={C.cream} />
    <path d="M30 41 Q32 43 34 41" stroke={C.cream} strokeWidth="1" fill="none" strokeLinecap="round" />
  </svg>
);

const WalkingCat = ({ size = 60, color = C.teal, opacity = 0.16, style }) => (
  <svg width={size} height={size * 0.6} viewBox="0 0 100 60" style={{ opacity, ...style }} aria-hidden>
    <path d="M10 40 Q10 30 18 28 L20 18 L24 26 L34 26 L36 18 L40 26 Q58 26 64 32 L72 32 L74 22 Q78 24 76 32 Q82 34 84 40 L82 50 L74 50 L72 44 L62 44 L60 50 L52 50 L50 44 L28 44 L26 50 L18 50 L16 44 Q10 44 10 40 Z"
      fill={color} />
  </svg>
);

const TarotMoon = ({ size = 56, color = C.teal, opacity = 0.45, style }) => (
  <svg width={size} height={size} viewBox="0 0 64 64" style={{ opacity, ...style }} aria-hidden>
    <circle cx="32" cy="32" r="22" fill="none" stroke={color} strokeWidth="0.7" />
    <path d="M38 14 A22 22 0 1 0 38 50 A16 18 0 1 1 38 14 Z" fill={color} />
    <circle cx="14" cy="20" r="0.8" fill={color} />
    <circle cx="50" cy="12" r="0.8" fill={color} />
    <circle cx="56" cy="44" r="0.8" fill={color} />
    <path d="M32 6 L32 10 M32 54 L32 58 M6 32 L10 32 M54 32 L58 32" stroke={color} strokeWidth="0.5" />
  </svg>
);

const TarotCup = ({ size = 56, color = C.teal, opacity = 0.45, style }) => (
  <svg width={size} height={size} viewBox="0 0 64 64" style={{ opacity, ...style }} aria-hidden>
    <circle cx="32" cy="32" r="22" fill="none" stroke={color} strokeWidth="0.7" />
    <path d="M22 22 L42 22 Q42 36 32 38 Q22 36 22 22 Z" fill="none" stroke={color} strokeWidth="0.9" />
    <path d="M26 22 Q26 30 32 32 Q38 30 38 22" fill={color} opacity="0.35" />
    <path d="M32 38 L32 44 M26 44 L38 44" stroke={color} strokeWidth="0.9" strokeLinecap="round" />
    <path d="M28 16 Q32 12 36 16" stroke={color} strokeWidth="0.7" fill="none" />
    <circle cx="32" cy="13" r="1.2" fill={color} />
  </svg>
);

// Image placeholder — striped, with optional label
const Placeholder = ({ w = '100%', h = 200, label, tone = 'teal', radius = 0, style, src, alt }) => {
  const palettes = {
    teal: { bg: '#E5DDD0', stripe: 'rgba(44,122,123,0.18)', text: C.tealInk },
    warm: { bg: '#E8DCC8', stripe: 'rgba(118,76,40,0.18)', text: '#5a3a1c' },
    deep: { bg: '#D9CFBE', stripe: 'rgba(31,87,87,0.25)', text: C.tealDeep },
  };
  const p = palettes[tone] || palettes.teal;
  return (
    <div style={{
      width: w, height: h, position: 'relative', overflow: 'hidden',
      borderRadius: radius, background: p.bg, ...style,
    }}>
      {/* striped fallback */}
      <div style={{
        position: 'absolute', inset: 0,
        backgroundImage: `repeating-linear-gradient(135deg, transparent 0 14px, ${p.stripe} 14px 15px)`,
      }} />
      {src && (
        <img src={src} alt={alt || ''} loading="lazy"
          style={{
            position: 'absolute', inset: 0, width: '100%', height: '100%',
            objectFit: 'cover', display: 'block',
          }} />
      )}
      {label && (
        <div style={{
          position: 'absolute', left: 10, bottom: 8,
          fontFamily: F.mono, fontSize: 9, letterSpacing: '0.08em',
          color: p.text, textTransform: 'uppercase',
          background: 'rgba(244,239,230,0.78)', padding: '3px 6px',
        }}>{label}</div>
      )}
    </div>
  );
};

// ────────────────────────────────────────────────────────────
// Scroll-reveal helper
// ────────────────────────────────────────────────────────────
function Reveal({ children, delay = 0, y = 18, style }) {
  const ref = useRef(null);
  const [shown, setShown] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const root = el.closest('[data-scroll-root]');
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) { setShown(true); io.disconnect(); }
    }, { threshold: 0.08, root });
    io.observe(el);
    // Unconditional safety net — guarantees content is never stuck invisible
    // regardless of iframe visibility state or IO delivery timing.
    const t = setTimeout(() => { setShown(true); io.disconnect(); }, 600);
    return () => { io.disconnect(); clearTimeout(t); };
  }, []);
  return (
    <div ref={ref} style={{
      transform: shown ? 'translateY(0)' : `translateY(${y}px)`,
      opacity: shown ? 1 : 0,
      transition: `transform 800ms cubic-bezier(.2,.7,.2,1) ${delay}ms, opacity 800ms ease ${delay}ms`,
      ...style,
    }}>{children}</div>
  );
}

// ────────────────────────────────────────────────────────────
// Brand mark
// ────────────────────────────────────────────────────────────
const BrandMark = ({ size = 18, color = C.tealDeep }) => (
  <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
    <svg width={size} height={size} viewBox="0 0 24 24" aria-hidden>
      <path d="M5 4 L8 10 L16 10 L19 4 L17 8 L15.5 7 L14 5 L10 5 L8.5 7 L7 8 Z" fill={color} />
      <path d="M5 10 Q3 13 3 17 Q3 21 7 21 L17 21 Q21 21 21 17 Q21 13 19 10 Z" fill={color} />
    </svg>
    <span data-brand-text="cafemicio" style={{
      fontFamily: F.brand, fontStyle: 'italic', fontWeight: 500,
      fontSize: size * 0.95, color, letterSpacing: '0.01em',
    }}>cafemicio</span>
  </div>
);

// ────────────────────────────────────────────────────────────
// Sticky nav
// ────────────────────────────────────────────────────────────
function Nav({ onMenu, scrolled }) {
  return (
    <div style={{
      position: 'sticky', top: 0, zIndex: 40,
      background: scrolled ? 'rgba(244,239,230,0.92)' : 'transparent',
      backdropFilter: scrolled ? 'blur(8px)' : 'none',
      WebkitBackdropFilter: scrolled ? 'blur(8px)' : 'none',
      borderBottom: scrolled ? `0.5px solid ${C.ink15}` : '0.5px solid transparent',
      transition: 'all 220ms ease',
    }}>
      <div style={{
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        padding: '14px 20px',
      }}>
        <BrandMark size={17} />
        <button onClick={onMenu} aria-label="menu" style={{
          width: 44, height: 44, border: 'none', background: 'transparent',
          display: 'flex', flexDirection: 'column', alignItems: 'center',
          justifyContent: 'center', gap: 5, cursor: 'pointer', padding: 0,
        }}>
          <span style={{ width: 22, height: 1, background: C.ink }} />
          <span style={{ width: 22, height: 1, background: C.ink }} />
          <span style={{ width: 14, height: 1, background: C.ink }} />
        </button>
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────
// Section number heading
// ────────────────────────────────────────────────────────────
const SectionHead = ({ num, kanji, latin }) => (
  <div style={{ padding: '0 24px', marginBottom: 22 }}>
    <div style={{
      display: 'flex', alignItems: 'baseline', gap: 12, marginBottom: 14,
    }}>
      <span style={{
        fontFamily: F.mono, fontSize: 10, color: C.teal,
        letterSpacing: '0.18em',
      }}>{num}</span>
      <div style={{ flex: 1, height: 0, borderTop: `0.5px solid ${C.ink30}` }} />
      <span style={{
        fontFamily: F.mono, fontSize: 9, color: C.ink50,
        letterSpacing: '0.2em', textTransform: 'uppercase',
      }}>{latin}</span>
    </div>
    <h2 style={{
      fontFamily: F.jp, fontWeight: 500, fontSize: 28,
      letterSpacing: '0.05em', color: C.ink, margin: 0,
      lineHeight: 1.2,
    }}>{kanji}</h2>
  </div>
);

// ────────────────────────────────────────────────────────────
// HERO
// ────────────────────────────────────────────────────────────
function Hero() {
  return (
    <section data-screen-label="01 Hero" style={{ position: 'relative', padding: '8px 0 56px', overflow: 'hidden' }}>
      {/* Brand-kit decorations (tweakable) */}
      <BrandDeco id="hero-tarot-moon" />
      <BrandDeco id="hero-cat-sit" />
      {/* mono kicker */}
      <Reveal style={{ padding: '16px 24px 0' }}>
        <div style={{
          display: 'flex', alignItems: 'center', gap: 10,
          fontFamily: F.mono, fontSize: 10, color: C.tealDeep,
          letterSpacing: '0.22em', textTransform: 'uppercase',
        }}>
          <span style={{ width: 18, height: 0.5, background: C.tealDeep }} />
          EST. KOBE · NADA
        </div>
      </Reveal>

      {/* Big vertical kanji title */}
      <Reveal delay={120} style={{ padding: '28px 24px 0' }}>
        <h1 style={{
          fontFamily: F.jp, fontWeight: 500,
          fontSize: 'clamp(56px, 18vw, 96px)',
          margin: 0, lineHeight: 0.98, letterSpacing: '0.04em',
          color: C.ink,
        }}>
          <span style={{ display: 'block' }}>カフェ</span>
          <span style={{ display: 'block', color: C.tealDeep, marginTop: 4 }}>ミーチョ</span>
        </h1>
      </Reveal>

      <Reveal delay={220} style={{ padding: '14px 24px 0' }}>
        <div style={{
          fontFamily: F.brand, fontStyle: 'italic', fontWeight: 400,
          fontSize: 30, color: C.teal, letterSpacing: '0.01em',
          lineHeight: 1,
        }}>cafemicio</div>
      </Reveal>

      <Reveal delay={300} style={{ padding: '22px 24px 0' }}>
        <p style={{
          fontFamily: F.jp, fontSize: 14.5, lineHeight: 1.95,
          color: C.ink70, margin: 0, fontWeight: 400,
          letterSpacing: '0.03em',
        }}>
          神戸・灘の住宅街にひっそり、<br />
          猫のグッズと過ごす午後のカフェ。
        </p>
      </Reveal>

      {/* chips */}
      <Reveal delay={380} style={{ padding: '26px 24px 0' }}>
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
          <Chip label="HOURS" value="09:30—17:30" />
          <Chip label="CLOSED" value="水曜・日曜・祝日" />
        </div>
      </Reveal>

      {/* CTA */}
      <Reveal delay={460} style={{ padding: '22px 24px 0' }}>
        <a href="https://www.instagram.com/cafemicio1121" target="_blank" rel="noopener" style={{
          display: 'inline-flex', alignItems: 'center', gap: 10,
          fontFamily: F.jp, fontSize: 15, color: C.ink,
          textDecoration: 'none', borderBottom: `0.5px solid ${C.ink}`,
          paddingBottom: 6, letterSpacing: '0.04em',
        }}>
          Instagramで見る
          <span style={{ fontFamily: F.mono, fontSize: 14, color: C.teal }}>↗</span>
        </a>
      </Reveal>

      {/* Storefront photo with vertical caption */}
      <Reveal delay={120} style={{ marginTop: 44, padding: '0 24px', position: 'relative' }}>
        <div style={{ position: 'relative' }}>
          <Placeholder h={420} tone="deep"
            src="/assets/hero/hero-pc.jpg"
            alt="カフェ ミーチョ 店頭：窓ガラス越しに金色の CAFE MICIO レター" />
        </div>
      </Reveal>

      {/* scattered cat */}
      <WalkingCat size={72} style={{ position: 'absolute', left: 12, bottom: -18, opacity: 0.14 }} />
    </section>
  );
}

const Chip = ({ label, value }) => (
  <div style={{
    display: 'inline-flex', flexDirection: 'column', gap: 2,
    border: `0.5px solid ${C.ink30}`, padding: '8px 14px',
    background: 'rgba(255,255,255,0.4)',
  }}>
    <span style={{
      fontFamily: F.mono, fontSize: 9, color: C.ink50,
      letterSpacing: '0.18em',
    }}>{label}</span>
    <span style={{
      fontFamily: F.jp, fontSize: 13, color: C.ink, letterSpacing: '0.04em',
    }}>{value}</span>
  </div>
);

// ────────────────────────────────────────────────────────────
// ABOUT
// ────────────────────────────────────────────────────────────
function About() {
  const tags = ['街のちいさなカフェ', '自家製スイーツ', '猫モチーフ', '落ち着いた時間', 'スパイスカレー'];
  const photos = [
    { label: 'fig.01 · interior',  tone: 'warm', src: '/assets/photos/interior-window-01.jpg', alt: '窓辺の席' },
    { label: 'fig.02 · counter',   tone: 'teal', src: '/assets/photos/interior-counter-01.jpg', alt: 'カウンター' },
    { label: 'fig.03 · the shelf', tone: 'deep', src: '/assets/photos/interior-shelf.jpg',     alt: '本棚' },
  ];
  return (
    <section data-screen-label="02 About" style={{ position: 'relative', padding: '64px 0 56px', background: C.cream, overflow: 'hidden' }}>
      <BrandDeco id="about-tarot-cup" />
      <BrandDeco id="about-cat-walk" />
      <Reveal><SectionHead num="01 / 05" kanji="店について" latin="About" /></Reveal>

      <Reveal delay={80} style={{ padding: '0 24px' }}>
        <p style={{
          fontFamily: F.jp, fontSize: 14.5, lineHeight: 2,
          color: C.ink, margin: '0 0 18px', letterSpacing: '0.04em',
          textIndent: '1em',
        }}>
          神戸・灘の住宅街、坂の途中にある小さな喫茶店。白い壁と、店内に広がる淡いティール色のタイル。丁寧に淹れるコーヒーと、手づくりのケーキ。街の音が遠くなる、ささやかな午後のために。
        </p>
        <p style={{
          fontFamily: F.jp, fontSize: 14.5, lineHeight: 2,
          color: C.ink, margin: 0, letterSpacing: '0.04em',
          textIndent: '1em',
        }}>
          「ミーチョ (micio)」はイタリア語で猫の愛称。肩の力を抜いて、本を開いて、ひとりでもふたりでも、ゆっくり過ごしてもらえたら。
        </p>
      </Reveal>

      {/* keyword tags */}
      <Reveal delay={160} style={{ padding: '24px 24px 0' }}>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
          {tags.map(t => (
            <span key={t} style={{
              fontFamily: F.jp, fontSize: 12, color: C.tealDeep,
              padding: '6px 12px', background: C.tealMist,
              letterSpacing: '0.05em',
            }}>{t}</span>
          ))}
        </div>
      </Reveal>

      {/* horizontal carousel */}
      <Reveal delay={240} style={{ marginTop: 30 }}>
        <div style={{
          display: 'flex', gap: 14, overflowX: 'auto', overflowY: 'hidden',
          padding: '0 24px 16px', scrollSnapType: 'x mandatory',
          WebkitOverflowScrolling: 'touch',
        }}>
          {photos.map((p, i) => (
            <div key={i} style={{
              flex: '0 0 220px', scrollSnapAlign: 'start', position: 'relative',
            }}>
              <Placeholder w={220} h={280} tone={p.tone} src={p.src} alt={p.alt} />
            </div>
          ))}
        </div>
      </Reveal>
    </section>
  );
}

// ────────────────────────────────────────────────────────────
// MENU
// ────────────────────────────────────────────────────────────
const menuData = [
  {
    slug: 'morning',
    title: 'モーニング', latin: 'Morning', hours: '09:30 — 11:30',
    note: 'ドリンク + ミニサラダ付',
    items: [
      { name: 'トーストセット',             en: 'Toast set',                price: '¥500' },
      { name: '玉子ホットサンドセット',     en: 'Egg hot sandwich set',     price: '¥600' },
      { name: '野菜サラダホットサンドセット', en: 'Veggie hot sandwich set', price: '¥600' },
      { name: '玉子サラダトーストセット',   en: 'Egg salad toast set',      price: '¥600' },
      { name: '野菜サラダトーストセット',   en: 'Veggie salad toast set',   price: '¥600' },
      { name: 'ハムチーズトーストセット',   en: 'Ham & cheese toast set',   price: '¥650' },
    ],
  },
  {
    slug: 'lunch',
    title: 'ランチ', latin: 'Lunch', hours: '11:30 — 14:30',
    note: 'ミニサラダ付 / ドリンク追加 +¥350',
    items: [
      { name: 'チキンカレー',   en: 'Chicken curry', price: '¥880', desc: 'スパイス、ココナツミルクと生クリーム仕上げ' },
      { name: 'キーマカレー',   en: 'Keema curry',   price: '¥880', desc: '玉ねぎ・人参・ナス・トマト + 目玉焼き' },
      { name: 'あいがけカレー', en: 'Combo curry',   price: '¥980', desc: 'チキンとキーマの両方' },
      { name: '焼きキーマカレー', en: 'Baked keema curry', price: '¥980', desc: 'チーズと半熟玉子' },
    ],
  },
  {
    slug: 'sweets',
    title: 'スイーツ', latin: 'Sweets', hours: '営業中いつでも',
    note: 'ケーキセット ¥850（ドリンク付）',
    items: [
      { name: 'チーズケーキ',   en: 'Cheesecake',  price: '¥500', desc: 'レモンシロップ漬け' },
      { name: 'ガトーショコラ', en: 'Gateau chocolat', price: '¥500', desc: '濃厚で食べやすい' },
      { name: 'シフォンケーキ', en: 'Chiffon cake', price: '¥500', desc: '自家製ジャム添え' },
      { subhead: 'Iced Sweets', jp: '冷たいスイーツ' },
      { name: 'じぶんいろクリームソーダ', en: 'Custom cream soda', price: '¥550', desc: '赤・青・黄・緑からお好きな 2 色' },
      { name: 'アイスサンデー', en: 'Ice sundae', price: '¥450', desc: 'チョコ／いちご／キャラメル' },
      { name: 'スムージーパフェ', en: 'Smoothie parfait', price: '¥660', desc: '5 種のフルーツ・豆乳・蜂蜜・ヨーグルト' },
    ],
  },
  {
    slug: 'drinks',
    title: 'ドリンク', latin: 'Drinks', hours: 'HOT / ICE',
    note: 'お選びいただけます',
    items: [
      { name: 'ブレンド',           en: 'Blend coffee',        opt: 'HOT / ICE', price: '¥450' },
      { name: 'カフェオレ',         en: 'Café au lait',        opt: 'HOT / ICE', price: '¥500' },
      { name: '紅茶',               en: 'Black tea',           opt: 'HOT / ICE', price: '¥450' },
      { name: 'ホットジンジャーティー', en: 'Hot ginger tea',  opt: 'HOT',        price: '¥500' },
      { name: 'ジンジャーエール',   en: 'Ginger ale',          opt: 'ICE',        price: '¥500' },
    ],
  },
];

function Menu() {
  const [open, setOpen] = useState(0);
  return (
    <section data-screen-label="03 Menu" style={{ position: 'relative', padding: '64px 0 56px', background: C.creamDeep, overflow: 'hidden' }}>
      <Reveal><SectionHead num="02 / 05" kanji="お品書き" latin="Menu" /></Reveal>

      <div style={{ padding: '4px 24px 0' }}>
        {menuData.map((sec, i) => {
          const isOpen = open === i;
          return (
            <Reveal key={sec.title} delay={i * 80}>
              <div style={{ borderTop: `0.5px solid ${C.ink30}`, position: 'relative' }}>
                {/* per-block cat — anchored to this block's header, so it
                    moves with the title (モーニング/ランチ/etc.) but does
                    NOT shift when other blocks expand/collapse. */}
                <BrandDeco id={`menu-${sec.slug}`} />
                <button onClick={() => setOpen(isOpen ? -1 : i)} style={{
                  width: '100%', textAlign: 'left', background: 'transparent',
                  border: 'none', padding: '20px 0', minHeight: 48,
                  display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                  cursor: 'pointer',
                }}>
                  <div>
                    <div style={{
                      fontFamily: F.mono, fontSize: 9, color: C.ink50,
                      letterSpacing: '0.2em', marginBottom: 6,
                    }}>0{i + 1} · {sec.hours}</div>
                    <div style={{ display: 'flex', alignItems: 'baseline', gap: 10 }}>
                      <span style={{
                        fontFamily: F.jp, fontSize: 22, color: C.ink,
                        letterSpacing: '0.04em',
                      }}>{sec.title}</span>
                      <span style={{
                        fontFamily: F.brand, fontStyle: 'italic',
                        fontSize: 17, color: C.teal,
                      }}>— {sec.latin}</span>
                    </div>
                  </div>
                  <span style={{
                    width: 28, height: 28, borderRadius: '50%',
                    border: `0.5px solid ${C.ink30}`, display: 'flex',
                    alignItems: 'center', justifyContent: 'center',
                    fontFamily: F.mono, fontSize: 14, color: C.tealDeep,
                    transition: 'transform 280ms ease',
                    transform: isOpen ? 'rotate(45deg)' : 'rotate(0)',
                  }}>+</span>
                </button>
                <div style={{
                  maxHeight: isOpen ? 1400 : 0, overflow: 'hidden',
                  transition: 'max-height 520ms ease',
                }}>
                  <div style={{ paddingBottom: 24 }}>
                    {sec.note && (
                      <div style={{
                        fontFamily: F.jp, fontSize: 11.5, color: C.ink50,
                        letterSpacing: '0.04em', padding: '0 0 14px',
                      }}>※ {sec.note}</div>
                    )}
                    {sec.items.map((it, j) => {
                      // Sub-heading row (e.g. "Iced Sweets" within Sweets)
                      if (it.subhead) {
                        return (
                          <div key={j} style={{
                            display: 'flex', alignItems: 'baseline', gap: 10,
                            padding: '18px 0 8px', marginTop: 4,
                            borderTop: `0.5px dashed ${C.ink15}`,
                          }}>
                            <span style={{
                              fontFamily: F.brand, fontStyle: 'italic',
                              fontSize: 14, color: C.teal, letterSpacing: '0.02em',
                            }}>{it.subhead}</span>
                            {it.jp && (
                              <span style={{
                                fontFamily: F.jp, fontSize: 11, color: C.ink50,
                                letterSpacing: '0.06em',
                              }}>{it.jp}</span>
                            )}
                          </div>
                        );
                      }
                      return (
                        <div key={j} style={{
                          padding: '10px 0',
                          borderBottom: j === sec.items.length - 1 ? 'none' : `0.5px dotted ${C.ink15}`,
                        }}>
                          <div style={{
                            display: 'flex', alignItems: 'baseline', justifyContent: 'space-between',
                            gap: 12,
                          }}>
                            <div style={{ flex: 1, minWidth: 0 }}>
                              <div style={{
                                fontFamily: F.jp, fontSize: 14, color: C.ink,
                                letterSpacing: '0.03em',
                              }}>{it.name}</div>
                              <div style={{
                                fontFamily: F.brand, fontStyle: 'italic',
                                fontSize: 12, color: C.ink50, marginTop: 1,
                              }}>{it.en}</div>
                            </div>
                            <div style={{
                              display: 'flex', flexDirection: 'column', alignItems: 'flex-end',
                              gap: 2, whiteSpace: 'nowrap',
                            }}>
                              {it.opt && (
                                <span style={{
                                  fontFamily: F.mono, fontSize: 9, color: C.ink50,
                                  letterSpacing: '0.18em',
                                }}>{it.opt}</span>
                              )}
                              <span style={{
                                fontFamily: F.mono, fontSize: 12, color: C.tealDeep,
                                letterSpacing: '0.04em',
                              }}>{it.price}</span>
                            </div>
                          </div>
                          {it.desc && (
                            <div style={{
                              fontFamily: F.jp, fontSize: 11, color: C.ink50,
                              letterSpacing: '0.04em', marginTop: 4,
                            }}>{it.desc}</div>
                          )}
                        </div>
                      );
                    })}
                  </div>
                </div>
              </div>
            </Reveal>
          );
        })}
        <div style={{ borderTop: `0.5px solid ${C.ink30}` }} />
      </div>
    </section>
  );
}

// ────────────────────────────────────────────────────────────
// FORTUNE — タロット / 四柱推命
// ────────────────────────────────────────────────────────────
function Fortune() {
  const services = [
    {
      title: 'タロット',
      latin: 'Tarot',
      prices: [{ amount: '¥1,500', unit: '/ 1 回' }],
      paragraphs: [
        '大アルカナ 22 枚・小アルカナ 56 枚の計 78 枚から構成されるカードで、近い未来を占います。',
        '良い結果のときは、その幸運をさらに呼び寄せるアドバイスを。望まない結果のときも、いまの行動を少し変えることで未来を少しずつ良い方向に導けるよう、寄り添ったアドバイスをお伝えします。',
      ],
      meta: {
        label: '受付',
        body: 'カフェ営業中、店主の手が空き次第いつでも占います。お気軽にお声がけください。',
      },
    },
    {
      title: '四柱推命',
      latin: 'Four Pillars',
      prices: [
        { amount: '¥3,000', unit: '/ 30 分' },
        { amount: '¥5,000', unit: '/ 1 時間' },
      ],
      paragraphs: [
        '生年月日と生まれた時間から、生涯の運勢を観ます。性格・仕事運・家庭運だけでなく、仕事仲間との相性、ご家族との関係性、現在の職業の向き不向き、転職時期や婚期など、さまざまな悩みに対応できる占いです。',
        '生年月日と生時をお伺いしての鑑定となるため、ご予約制とさせていただきます。ご希望があれば、ご自身以外の方の鑑定もお受けします。',
      ],
      reservation: [
        '上の LINE ボタンから友だち追加してください',
        'LINE にお名前（ニックネーム可）と「四柱推命占い希望」とお送りください',
        '店主からの返信で予約日時が決まります',
      ],
      lineCta: true,
    },
  ];
  return (
    <section data-screen-label="03 Fortune" style={{ position: 'relative', padding: '64px 0 56px', background: C.cream, overflow: 'hidden' }}>
      <Reveal><SectionHead num="03 / 05" kanji="占い" latin="Tarot & Four Pillars" /></Reveal>

      <div style={{ padding: '4px 24px 0', display: 'flex', flexDirection: 'column', gap: 24 }}>
        {services.map((s, i) => (
          <Reveal key={s.title} delay={i * 100}>
            <article style={{
              position: 'relative',
              padding: '26px 22px',
              background: 'rgba(255,255,255,0.5)',
              border: `0.5px solid ${C.ink15}`,
              borderRadius: 2,
            }}>
              <header style={{
                paddingBottom: 14, marginBottom: 14,
                borderBottom: `0.5px dotted ${C.ink15}`,
              }}>
                <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 4 }}>
                  <span aria-hidden="true" style={{
                    fontFamily: F.mono, fontSize: 18, color: C.teal, lineHeight: 1,
                  }}>☆</span>
                  <span style={{
                    fontFamily: F.jp, fontSize: 22, color: C.ink,
                    letterSpacing: '0.04em',
                  }}>{s.title}</span>
                  <span style={{
                    fontFamily: F.brand, fontStyle: 'italic',
                    fontSize: 15, color: C.teal,
                  }}>— {s.latin}</span>
                </div>
                <div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'baseline', gap: 6, marginTop: 8 }}>
                  {s.prices.map((p, j) => (
                    <React.Fragment key={j}>
                      {j > 0 && <span style={{ color: C.ink30, margin: '0 4px' }}>·</span>}
                      <span style={{
                        fontFamily: F.brand, fontStyle: 'italic',
                        fontSize: 22, color: C.tealDeep,
                      }}>{p.amount}</span>
                      <span style={{
                        fontFamily: F.mono, fontSize: 10,
                        letterSpacing: '0.14em', color: C.ink50,
                      }}>{p.unit}</span>
                    </React.Fragment>
                  ))}
                </div>
              </header>

              {s.paragraphs.map((p, j) => (
                <p key={j} style={{
                  fontFamily: F.jp, fontSize: 13, color: C.ink,
                  lineHeight: 1.85, letterSpacing: '0.02em',
                  margin: j === 0 ? '0 0 12px' : '0 0 10px',
                }}>{p}</p>
              ))}

              {s.meta && (
                <div style={{
                  marginTop: 14, paddingTop: 14,
                  borderTop: `0.5px dotted ${C.ink15}`,
                  fontFamily: F.jp, fontSize: 12, color: C.ink50,
                  lineHeight: 1.85,
                }}>
                  <div style={{
                    fontFamily: F.mono, fontSize: 9.5,
                    color: C.teal, letterSpacing: '0.22em',
                    textTransform: 'uppercase', marginBottom: 4,
                  }}>{s.meta.label}</div>
                  {s.meta.body}
                </div>
              )}

              {s.reservation && (
                <div style={{
                  marginTop: 14, paddingTop: 14,
                  borderTop: `0.5px dotted ${C.ink15}`,
                }}>
                  <div style={{
                    fontFamily: F.mono, fontSize: 9.5,
                    color: C.teal, letterSpacing: '0.22em',
                    textTransform: 'uppercase', marginBottom: 8,
                  }}>ご予約</div>
                  {s.lineCta && (
                    <a href="https://line.me/ti/p/pAHvCHJNjD" target="_blank" rel="noopener"
                      aria-label="LINE で友だち追加して予約・問い合わせ"
                      style={{
                        display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 10,
                        marginBottom: 14, padding: '14px 18px',
                        background: '#06C755', color: '#fff',
                        textDecoration: 'none',
                        fontFamily: F.jp, fontSize: 15, letterSpacing: '0.04em',
                        boxShadow: '0 2px 0 rgba(5,176,74,0.25)',
                        minHeight: 48,
                      }}>
                      <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
                        <path d="M12 2C6.48 2 2 5.85 2 10.59c0 4.25 3.58 7.81 8.42 8.49.33.07.78.21.89.49.1.25.07.65.03.91l-.14.86c-.04.25-.2.99.86.54 1.07-.45 5.74-3.38 7.83-5.79C21.4 14.32 22 12.55 22 10.59 22 5.85 17.52 2 12 2zM7.83 13.21H5.79c-.3 0-.54-.24-.54-.54V8.59c0-.3.24-.54.54-.54s.54.24.54.54v3.54h1.5c.3 0 .54.24.54.54s-.24.54-.54.54zm2.1-.54c0 .3-.24.54-.54.54s-.54-.24-.54-.54V8.59c0-.3.24-.54.54-.54s.54.24.54.54v4.08zm5.1 0c0 .23-.15.44-.37.51-.06.02-.12.03-.17.03-.17 0-.33-.08-.43-.22l-2.1-2.86v2.54c0 .3-.24.54-.54.54s-.54-.24-.54-.54V8.59c0-.23.15-.44.37-.51.05-.02.11-.03.17-.03.17 0 .33.08.43.22l2.1 2.86V8.59c0-.3.24-.54.54-.54s.54.24.54.54v4.08zm3.42-2.58c.3 0 .54.24.54.54s-.24.54-.54.54h-1.5v.96h1.5c.3 0 .54.24.54.54s-.24.54-.54.54h-2.04c-.3 0-.54-.24-.54-.54V8.59c0-.3.24-.54.54-.54h2.04c.3 0 .54.24.54.54s-.24.54-.54.54h-1.5v.96h1.5z"/>
                      </svg>
                      <span>LINE で予約・お問い合わせ</span>
                      <span style={{ fontFamily: F.mono, fontSize: 14, color: 'rgba(255,255,255,0.75)' }}>↗</span>
                    </a>
                  )}
                  <ol style={{ listStyle: 'none', padding: 0, margin: 0, counterReset: 'step' }}>
                    {s.reservation.map((step, j) => (
                      <li key={j} style={{
                        position: 'relative', paddingLeft: 28,
                        marginBottom: 8, counterIncrement: 'step',
                        fontFamily: F.jp, fontSize: 12, color: C.ink,
                        lineHeight: 1.7, letterSpacing: '0.02em',
                      }}>
                        <span style={{
                          position: 'absolute', left: 0, top: 1,
                          width: 18, height: 18, borderRadius: '50%',
                          border: `0.5px solid ${C.ink30}`,
                          display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                          fontFamily: F.mono, fontSize: 9, color: C.teal,
                        }}>{j + 1}</span>
                        {step}
                      </li>
                    ))}
                  </ol>
                </div>
              )}
            </article>
          </Reveal>
        ))}
      </div>

      <Reveal>
        <div style={{
          margin: '32px 24px 0', padding: '20px',
          borderTop: `0.5px solid ${C.ink15}`,
          borderBottom: `0.5px solid ${C.ink15}`,
          display: 'flex', flexDirection: 'column',
          alignItems: 'center', gap: 8, textAlign: 'center',
        }}>
          <div style={{
            fontFamily: F.mono, fontSize: 10, color: C.teal,
            letterSpacing: '0.24em', textTransform: 'uppercase',
          }}>占い日 / Open</div>
          <div style={{
            display: 'flex', alignItems: 'baseline',
            gap: 14, flexWrap: 'wrap', justifyContent: 'center',
          }}>
            <strong style={{
              fontFamily: F.jp, fontSize: 18, color: C.ink,
              letterSpacing: '0.06em', fontWeight: 600,
            }}>水・日</strong>
            <span style={{
              fontFamily: F.brand, fontStyle: 'italic',
              fontSize: 17, color: C.tealDeep,
            }}>10:00 — 18:00</span>
          </div>
          <small style={{
            fontFamily: F.jp, fontSize: 11, color: C.ink50,
            letterSpacing: '0.02em',
          }}>※ 日程やお時間が合わない場合はお尋ねください</small>
        </div>
      </Reveal>
    </section>
  );
}

// ────────────────────────────────────────────────────────────
// GALLERY — masonry
// ────────────────────────────────────────────────────────────
function Gallery() {
  const items = [
    { h: 220, tone: 'teal', src: '/assets/photos/interior-bar.jpg',               alt: 'カウンター席（バー）' },
    { h: 160, tone: 'warm', src: '/assets/photos/interior-counter-02.jpg',        alt: 'カウンター' },
    { h: 240, tone: 'teal', src: '/assets/photos/summer-smoothie-parfait.webp',   alt: 'スムージーパフェ' },
    { h: 200, tone: 'warm', src: '/assets/photos/summer-cream-soda.webp',         alt: 'じぶんいろクリームソーダ' },
    { h: 160, tone: 'deep', src: '/assets/photos/interior-table-02.jpg',          alt: 'テーブル' },
    { h: 180, tone: 'teal', src: '/assets/photos/sweets-french-toast.jpg',        alt: 'フレンチトースト' },
    { h: 220, tone: 'warm', src: '/assets/photos/summer-ice-sundae.webp',         alt: 'アイスサンデー' },
    { h: 240, tone: 'deep', src: '/assets/photos/fortune-tarot.jpg',              alt: 'タロット占いのカード展開' },
    { h: 200, tone: 'teal', src: '/assets/photos/sweets-cheesecake-plate.jpg',    alt: 'ベイクドチーズケーキ' },
    { h: 150, tone: 'warm', src: '/assets/photos/lunch-cheese-rice.jpg',          alt: 'チーズライス' },
  ];
  const colA = items.filter((_, i) => i % 2 === 0);
  const colB = items.filter((_, i) => i % 2 === 1);
  return (
    <section data-screen-label="04 Gallery" style={{ position: 'relative', padding: '64px 0 56px', background: C.cream, overflow: 'hidden' }}>
      <BrandDeco id="gallery-tarot-moon" />
      <BrandDeco id="gallery-cat-curl" />
      <Reveal><SectionHead num="04 / 05" kanji="店内のようす" latin="Gallery" /></Reveal>

      <div style={{
        display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10,
        padding: '0 24px',
      }}>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          {colA.map((it, i) => (
            <Reveal key={i} delay={i * 60}>
              <Placeholder h={it.h} tone={it.tone} src={it.src} alt={it.alt} />
            </Reveal>
          ))}
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10, paddingTop: 30 }}>
          {colB.map((it, i) => (
            <Reveal key={i} delay={i * 60 + 30}>
              <Placeholder h={it.h} tone={it.tone} src={it.src} alt={it.alt} />
            </Reveal>
          ))}
        </div>
      </div>
    </section>
  );
}

// ────────────────────────────────────────────────────────────
// INFO (dark)
// ────────────────────────────────────────────────────────────
function Info() {
  return (
    <section data-screen-label="05 Info" style={{ position: 'relative', padding: '64px 0 56px', background: C.tealInk, color: C.cream, overflow: 'hidden' }}>
      <BrandDeco id="info-cat-curl" />
      <BrandDeco id="info-cat-walk" />

      <Reveal style={{ padding: '0 24px', marginBottom: 22 }}>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 12, marginBottom: 14 }}>
          <span style={{
            fontFamily: F.mono, fontSize: 10, color: '#7FBFBA',
            letterSpacing: '0.18em',
          }}>05 / 05</span>
          <div style={{ flex: 1, height: 0, borderTop: `0.5px solid rgba(244,239,230,0.3)` }} />
          <span style={{
            fontFamily: F.mono, fontSize: 9, color: 'rgba(244,239,230,0.6)',
            letterSpacing: '0.2em',
          }}>INFO</span>
        </div>
        <h2 style={{
          fontFamily: F.jp, fontWeight: 500, fontSize: 28,
          letterSpacing: '0.05em', color: C.cream, margin: 0,
          lineHeight: 1.2,
        }}>場所と営業時間</h2>
      </Reveal>

      <Reveal delay={80} style={{ padding: '0 24px' }}>
        <InfoRow label="ADDRESS" jp="住所">
          〒657-0823<br />
          兵庫県神戸市灘区天城通4丁目1-1<br />
          ディアコート天城マンション101
        </InfoRow>
        <InfoRow label="HOURS" jp="営業時間">
          09:30 — 17:30<br />
          <span style={{ color: 'rgba(244,239,230,0.65)' }}>(L.O. 17:00)</span>
        </InfoRow>
        <InfoRow label="CLOSED" jp="定休日">水曜日・日曜日・祝日</InfoRow>
        <InfoRow label="TEL" jp="電話">
          <a href="tel:07050430126" style={{ color: C.cream, textDecoration: 'none', borderBottom: `0.5px solid rgba(244,239,230,0.5)`, paddingBottom: 2 }}>
            070-5043-0126
          </a>
        </InfoRow>
        <InfoRow label="INSTAGRAM" jp="SNS">
          <a href="https://www.instagram.com/cafemicio1121" target="_blank" rel="noopener" style={{ color: C.cream, textDecoration: 'none', borderBottom: `0.5px solid rgba(244,239,230,0.5)`, paddingBottom: 2 }}>
            @cafemicio1121
          </a>
        </InfoRow>
        <InfoRow label="LINE" jp="予約・問い合わせ" last>
          <a href="https://line.me/ti/p/pAHvCHJNjD" target="_blank" rel="noopener" style={{ color: C.cream, textDecoration: 'none', borderBottom: `0.5px solid rgba(244,239,230,0.5)`, paddingBottom: 2 }}>
            友だち追加
          </a>
        </InfoRow>
      </Reveal>

      {/* Map card */}
      <Reveal delay={120} style={{ marginTop: 24, padding: '0 24px' }}>
        <div style={{
          background: 'rgba(244,239,230,0.06)', border: '0.5px solid rgba(244,239,230,0.18)',
          padding: 14,
        }}>
          <div style={{
            fontFamily: F.mono, fontSize: 9, color: 'rgba(244,239,230,0.6)',
            letterSpacing: '0.2em', marginBottom: 10,
          }}>LOCATION MAP</div>
          {/* Google Maps embed */}
          <div style={{
            position: 'relative', height: 200, overflow: 'hidden',
            background: 'rgba(244,239,230,0.04)',
            border: '0.5px solid rgba(244,239,230,0.12)',
          }}>
            <iframe
              src="https://www.google.com/maps?q=%E5%85%B5%E5%BA%AB%E7%9C%8C%E7%A5%9E%E6%88%B8%E5%B8%82%E7%81%98%E5%8C%BA%E5%A4%A9%E5%9F%8E%E9%80%9A4%E4%B8%81%E7%9B%AE1-1&output=embed"
              loading="lazy"
              referrerPolicy="no-referrer-when-downgrade"
              title="cafemicio の地図"
              style={{
                width: '100%', height: '100%', border: 0, display: 'block',
                filter: 'grayscale(0.15) contrast(0.95) brightness(0.95)',
              }}
            />
          </div>
          <a href="https://www.google.com/maps/search/?api=1&query=%E5%85%B5%E5%BA%AB%E7%9C%8C%E7%A5%9E%E6%88%B8%E5%B8%82%E7%81%98%E5%8C%BA%E5%A4%A9%E5%9F%8E%E9%80%9A4%E4%B8%81%E7%9B%AE1-1" target="_blank" rel="noopener" style={{
            display: 'flex', alignItems: 'center', justifyContent: 'space-between',
            marginTop: 14, padding: '12px 14px', minHeight: 44,
            background: 'rgba(244,239,230,0.08)',
            border: '0.5px solid rgba(244,239,230,0.22)',
            color: C.cream, textDecoration: 'none',
            fontFamily: F.jp, fontSize: 14, letterSpacing: '0.04em',
          }}>
            <span>Google Mapsで開く</span>
            <span style={{ fontFamily: F.mono, color: '#7FBFBA' }}>↗</span>
          </a>
        </div>
      </Reveal>

      {/* LINE CTA — moved below the map card per request 2026-05-27 */}
      <Reveal delay={200} style={{ marginTop: 16, padding: '0 24px' }}>
        <a href="https://line.me/ti/p/pAHvCHJNjD" target="_blank" rel="noopener"
          aria-label="LINE で友だち追加"
          style={{
            display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 10,
            padding: '14px 18px',
            background: '#06C755', color: '#fff',
            textDecoration: 'none',
            fontFamily: F.jp, fontSize: 15, letterSpacing: '0.04em',
            boxShadow: '0 2px 0 rgba(5,176,74,0.35)',
            minHeight: 48,
          }}>
          <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
            <path d="M12 2C6.48 2 2 5.85 2 10.59c0 4.25 3.58 7.81 8.42 8.49.33.07.78.21.89.49.1.25.07.65.03.91l-.14.86c-.04.25-.2.99.86.54 1.07-.45 5.74-3.38 7.83-5.79C21.4 14.32 22 12.55 22 10.59 22 5.85 17.52 2 12 2zM7.83 13.21H5.79c-.3 0-.54-.24-.54-.54V8.59c0-.3.24-.54.54-.54s.54.24.54.54v3.54h1.5c.3 0 .54.24.54.54s-.24.54-.54.54zm2.1-.54c0 .3-.24.54-.54.54s-.54-.24-.54-.54V8.59c0-.3.24-.54.54-.54s.54.24.54.54v4.08zm5.1 0c0 .23-.15.44-.37.51-.06.02-.12.03-.17.03-.17 0-.33-.08-.43-.22l-2.1-2.86v2.54c0 .3-.24.54-.54.54s-.54-.24-.54-.54V8.59c0-.23.15-.44.37-.51.05-.02.11-.03.17-.03.17 0 .33.08.43.22l2.1 2.86V8.59c0-.3.24-.54.54-.54s.54.24.54.54v4.08zm3.42-2.58c.3 0 .54.24.54.54s-.24.54-.54.54h-1.5v.96h1.5c.3 0 .54.24.54.54s-.24.54-.54.54h-2.04c-.3 0-.54-.24-.54-.54V8.59c0-.3.24-.54.54-.54h2.04c.3 0 .54.24.54.54s-.24.54-.54.54h-1.5v.96h1.5z"/>
          </svg>
          <span>LINE で友だち追加</span>
          <span style={{ fontFamily: F.mono, fontSize: 14, color: 'rgba(255,255,255,0.75)' }}>↗</span>
        </a>
      </Reveal>
    </section>
  );
}

const InfoRow = ({ label, jp, children, last }) => (
  <div style={{
    display: 'grid', gridTemplateColumns: '88px 1fr', gap: 16,
    padding: '16px 0', borderBottom: last ? 'none' : '0.5px dotted rgba(244,239,230,0.22)',
    minHeight: 44,
  }}>
    <div>
      <div style={{
        fontFamily: F.mono, fontSize: 9, color: '#7FBFBA',
        letterSpacing: '0.2em', marginBottom: 4,
      }}>{label}</div>
      <div style={{
        fontFamily: F.jp, fontSize: 11, color: 'rgba(244,239,230,0.55)',
        letterSpacing: '0.06em',
      }}>{jp}</div>
    </div>
    <div style={{
      fontFamily: F.jp, fontSize: 14, color: C.cream,
      lineHeight: 1.75, letterSpacing: '0.03em',
    }}>{children}</div>
  </div>
);

// ────────────────────────────────────────────────────────────
// Footer
// ────────────────────────────────────────────────────────────
function Footer() {
  return (
    <FooterInner />);
}
function FooterInner() {
  // Anchor footer-cat-sit so its visual LEFT sits ~8px to the right
  // of the "cafemicio" brand text in BrandMark. Recomputed on resize,
  // font-load, and whenever the brand text's bounding box changes
  // (ResizeObserver — catches layout shifts from font swapping).
  useEffect(() => {
    const FOOTER_CAT_GAP = 10;
    function adjust() {
      const footer = document.querySelector('footer[data-mobile-footer]');
      if (!footer) return;
      const cat = footer.querySelector('[data-deco-id="footer-cat-sit"]');
      const brand = footer.querySelector('[data-brand-text="cafemicio"]');
      if (!cat || !brand) return;
      const r = brand.getBoundingClientRect();
      const fLeft = footer.getBoundingClientRect().left;
      cat.style.right = 'auto';
      cat.style.left = `${(r.right - fLeft) + FOOTER_CAT_GAP}px`;
      cat.style.transformOrigin = 'top left';
    }
    adjust();
    window.addEventListener('resize', adjust, { passive: true });
    if (document.fonts && document.fonts.ready) document.fonts.ready.then(adjust).catch(()=>{});
    // ResizeObserver on the brand text — re-adjusts when its dimensions
    // change (e.g., when the Cormorant Garamond italic font finishes loading).
    let ro;
    const footer = document.querySelector('footer[data-mobile-footer]');
    const brand = footer ? footer.querySelector('[data-brand-text="cafemicio"]') : null;
    if (brand && typeof ResizeObserver !== 'undefined') {
      ro = new ResizeObserver(adjust);
      ro.observe(brand);
    }
    const t1 = setTimeout(adjust, 500);
    const t2 = setTimeout(adjust, 1500);
    return () => {
      window.removeEventListener('resize', adjust);
      if (ro) ro.disconnect();
      clearTimeout(t1); clearTimeout(t2);
    };
  }, []);
  return (
    <footer data-mobile-footer style={{
      position: 'relative', overflow: 'hidden',
      padding: '36px 24px 96px', background: C.cream,
      borderTop: `0.5px solid ${C.ink15}`, textAlign: 'center',
    }}>
      <BrandDeco id="footer-cat-sit" />
      <div style={{ display: 'flex', justifyContent: 'center', marginBottom: 18 }}>
        <BrandMark size={20} />
      </div>
      <div style={{
        fontFamily: F.jp, fontSize: 11, color: C.ink50,
        letterSpacing: '0.06em', lineHeight: 1.9,
      }}>
        神戸・灘区天城通<br />
        <a href="https://www.instagram.com/cafemicio1121" target="_blank" rel="noopener" style={{ color: C.tealDeep, textDecoration: 'none', borderBottom: `0.5px solid ${C.tealDeep}` }}>Instagram @cafemicio1121</a>
      </div>
      <div style={{
        fontFamily: F.mono, fontSize: 9, color: C.ink30,
        letterSpacing: '0.22em', marginTop: 22,
      }}>© 2026 CAFEMICIO · ALL RIGHTS RESERVED</div>
      <div style={{ marginTop: 18 }}>
        <a href="/?desktop=1" style={{
          fontFamily: F.mono, fontSize: 10, color: C.ink50,
          letterSpacing: '0.22em', textDecoration: 'none',
          borderBottom: `1px dotted ${C.ink30}`, paddingBottom: 2,
        }}>VIEW DESKTOP ↗</a>
      </div>
    </footer>
  );
}

// ────────────────────────────────────────────────────────────
// Sticky bottom CTA
// ────────────────────────────────────────────────────────────
function StickyCTA({ visible }) {
  return (
    <div style={{
      position: 'fixed', left: 16, right: 16,
      bottom: 'calc(env(safe-area-inset-bottom, 0) + 20px)',
      zIndex: 35, pointerEvents: visible ? 'auto' : 'none',
      transform: visible ? 'translateY(0)' : 'translateY(80px)',
      opacity: visible ? 1 : 0,
      transition: 'all 320ms cubic-bezier(.2,.7,.2,1)',
    }}>
      <a href="https://www.instagram.com/cafemicio1121" target="_blank" rel="noopener" style={{
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        background: C.tealDeep, color: C.cream, textDecoration: 'none',
        padding: '15px 22px', minHeight: 52,
        boxShadow: '0 8px 24px rgba(31,87,87,0.35), 0 2px 6px rgba(0,0,0,0.12)',
        fontFamily: F.jp, fontSize: 15, letterSpacing: '0.06em',
      }}>
        <span style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={C.cream} strokeWidth="1.5">
            <rect x="3" y="3" width="18" height="18" rx="5" />
            <circle cx="12" cy="12" r="4" />
            <circle cx="17.5" cy="6.5" r="1" fill={C.cream} />
          </svg>
          Instagramで見る
        </span>
        <span style={{ fontFamily: F.mono, fontSize: 16, color: '#7FBFBA' }}>↗</span>
      </a>
    </div>
  );
}

// ────────────────────────────────────────────────────────────
// Hamburger overlay
// ────────────────────────────────────────────────────────────
function MenuOverlay({ open, onClose }) {
  const links = [
    { num: '01', jp: '店について', en: 'About' },
    { num: '02', jp: 'お品書き', en: 'Menu' },
    { num: '03', jp: '占い', en: 'Fortune' },
    { num: '04', jp: '店内のようす', en: 'Gallery' },
    { num: '05', jp: '場所と営業時間', en: 'Info' },
  ];
  return (
    <div style={{
      position: 'fixed', inset: 0, zIndex: 50,
      background: C.tealInk, color: C.cream,
      transform: open ? 'translateY(0)' : 'translateY(-100%)',
      transition: 'transform 440ms cubic-bezier(.2,.7,.2,1)',
      display: 'flex', flexDirection: 'column',
      overflowY: 'auto',
    }}>
      <div style={{
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        padding: '14px 20px', borderBottom: '0.5px solid rgba(244,239,230,0.18)',
      }}>
        <BrandMark size={17} color={C.cream} />
        <button onClick={onClose} aria-label="close" style={{
          width: 44, height: 44, border: 'none', background: 'transparent',
          color: C.cream, fontFamily: F.mono, fontSize: 22,
          cursor: 'pointer',
        }}>×</button>
      </div>
      <div style={{ flex: 1, padding: '36px 24px', overflow: 'auto' }}>
        {links.map((l, i) => (
          <a key={l.num} href="#" onClick={onClose} style={{
            display: 'block', textDecoration: 'none', color: C.cream,
            padding: '20px 0', borderBottom: '0.5px solid rgba(244,239,230,0.18)',
          }}>
            <div style={{
              fontFamily: F.mono, fontSize: 10, color: '#7FBFBA',
              letterSpacing: '0.22em', marginBottom: 6,
            }}>{l.num}</div>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 12 }}>
              <span style={{ fontFamily: F.jp, fontSize: 26, letterSpacing: '0.04em' }}>{l.jp}</span>
              <span style={{ fontFamily: F.brand, fontStyle: 'italic', fontSize: 16, color: 'rgba(244,239,230,0.7)' }}>{l.en}</span>
            </div>
          </a>
        ))}
        <div style={{ marginTop: 40, display: 'flex', flexDirection: 'column', gap: 10 }}>
          <div style={{ fontFamily: F.mono, fontSize: 10, color: '#7FBFBA', letterSpacing: '0.22em' }}>FOLLOW</div>
          <a href="https://www.instagram.com/cafemicio1121" target="_blank" rel="noopener" style={{
            fontFamily: F.brand, fontStyle: 'italic', fontSize: 20,
            color: C.cream, textDecoration: 'none',
          }}>@cafemicio1121 ↗</a>
        </div>
        <div style={{
          position: 'absolute', bottom: 40, left: 24, right: 24,
          fontFamily: F.jp, fontSize: 11, color: 'rgba(244,239,230,0.5)',
          letterSpacing: '0.06em', lineHeight: 1.9,
        }}>
          神戸・灘区天城通4丁目1-1<br />
          09:30 — 17:30 · 定休日 水曜・日曜・祝日
        </div>
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────
// TWEAKS PANEL — bottom-sheet UI for adjusting each deco
// ────────────────────────────────────────────────────────────
function TweaksPanel() {
  const { tweaks, update, resetOne, resetAll } = useContext(TweaksContext);
  const [open, setOpen] = useState(false);
  const [hidden, setHidden] = useState(false);
  const ids = Object.keys(DECO_DEFAULTS);
  const sectionList = [...new Set(ids.map(id => DECO_DEFAULTS[id].section))];
  const [sec, setSec] = useState(sectionList[0]);
  const idsInSection = ids.filter(id => DECO_DEFAULTS[id].section === sec);
  const [curId, setCurId] = useState(idsInSection[0]);
  // keep curId valid when section changes
  useEffect(() => {
    if (!idsInSection.includes(curId)) setCurId(idsInSection[0]);
  }, [sec]);
  const def = DECO_DEFAULTS[curId];
  const t = tweaks[curId] || {};
  const enabled = t.enabled !== false;
  const x = t.x != null ? t.x : 0;
  const y = t.y != null ? t.y : 0;
  const scale = t.scale != null ? t.scale : 1;
  const rot = t.rot != null ? t.rot : def.rotate;
  const opacity = t.opacity != null ? t.opacity : def.opacity;

  const copyCSS = () => {
    const lines = ids.map(id => {
      const tk = tweaks[id]; if (!tk) return '';
      const d = DECO_DEFAULTS[id];
      if (tk.enabled === false) return `[data-deco-id="${id}"] { display: none !important; }`;
      const tx = tk.x != null ? tk.x : 0, ty = tk.y != null ? tk.y : 0;
      const sc = tk.scale != null ? tk.scale : 1;
      const rr = tk.rot != null ? tk.rot : d.rotate;
      const op = tk.opacity != null ? tk.opacity : d.opacity;
      return `[data-deco-id="${id}"] { transform: translate(${tx}px, ${ty}px) rotate(${rr}deg) scale(${sc}); opacity: ${op}; }`;
    }).filter(Boolean).join('\n');
    navigator.clipboard?.writeText(lines).catch(()=>{});
  };

  // When hidden, render a minimal restore pill (top-right, away from CTA).
  if (hidden) {
    return (
      <button
        onClick={() => setHidden(false)}
        aria-label="show tweaks"
        title="Show tweaks panel"
        style={{
          position: 'fixed',
          right: 14,
          top: 'calc(env(safe-area-inset-top, 0) + 70px)',
          padding: '6px 10px',
          background: 'rgba(26,26,26,0.85)',
          color: C.cream,
          border: '0.5px solid rgba(244,239,230,0.3)',
          fontFamily: F.mono, fontSize: 9, letterSpacing: '0.22em',
          borderRadius: 4,
          boxShadow: '0 4px 12px rgba(0,0,0,0.2)',
          zIndex: 60, cursor: 'pointer',
        }}>TWEAKS</button>
    );
  }

  // Floating toggle (gear) — bottom-left so it doesn't conflict with StickyCTA on right
  return (
    <>
      <button
        onClick={() => setOpen(o => !o)}
        aria-label="tweaks"
        style={{
          position: 'fixed',
          left: 14,
          bottom: 'calc(env(safe-area-inset-bottom, 0) + 22px)',
          width: 40, height: 40, borderRadius: 999,
          border: 'none', background: C.ink, color: C.cream,
          fontFamily: F.mono, fontSize: 13, letterSpacing: '0.1em',
          boxShadow: '0 6px 18px rgba(0,0,0,0.25)',
          zIndex: 60, cursor: 'pointer',
          display: open ? 'none' : 'inline-flex',
          alignItems: 'center', justifyContent: 'center',
        }}>⚙︎</button>

      <div style={{
        position: 'fixed', left: 0, right: 0, bottom: 0,
        maxHeight: '42vh',
        background: C.ink, color: C.cream,
        zIndex: 80,
        transform: open ? 'translateY(0)' : 'translateY(102%)',
        transition: 'transform 320ms cubic-bezier(.2,.7,.2,1)',
        boxShadow: '0 -10px 30px rgba(0,0,0,0.35)',
        display: 'flex', flexDirection: 'column',
        paddingBottom: 'env(safe-area-inset-bottom, 0)',
      }}>
        {/* handle / header — slim */}
        <div style={{
          display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          padding: '8px 14px 6px',
          borderBottom: '0.5px solid rgba(244,239,230,0.18)',
        }}>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
            <span style={{ fontFamily: F.brand, fontStyle: 'italic', fontSize: 14, color: C.cream }}>Deco Tweaks</span>
            <span style={{ fontFamily: F.mono, fontSize: 8, color: 'rgba(244,239,230,0.45)', letterSpacing: '0.22em' }}>· {curId}</span>
          </div>
          <div style={{ display: 'flex', gap: 4 }}>
            <button onClick={() => setHidden(true)} style={btn('ghost')} title="Hide entirely (click TWEAKS pill to restore)">HIDE</button>
            <button onClick={() => setOpen(false)} style={btn()} title="Collapse">▼</button>
          </div>
        </div>

        {/* body — scrollable, compact */}
        <div style={{ overflowY: 'auto', padding: '8px 14px 10px', flex: 1 }}>
          {/* Section chips */}
          <Row label="SECTION">
            <ChipRow values={sectionList} current={sec} onPick={setSec} />
          </Row>

          {/* Deco chips for selected section */}
          <Row label="DECO">
            <ChipRow
              values={idsInSection}
              current={curId}
              onPick={setCurId}
              labelFor={id => DECO_DEFAULTS[id].label}
            />
          </Row>

          {/* Enable toggle */}
          <Row label="ENABLED">
            <div style={{ display: 'flex', gap: 8 }}>
              <button
                onClick={() => update(curId, { enabled: true })}
                style={pill(enabled)}>ON</button>
              <button
                onClick={() => update(curId, { enabled: false })}
                style={pill(!enabled)}>OFF</button>
            </div>
          </Row>

          {/* Image picker — all 7 brand-kit images selectable per slot */}
          <Row label="IMAGE">
            <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
              {ALL_KINDS.map(k => {
                const curKind = t.pose || def.kind;
                const active = curKind === k;
                return (
                  <button key={k}
                    onClick={() => update(curId, { pose: k })}
                    style={{ ...pill(active), padding: '6px 10px' }}
                    title={k}>
                    {k.replace('-', ' ').toUpperCase()}
                  </button>
                );
              })}
            </div>
          </Row>

          {/* Sliders */}
          <Slider label="X" value={x} min={-200} max={200} step={1}
                  onChange={v => update(curId, { x: v })} suffix="px" />
          <Slider label="Y" value={y} min={-400} max={400} step={1}
                  onChange={v => update(curId, { y: v })} suffix="px" />
          <Slider label="SCALE" value={scale} min={0.3} max={3} step={0.05}
                  onChange={v => update(curId, { scale: v })} format={v => v.toFixed(2)} />
          <Slider label="ROT" value={rot} min={-180} max={180} step={1}
                  onChange={v => update(curId, { rot: v })} suffix="°" />
          <Slider label="OPACITY" value={opacity} min={0} max={1} step={0.02}
                  onChange={v => update(curId, { opacity: v })} format={v => v.toFixed(2)} />

          {/* Actions */}
          <div style={{ display: 'flex', gap: 8, marginTop: 12, flexWrap: 'wrap' }}>
            <button onClick={() => resetOne(curId)} style={btn()}>RESET THIS</button>
            <button onClick={resetAll} style={btn()}>RESET ALL</button>
            <button onClick={copyCSS} style={btn()}>COPY CSS</button>
          </div>
        </div>
      </div>
    </>
  );
}

// Tiny UI helpers for the Tweaks panel
function btn(kind) {
  const base = {
    fontFamily: 'JetBrains Mono, monospace',
    fontSize: 10, letterSpacing: '0.16em',
    padding: '8px 12px',
    background: kind === 'ghost' ? 'transparent' : 'rgba(244,239,230,0.12)',
    color: '#F4EFE6',
    border: '0.5px solid rgba(244,239,230,0.25)',
    cursor: 'pointer',
    minHeight: 32,
  };
  return base;
}
function pill(active) {
  return {
    fontFamily: 'JetBrains Mono, monospace',
    fontSize: 10, letterSpacing: '0.16em',
    padding: '8px 14px',
    background: active ? '#2C7A7B' : 'transparent',
    color: '#F4EFE6',
    border: `0.5px solid ${active ? '#2C7A7B' : 'rgba(244,239,230,0.25)'}`,
    cursor: 'pointer', minWidth: 56,
  };
}
function Row({ label, children }) {
  return (
    <div style={{ marginBottom: 8 }}>
      <div style={{
        fontFamily: 'JetBrains Mono, monospace', fontSize: 8,
        letterSpacing: '0.22em', color: 'rgba(244,239,230,0.55)',
        marginBottom: 4,
      }}>{label}</div>
      {children}
    </div>
  );
}
function ChipRow({ values, current, onPick, labelFor }) {
  return (
    <div style={{ display: 'flex', gap: 6, overflowX: 'auto', paddingBottom: 4 }}>
      {values.map(v => {
        const active = v === current;
        const txt = labelFor ? labelFor(v) : v.toUpperCase();
        return (
          <button key={v} onClick={() => onPick(v)} style={{
            ...pill(active), whiteSpace: 'nowrap', flex: '0 0 auto',
          }}>{txt}</button>
        );
      })}
    </div>
  );
}
function Slider({ label, value, min, max, step, onChange, suffix, format }) {
  const disp = format ? format(value) : `${Math.round(value)}${suffix || ''}`;
  return (
    <div style={{
      display: 'grid', gridTemplateColumns: '46px 1fr 54px',
      alignItems: 'center', gap: 8, marginBottom: 4,
    }}>
      <span style={{
        fontFamily: 'JetBrains Mono, monospace', fontSize: 9,
        letterSpacing: '0.18em', color: 'rgba(244,239,230,0.7)',
      }}>{label}</span>
      <input
        type="range"
        min={min} max={max} step={step} value={value}
        onChange={e => onChange(parseFloat(e.target.value))}
        style={{ width: '100%', accentColor: '#2C7A7B', height: 18 }}
      />
      <span style={{
        fontFamily: 'JetBrains Mono, monospace', fontSize: 10,
        color: '#F4EFE6', textAlign: 'right',
      }}>{disp}</span>
    </div>
  );
}

// ────────────────────────────────────────────────────────────
// App
// ────────────────────────────────────────────────────────────
function App() {
  const [menuOpen, setMenuOpen] = useState(false);
  const [scrolled, setScrolled] = useState(false);
  const [ctaVisible, setCtaVisible] = useState(false);
  const scrollRef = useRef(null);

  useEffect(() => {
    const el = scrollRef.current;
    if (!el) return;
    const onScroll = () => {
      setScrolled(el.scrollTop > 24);
      setCtaVisible(el.scrollTop > 380);
    };
    el.addEventListener('scroll', onScroll, { passive: true });
    return () => el.removeEventListener('scroll', onScroll);
  }, []);

  // Track viewport-level scroll for sticky behaviors when running outside
  // the iPhone-mockup frame (full-screen mobile deployment).
  useEffect(() => {
    const onScroll = () => {
      const y = window.scrollY;
      setScrolled(y > 24);
      setCtaVisible(y > 380);
    };
    window.addEventListener('scroll', onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener('scroll', onScroll);
  }, []);

  return (
    <TweaksProvider>
      <div style={{
        width: '100%',
        minHeight: '100vh',
        position: 'relative',
        background: C.cream,
        paddingTop: 'env(safe-area-inset-top, 0)',
        paddingBottom: 'env(safe-area-inset-bottom, 0)',
      }}>
        <Nav onMenu={() => setMenuOpen(true)} scrolled={scrolled} />
        <Hero />
        <About />
        <Menu />
        <Fortune />
        <Gallery />
        <Info />
        <Footer />

        <StickyCTA visible={ctaVisible && !menuOpen} />
        <MenuOverlay open={menuOpen} onClose={() => setMenuOpen(false)} />
        {/* <TweaksPanel /> — disabled in production */}
      </div>
    </TweaksProvider>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
