/* 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.
// ────────────────────────────────────────────────────────────
// 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.55, 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.32, 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-cat-curl':      { section: 'menu',    label: 'Cat — Curl',   kind: 'cat-curl',   size: fluidSize(130), ratio: 1,   rotate:   0, opacity: 0.85, color: 'teal',  anchor: { top: 24,             right: fluidAxis(-20) } },
  'menu-cat-jump':      { section: 'menu',    label: 'Cat — Jump',   kind: 'cat-jump',   size: fluidSize(110), ratio: 1,   rotate:   0, opacity: 0.7,  color: 'teal',  anchor: { bottom: fluidAxis(60), left: fluidAxis(-16) } },
  'menu-cat-walk':      { section: 'menu',    label: 'Cat — Walk',   kind: 'cat-walk',   size: fluidSize(90),  ratio: 1,   rotate:   0, opacity: 0.45, color: 'teal',  anchor: { top: '52%',          right: fluidAxis(-10) } },

  'gallery-tarot-moon': { section: 'gallery', label: 'Tarot — Moon', kind: 'tarot-moon', size: fluidSize(130), ratio: 1.5, rotate: -16, opacity: 0.6,  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.6,  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.4,  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)  } },
};

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

function TweaksProvider({ children }) {
  const [tweaks, setTweaks] = useState(() => {
    try { return JSON.parse(localStorage.getItem(TWEAKS_KEY) || '{}'); }
    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;
  const t = tweaks[id] || {};
  if (t.enabled === false) return null;

  const baseColor = def.color === 'cream' ? C.cream : C.teal;
  const tx = t.x != null ? t.x : 0;
  const ty = 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 url = `/assets/brand-kit/individual/${def.kind}-mask.png`;

  // Width can be a number (px) or a CSS string (e.g. clamp()).
  // Height = width * ratio. Build CSS strings so both fluid + fixed work.
  const widthCss = typeof def.size === 'number' ? `${def.size}px` : def.size;
  const heightCss = def.ratio === 1
    ? widthCss
    : (typeof def.size === 'number'
        ? `${def.size * def.ratio}px`
        : `calc(${widthCss} * ${def.ratio})`);

  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 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="#" 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" label="storefront · exterior"
            src="/assets/hero/hero-pc.jpg"
            alt="カフェ ミーチョ 店頭：窓ガラス越しに金色の CAFE MICIO レター" />
          {/* Vertical FIG caption */}
          <div style={{
            position: 'absolute', top: 16, left: -10,
            fontFamily: F.mono, fontSize: 9.5, color: C.tealDeep,
            letterSpacing: '0.32em', writingMode: 'vertical-rl',
            background: C.cream, padding: '8px 4px',
          }}>FIG.00 — STOREFRONT</div>
          {/* Editorial frame number */}
          <div style={{
            position: 'absolute', bottom: -14, right: -4,
            fontFamily: F.brand, fontStyle: 'italic', fontSize: 64,
            color: C.tealDeep, lineHeight: 1, letterSpacing: '0.02em',
          }}>00</div>
        </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 / 04" 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} label={p.label} src={p.src} alt={p.alt} />
              <div style={{
                fontFamily: F.mono, fontSize: 9, color: C.ink50,
                letterSpacing: '0.18em', marginTop: 8,
              }}>0{i + 1} / 03</div>
            </div>
          ))}
        </div>
      </Reveal>
    </section>
  );
}

// ────────────────────────────────────────────────────────────
// MENU
// ────────────────────────────────────────────────────────────
const menuData = [
  {
    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' },
    ],
  },
  {
    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: 'チーズと半熟玉子' },
    ],
  },
  {
    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: '自家製ジャム添え' },
    ],
  },
  {
    title: 'ドリンク', latin: 'Drinks', hours: 'ICE / HOT',
    note: '各種ご用意あります',
    items: [
      { name: 'ブレンド',     en: 'Blend coffee',  price: 'ICE / HOT' },
      { name: 'カフェラテ',   en: 'Café latte',    price: 'ICE / HOT' },
      { name: 'カフェオレ',   en: 'Café au lait',  price: 'ICE / HOT' },
      { name: 'ストレートティー', en: 'Tea (straight)', price: 'ICE / HOT' },
      { name: 'ミルクティー', en: 'Milk tea',      price: 'ICE / HOT' },
      { name: 'レモンティー', en: 'Lemon tea',     price: 'ICE / HOT' },
    ],
  },
];

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' }}>
      <BrandDeco id="menu-cat-curl" />
      <BrandDeco id="menu-cat-jump" />
      <BrandDeco id="menu-cat-walk" />
      <Reveal><SectionHead num="02 / 04" 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}` }}>
                <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) => (
                      <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={{
                            fontFamily: F.mono, fontSize: 12, color: C.tealDeep,
                            letterSpacing: '0.04em', whiteSpace: 'nowrap',
                          }}>{it.price}</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>
  );
}

// ────────────────────────────────────────────────────────────
// GALLERY — masonry
// ────────────────────────────────────────────────────────────
function Gallery() {
  const items = [
    { h: 220, tone: 'teal', src: '/assets/photos/interior-table-01.jpg',     alt: 'テーブル席' },
    { h: 160, tone: 'warm', src: '/assets/photos/interior-counter-02.jpg',   alt: 'カウンター' },
    { h: 180, tone: 'deep', src: '/assets/photos/sweets-cheesecake.jpg',     alt: 'チーズケーキ' },
    { h: 240, tone: 'teal', src: '/assets/photos/interior-window-01.jpg',   alt: '窓辺' },
    { h: 200, tone: 'warm', src: '/assets/photos/interior-shelf.jpg',        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/interior-counter-01.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="03 / 04" 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} label={`fig.${String(i * 2 + 1).padStart(2, '0')}`} 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} label={`fig.${String(i * 2 + 2).padStart(2, '0')}`} 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',
          }}>04 / 04</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" last>
          <a href="#" style={{ color: C.cream, textDecoration: 'none', borderBottom: `0.5px solid rgba(244,239,230,0.5)`, paddingBottom: 2 }}>
            @cafemicio1121
          </a>
        </InfoRow>
      </Reveal>

      {/* Map card */}
      <Reveal delay={200} style={{ marginTop: 32, 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,
          }}>FIG.09 — LOCATION MAP</div>
          {/* Stylized map */}
          <div style={{
            position: 'relative', height: 180, overflow: 'hidden',
            background: 'rgba(244,239,230,0.04)',
          }}>
            <svg viewBox="0 0 320 180" width="100%" height="100%" preserveAspectRatio="none">
              {/* streets */}
              <path d="M0 60 L320 80" stroke="rgba(244,239,230,0.22)" strokeWidth="14" fill="none" />
              <path d="M0 130 L320 140" stroke="rgba(244,239,230,0.12)" strokeWidth="8" fill="none" />
              <path d="M100 0 L120 180" stroke="rgba(244,239,230,0.18)" strokeWidth="10" fill="none" />
              <path d="M220 0 L240 180" stroke="rgba(244,239,230,0.1)" strokeWidth="6" fill="none" />
              {/* blocks */}
              <rect x="20" y="20" width="60" height="28" fill="rgba(244,239,230,0.04)" />
              <rect x="20" y="92" width="60" height="32" fill="rgba(244,239,230,0.04)" />
              <rect x="140" y="20" width="60" height="32" fill="rgba(244,239,230,0.04)" />
              <rect x="140" y="92" width="60" height="32" fill="rgba(244,239,230,0.05)" />
              {/* river hint */}
              <path d="M260 0 Q270 60 250 110 Q260 150 270 180" stroke="rgba(127,191,186,0.4)" strokeWidth="3" fill="none" />
              {/* pin */}
              <circle cx="158" cy="106" r="18" fill="rgba(127,191,186,0.18)" />
              <circle cx="158" cy="106" r="6" fill="#7FBFBA" />
              <circle cx="158" cy="106" r="3" fill={C.tealInk} />
            </svg>
            <div style={{
              position: 'absolute', left: 170, top: 90,
              fontFamily: F.brand, fontStyle: 'italic', fontSize: 14,
              color: '#7FBFBA',
            }}>cafemicio</div>
          </div>
          <a href="#" 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>
    </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 (
    <footer style={{
      position: 'relative', overflow: 'hidden',
      padding: '36px 24px 110px', 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="#" 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="#" 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: 'Gallery' },
    { num: '04', 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="#" 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(()=>{});
  };

  if (hidden) return null;

  // 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: 44, height: 44, borderRadius: 999,
          border: 'none', background: C.ink, color: C.cream,
          fontFamily: F.mono, fontSize: 14, 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: '72vh',
        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 */}
        <div style={{
          display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          padding: '14px 16px 8px',
          borderBottom: '0.5px solid rgba(244,239,230,0.18)',
        }}>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
            <span style={{ fontFamily: F.brand, fontStyle: 'italic', fontSize: 18, color: C.cream }}>Deco Tweaks</span>
            <span style={{ fontFamily: F.mono, fontSize: 9, color: 'rgba(244,239,230,0.5)', letterSpacing: '0.22em' }}>MOBILE · v1</span>
          </div>
          <div style={{ display: 'flex', gap: 6 }}>
            <button onClick={() => setHidden(true)} style={btn('ghost')}>HIDE</button>
            <button onClick={() => setOpen(false)} style={btn()}>×</button>
          </div>
        </div>

        {/* body — scrollable */}
        <div style={{ overflowY: 'auto', padding: '12px 16px 14px', 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>

          {/* 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: 12 }}>
      <div style={{
        fontFamily: 'JetBrains Mono, monospace', fontSize: 9,
        letterSpacing: '0.22em', color: 'rgba(244,239,230,0.55)',
        marginBottom: 6,
      }}>{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={{ marginBottom: 10 }}>
      <div style={{
        display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
        marginBottom: 4,
      }}>
        <span style={{
          fontFamily: 'JetBrains Mono, monospace', fontSize: 9,
          letterSpacing: '0.22em', color: 'rgba(244,239,230,0.7)',
        }}>{label}</span>
        <span style={{
          fontFamily: 'JetBrains Mono, monospace', fontSize: 11,
          color: '#F4EFE6',
        }}>{disp}</span>
      </div>
      <input
        type="range"
        min={min} max={max} step={step} value={value}
        onChange={e => onChange(parseFloat(e.target.value))}
        style={{ width: '100%', accentColor: '#2C7A7B' }}
      />
    </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 />
        <Gallery />
        <Info />
        <Footer />

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

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