/* global React, ReactDOM */
const { useState: uS, useEffect: uE } = React;

// Framer Motion UMD exports as window.Motion (not window.FramerMotion)
const _FM = window.Motion || {};
const AnimatePresence = _FM.AnimatePresence || (({ children }) => children);
const motion = _FM.motion || new Proxy({}, {
  get: (_, tag) => function MotionEl({ children, initial, animate, whileInView, whileHover, exit, viewport, variants, transition, ...props }) {
    return React.createElement(tag, props, children);
  }
});

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accentRed": "#A82828",
  "background": "#F5F0E8",
  "displayFont": "Shippori Mincho",
  "showShojiGrid": true,
  "ctaLabel": "Reserve a visit"
}/*EDITMODE-END*/;

// animation variants
const fadeUp = {
  hidden: { opacity: 0, y: 24 },
  show:   { opacity: 1, y: 0, transition: { duration: 0.7, ease: "easeOut" } }
};
const fadeIn = {
  hidden: { opacity: 0 },
  show:   { opacity: 1, transition: { duration: 0.8, ease: "easeOut" } }
};
const stagger = {
  hidden: {},
  show:   { transition: { staggerChildren: 0.1, delayChildren: 0.05 } }
};
const viewOpts = { once: true, margin: "-80px" };

function useT() {
  const [, force] = uS(0);
  uE(() => {
    const fn = () => force(x => x + 1);
    window.addEventListener("nik-lang-change", fn);
    return () => window.removeEventListener("nik-lang-change", fn);
  }, []);
  return window.t;
}

function setLang(l) {
  window.NIK_LANG = l;
  window.dispatchEvent(new CustomEvent("nik-lang-change"));
}

function Nav({ onBook, onGift, lang }) {
  const t = useT();
  const [scrolled, setScrolled] = uS(false);
  uE(() => {
    const fn = () => setScrolled(window.scrollY > 40);
    window.addEventListener("scroll", fn);
    return () => window.removeEventListener("scroll", fn);
  }, []);
  return (
    <nav className={"nav" + (scrolled ? " scrolled" : "")}>
      <a href="#top" className="nav-logo">
        <img src="assets/logo.jpg" alt="" />
        <div className="wordmark">Nik Onsen<small>SPA · Phnom Penh</small></div>
      </a>
      <div className="nav-links">
        <a href="#onsen">{t("nav.onsen")}</a>
        <a href="#services">{t("nav.services")}</a>
        <a href="#atmosphere">{t("nav.atmosphere")}</a>
        <a href="#visit">{t("nav.visit")}</a>
        <a href="#" onClick={(e)=>{e.preventDefault(); onGift();}}>{t("nav.gift")}</a>
      </div>
      <div className="nav-cta">
        <div className="lang-switch">
          {["EN","KM","JA"].map((l, i) => (
            <React.Fragment key={l}>
              <button className={lang===l?"active":""} onClick={()=>setLang(l)}>{l}</button>
              {i < 2 && <span className="sep">·</span>}
            </React.Fragment>
          ))}
        </div>
        <button className="btn btn-primary" onClick={onBook}>{t("nav.reserve")}</button>
      </div>
    </nav>
  );
}

function Hero({ onBook, tweaks }) {
  const t = useT();
  const headlineParts = (t("hero.headline") || "").split("\n");
  return (
    <section className="hero" id="top" data-screen-label="01 Home Hero">
      {tweaks.showShojiGrid && <div className="shoji-bg" />}
      <motion.div
        className="hero-text"
        variants={stagger}
        initial="hidden"
        animate="show"
      >
        <motion.div className="eyebrow" variants={fadeUp}><span className="dot" />{t("hero.eyebrow")}</motion.div>
        <motion.h1 className="hero-title" variants={fadeUp}>
          {headlineParts.map((line, i) => (
            <React.Fragment key={i}>
              {i === headlineParts.length - 1 ? <em>{line}</em> : line}
              {i < headlineParts.length - 1 && <br />}
            </React.Fragment>
          ))}
        </motion.h1>
        <motion.div className="hero-jp" variants={fadeUp}>{t("hero.jp")}</motion.div>
        <motion.p className="hero-lede" variants={fadeUp}>{t("hero.lede")}</motion.p>
        <motion.div className="hero-actions" variants={fadeUp}>
          <button className="btn btn-primary" onClick={onBook}>{tweaks.ctaLabel || t("hero.cta")}
            <svg width="14" height="10" viewBox="0 0 14 10" fill="none"><path d="M1 5h12m0 0L9 1m4 4L9 9" stroke="currentColor" strokeWidth="1.4" /></svg>
          </button>
          <a href="#onsen" className="btn btn-ghost">{t("hero.alt")}</a>
        </motion.div>
      </motion.div>
      <motion.div
        className="hero-image"
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        transition={{ duration: 1.2, ease: "easeOut", delay: 0.2 }}
      >
        <img src="assets/lobby.jpg" alt="" />
        <div className="hero-meta">
          <div><span className="num">10—23</span>{t("creds.hours")}</div>
          <div><span className="num">3</span>{t("creds.langs").split(" — ")[0]}</div>
          <div><span className="num">42°</span>{t("creds.temp")}</div>
        </div>
        <div className="hero-anno">
          <span>{t("hero.lobby")}</span>
          <span className="ln" />
          <span>N 11.5774° · E 104.9006°</span>
        </div>
        <div className="hero-stamp"><img src="assets/logo.jpg" alt="" /></div>
      </motion.div>
    </section>
  );
}

function PhotoPlaceholder({ variant = "wood", glyph, kind, frame, grain = true }) {
  return (
    <div className={"photo-placeholder photo-placeholder--" + variant + (grain ? " photo-placeholder--grain" : "")}>
      <div className="pp-meta">
        <div className="left"><span>{kind}</span><span className="pp-tag">{frame}</span></div>
        <span>NIK · {variant.toUpperCase()}</span>
      </div>
      <div className="pp-glyph">{glyph}</div>
    </div>
  );
}

function Creds() {
  const t = useT();
  return (
    <motion.div
      className="creds"
      data-screen-label="Credentials Strip"
      variants={stagger}
      initial="hidden"
      whileInView="show"
      viewport={viewOpts}
    >
      <motion.div className="creds-item" variants={fadeUp}><span className="cnum">2022</span>{t("creds.est")}</motion.div>
      <motion.div className="creds-item" variants={fadeUp}><span className="cstars">★★★★★</span>{t("creds.reviews")}</motion.div>
      <motion.div className="creds-item" variants={fadeUp}><span className="cnum">3</span>{t("creds.langs")}</motion.div>
      <motion.div className="creds-item" variants={fadeUp}><span className="cnum">42°</span>{t("creds.temp")}</motion.div>
      <motion.div className="creds-item" variants={fadeUp}><span className="cnum">10–23</span>{t("creds.hours")}</motion.div>
    </motion.div>
  );
}

function Onsen({ onBook }) {
  const t = useT();
  const steps = [
    { n: "一", t: t("onsen.s1.t"), d: t("onsen.s1.d") },
    { n: "二", t: t("onsen.s2.t"), d: t("onsen.s2.d") },
    { n: "三", t: t("onsen.s3.t"), d: t("onsen.s3.d") },
    { n: "四", t: t("onsen.s4.t"), d: t("onsen.s4.d") }
  ];
  const head = t("onsen.h");
  const split = head.lastIndexOf(". ");
  return (
    <section id="onsen" className="etiquette section-pad" data-screen-label="02 The Onsen">
      <motion.div className="section-head" variants={stagger} initial="hidden" whileInView="show" viewport={viewOpts}>
        <motion.div className="label" variants={fadeUp}>
          <span className="num">{t("onsen.label")}</span>
          <span className="name" style={{color:"var(--off-white)"}}>{t("onsen.name")}</span>
        </motion.div>
        <motion.h2 variants={fadeUp}>{split>0 ? <>{head.slice(0, split+1)} <em>{head.slice(split+2)}</em></> : head}</motion.h2>
      </motion.div>
      <motion.div className="etiquette-steps" variants={stagger} initial="hidden" whileInView="show" viewport={viewOpts}>
        {steps.map((s, i) => (
          <motion.div className="etq-step" key={i} variants={fadeUp}>
            <div className="num">{s.n}</div>
            <h4>{s.t}</h4>
            <p>{s.d}</p>
          </motion.div>
        ))}
      </motion.div>
      <motion.div
        style={{ display: "flex", gap: 16, justifyContent: "center", marginTop: 80 }}
        initial={{ opacity: 0, y: 16 }}
        whileInView={{ opacity: 1, y: 0 }}
        viewport={viewOpts}
        transition={{ duration: 0.6, ease: "easeOut", delay: 0.3 }}
      >
        <button className="btn btn-red" onClick={onBook}>{t("onsen.cta")}
          <svg width="14" height="10" viewBox="0 0 14 10" fill="none"><path d="M1 5h12m0 0L9 1m4 4L9 9" stroke="currentColor" strokeWidth="1.4" /></svg>
        </button>
      </motion.div>
    </section>
  );
}

function H2Split({ text }) {
  const split = text.lastIndexOf(". ");
  return split > 0 ? <>{text.slice(0, split+1)} <em>{text.slice(split+2)}</em></> : <>{text}</>;
}

function Services({ onBookService }) {
  const t = useT();
  return (
    <section id="services" className="services section-pad" data-screen-label="03 Services">
      <motion.div className="section-head" variants={stagger} initial="hidden" whileInView="show" viewport={viewOpts}>
        <motion.div className="label" variants={fadeUp}><span className="num">{t("svc.label")}</span><span className="name">{t("svc.name")}</span></motion.div>
        <motion.h2 variants={fadeUp}><H2Split text={t("svc.h")} /></motion.h2>
      </motion.div>
      <motion.div className="service-list" variants={stagger} initial="hidden" whileInView="show" viewport={viewOpts}>
        {window.NIK_SERVICES.map(s => (
          <motion.div
            className="service-row"
            key={s.id}
            variants={fadeUp}
            onClick={() => onBookService(s.id)}
            whileHover={{ x: 6 }}
            transition={{ duration: 0.2, ease: "easeOut" }}
          >
            <div className="num">{s.num}</div>
            <div className="name">{s.name}<span>{s.nameJp}</span></div>
            <div className="desc">{s.desc}</div>
            <div className="duration">{s.durations.length > 1 ? `${s.durations[0]}–${s.durations[s.durations.length-1]} min` : `${s.duration} min`}</div>
            <div className="price">{`${t("svc.from")} $${Math.min(...Object.values(s.pricing))}`}
              <svg className="arrow" width="14" height="10" viewBox="0 0 14 10" fill="none" style={{ display: "inline-block", marginLeft: 8 }}><path d="M1 5h12m0 0L9 1m4 4L9 9" stroke="currentColor" strokeWidth="1.4" /></svg>
            </div>
          </motion.div>
        ))}
      </motion.div>
      <motion.div
        style={{ marginTop: 48, fontSize: 13, color: "var(--stone)", maxWidth: 600 }}
        initial={{ opacity: 0 }}
        whileInView={{ opacity: 1 }}
        viewport={viewOpts}
        transition={{ duration: 0.6, ease: "easeOut", delay: 0.4 }}
      >{t("svc.note")}</motion.div>
    </section>
  );
}

function Atmosphere() {
  const t = useT();
  return (
    <section id="atmosphere" className="atmosphere section-pad" data-screen-label="04 Atmosphere">
      <motion.div className="section-head" variants={stagger} initial="hidden" whileInView="show" viewport={viewOpts}>
        <motion.div className="label" variants={fadeUp}><span className="num">{t("atmo.label")}</span><span className="name">{t("atmo.name")}</span></motion.div>
        <motion.h2 variants={fadeUp}><H2Split text={t("atmo.h")} /></motion.h2>
      </motion.div>
      <motion.div className="atmosphere-grid" variants={stagger} initial="hidden" whileInView="show" viewport={viewOpts}>
        <motion.div className="atmo-card atmo-1" variants={fadeIn}>
          <img src="assets/lobby.jpg" alt="" style={{objectPosition: "20% 40%"}} />
          <div className="caption">{t("atmo.cap1")}</div>
        </motion.div>
        <motion.div className="atmo-card atmo-2" variants={fadeIn}>
          <img src="assets/lobby.jpg" alt="" style={{objectPosition: "75% 65%"}} />
          <div className="caption">{t("atmo.cap2")}</div>
        </motion.div>
        <motion.div className="atmo-card atmo-3" variants={fadeUp}><PhotoPlaceholder variant="wood" glyph="檜" kind={t("atmo.cap3")} frame="03 / 06" /></motion.div>
        <motion.div className="atmo-quote" variants={fadeUp}>
          <div className="q">{t("atmo.quote")}</div>
          <div className="src">{t("atmo.qsrc")}</div>
        </motion.div>
        <motion.div className="atmo-card atmo-4" variants={fadeUp}><PhotoPlaceholder variant="sakura" glyph="桜" kind="Sakura corner" frame="04 / 06" /></motion.div>
        <motion.div className="atmo-card atmo-5" variants={fadeUp}><PhotoPlaceholder variant="stone" glyph="石" kind="Stone path" frame="05 / 06" /></motion.div>
      </motion.div>
      <motion.p
        style={{ marginTop: 24, fontSize: 11, fontFamily: "var(--font-mono)", letterSpacing: "0.18em", color: "var(--stone)", textTransform: "uppercase" }}
        initial={{ opacity: 0 }}
        whileInView={{ opacity: 1 }}
        viewport={viewOpts}
        transition={{ duration: 0.6, delay: 0.5 }}
      >06 frames · Phnom Penh · {new Date().getFullYear()}</motion.p>
    </section>
  );
}

function Pull() {
  const t = useT();
  return (
    <section className="pull" data-screen-label="05 Pull Quote">
      <motion.div
        className="img-col"
        initial={{ opacity: 0, x: -32 }}
        whileInView={{ opacity: 1, x: 0 }}
        viewport={viewOpts}
        transition={{ duration: 0.8, ease: "easeOut" }}
      ><PhotoPlaceholder variant="ink" glyph="湯" kind={t("pull.eyebrow")} frame="—" /></motion.div>
      <motion.div
        initial={{ opacity: 0, x: 32 }}
        whileInView={{ opacity: 1, x: 0 }}
        viewport={viewOpts}
        transition={{ duration: 0.8, ease: "easeOut", delay: 0.15 }}
      >
        <div className="eyebrow" style={{ marginBottom: 32 }}>{t("pull.eyebrow")}</div>
        <blockquote>{t("pull.q")}</blockquote>
        <div className="attr"><span className="line" />{t("pull.attr")}</div>
      </motion.div>
    </section>
  );
}

function Reviews() {
  const t = useT();
  const items = [
    { stars: "★★★★★", q: "Felt like an afternoon in Hakone. The therapist remembered my pressure preference from the booking form before I even said hello.", who: "Aiko M.", src: "Tripadvisor · Mar 2026" },
    { stars: "★★★★★", q: "The bath is real. Not a hot pool with Japanese music — actual onsen temperature, actual quiet. Worth the price twice over.", who: "Daniel K.", src: "Google · Feb 2026" },
    { stars: "★★★★★", q: "មកលើកទីបី។ ស្ងាត់ ស្អាត ច្រើនជាងគ្រប់ប្រាក់ដែលបានបង់។", who: "Sothea R.", src: "Facebook · Jan 2026" }
  ];
  return (
    <section className="reviews" data-screen-label="06 Reviews">
      <motion.div className="section-head" variants={stagger} initial="hidden" whileInView="show" viewport={viewOpts}>
        <motion.div className="label" variants={fadeUp}><span className="num">{t("rev.label")}</span><span className="name">{t("rev.name")}</span></motion.div>
        <motion.h2 variants={fadeUp}><H2Split text={t("rev.h")} /></motion.h2>
      </motion.div>
      <motion.div className="reviews-grid" variants={stagger} initial="hidden" whileInView="show" viewport={viewOpts}>
        {items.map((r, i) => (
          <motion.div
            className="review-card"
            key={i}
            variants={fadeUp}
            whileHover={{ y: -4 }}
            transition={{ duration: 0.25, ease: "easeOut" }}
          >
            <div className="stars">{r.stars}</div>
            <div className="qt">"{r.q}"</div>
            <div className="meta"><span>— {r.who}</span><span>{r.src}</span></div>
          </motion.div>
        ))}
      </motion.div>
    </section>
  );
}

function Journal() {
  const t = useT();
  const posts = [
    { kind: "Field Note", title: "Why we keep our baths at 42°C", date: "08 Apr 2026", variant: "wood", glyph: "湯" },
    { kind: "Etiquette", title: "First-time onsen: a short, kind guide", date: "22 Mar 2026", variant: "stone", glyph: "礼" },
    { kind: "Materials", title: "On the joinery — and the man in Battambang", date: "01 Mar 2026", variant: "cream", glyph: "木" }
  ];
  return (
    <section className="journal" data-screen-label="07 Journal">
      <motion.div className="section-head" variants={stagger} initial="hidden" whileInView="show" viewport={viewOpts}>
        <motion.div className="label" variants={fadeUp}><span className="num">{t("jr.label")}</span><span className="name">{t("jr.name")}</span></motion.div>
        <motion.h2 variants={fadeUp}><H2Split text={t("jr.h")} /></motion.h2>
      </motion.div>
      <motion.div className="journal-grid" variants={stagger} initial="hidden" whileInView="show" viewport={viewOpts}>
        {posts.map((p, i) => (
          <motion.article
            className="journal-card"
            key={i}
            variants={fadeUp}
            whileHover={{ y: -4 }}
            transition={{ duration: 0.25, ease: "easeOut" }}
          >
            <div className="img"><PhotoPlaceholder variant={p.variant} glyph={p.glyph} kind={p.kind} frame={`0${i+1} / 03`} /></div>
            <div className="body">
              <div className="kind">{p.kind}</div>
              <h4>{p.title}</h4>
              <div className="date">{p.date} · 4 {t("jr.read")}</div>
            </div>
          </motion.article>
        ))}
      </motion.div>
    </section>
  );
}

function StickyCta({ onBook }) {
  const t = useT();
  return (
    <div className="sticky-cta">
      <a className="call" href="tel:+855969195566">{t("stick.call")}</a>
      <button className="reserve" onClick={onBook}>{t("stick.reserve")}</button>
    </div>
  );
}

function Visit({ onBook }) {
  const t = useT();
  return (
    <section id="visit" className="visit section-pad" data-screen-label="06 Visit">
      <motion.div className="section-head" variants={stagger} initial="hidden" whileInView="show" viewport={viewOpts}>
        <motion.div className="label" variants={fadeUp}><span className="num">{t("visit.label")}</span><span className="name">{t("visit.name")}</span></motion.div>
        <motion.h2 variants={fadeUp}><H2Split text={t("visit.h")} /></motion.h2>
      </motion.div>
      <motion.div
        className="visit-grid"
        initial={{ opacity: 0, y: 24 }}
        whileInView={{ opacity: 1, y: 0 }}
        viewport={viewOpts}
        transition={{ duration: 0.7, ease: "easeOut", delay: 0.15 }}
      >
        <div className="visit-info">
          <dl><dt>{t("visit.address")}</dt><dd>#18, Street 566<br />Sangkat Boeng Kak 2, Khan Tuol Kouk<br />Phnom Penh 120408</dd></dl>
          <dl><dt>{t("visit.hours")}</dt><dd>
            <div className="hours-row"><span>{t("visit.daily")}</span><span>10:00 – 23:00</span></div>
            <div className="hours-row" style={{ color: "var(--stone)" }}><span>{t("visit.last")}</span><span>21:00</span></div>
          </dd></dl>
          <dl><dt>{t("visit.contact")}</dt><dd>
            <div className="hours-row"><a href="tel:+855969195566">+855 96 919 5566</a><span style={{color: "var(--stone)"}}>{t("visit.tap")}</span></div>
            <div className="hours-row" style={{ marginTop: 4 }}><a href="mailto:nik.onsenspa@gmail.com">nik.onsenspa@gmail.com</a><span style={{color: "var(--stone)"}}>{t("visit.email")}</span></div>
          </dd></dl>
          <dl><dt>{t("visit.first")}</dt><dd>{t("visit.firstD")}</dd></dl>
          <dl><dt>{t("visit.langs")}</dt><dd>{t("visit.langsD")}</dd></dl>
          <div style={{ display: "flex", gap: 12, marginTop: 40 }}>
            <button className="btn btn-primary" onClick={onBook}>{t("nav.reserve")}</button>
            <a href="tel:+855969195566" className="btn btn-ghost">{t("visit.callBtn")}</a>
          </div>
        </div>
        <div className="map-card">
          <svg viewBox="0 0 400 480" preserveAspectRatio="none">
            <defs><pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse"><path d="M 40 0 L 0 0 0 40" fill="none" stroke="rgba(26,26,26,0.06)" strokeWidth="1"/></pattern></defs>
            <rect width="100%" height="100%" fill="var(--cream)"/>
            <rect width="100%" height="100%" fill="url(#grid)" />
            <path d="M 0 220 L 400 240" stroke="rgba(26,26,26,0.18)" strokeWidth="14" fill="none" />
            <path d="M 200 0 L 220 480" stroke="rgba(26,26,26,0.18)" strokeWidth="10" fill="none" />
            <path d="M 0 360 L 400 380" stroke="rgba(26,26,26,0.10)" strokeWidth="6" fill="none" />
            <path d="M 80 0 L 100 480" stroke="rgba(26,26,26,0.10)" strokeWidth="6" fill="none" />
            <path d="M 320 0 L 340 480" stroke="rgba(26,26,26,0.10)" strokeWidth="6" fill="none" />
            <rect x="20" y="40" width="120" height="120" fill="rgba(92,117,72,0.18)" />
            <text x="80" y="105" textAnchor="middle" fontFamily="ui-monospace, monospace" fontSize="9" fill="var(--plant)" letterSpacing="0.2em">PARK</text>
            <text x="380" y="260" textAnchor="end" fontFamily="ui-monospace, monospace" fontSize="9" fill="var(--stone)" letterSpacing="0.2em">ST 566 →</text>
            <text x="220" y="20" textAnchor="end" fontFamily="ui-monospace, monospace" fontSize="9" fill="var(--stone)" letterSpacing="0.2em">↑ ST 271</text>
          </svg>
          <div className="map-pin">
            <div className="stamp"><img src="assets/logo.jpg" alt="" /></div>
            <div className="label">Nik Onsen · #18</div>
          </div>
        </div>
      </motion.div>
    </section>
  );
}

function Footer({ onGift }) {
  const t = useT();
  return (
    <footer className="foot" data-screen-label="08 Footer">
      <div className="foot-grid">
        <div className="brand-block">
          <div className="mark">
            <img src="assets/logo.jpg" alt="" />
            <div className="wm">Nik Onsen<br /><span style={{ fontFamily: "var(--font-mono)", fontSize: 10, letterSpacing: "0.3em", color: "var(--stone-light)", textTransform: "uppercase" }}>SPA · Phnom Penh</span></div>
          </div>
          <p>{t("foot.intro")}</p>
        </div>
        <div>
          <h5>{t("foot.h.visit")}</h5>
          <ul><li>#18, Street 566</li><li>Sangkat Boeng Kak 2</li><li>Khan Tuol Kouk</li><li>Phnom Penh 120408</li></ul>
        </div>
        <div>
          <h5>{t("foot.h.hours")}</h5>
          <ul><li>{t("visit.daily")}</li><li>10:00 – 23:00</li><li>{t("visit.last")} 21:00</li></ul>
        </div>
        <div>
          <h5>{t("foot.h.reach")}</h5>
          <ul>
            <li><a href="tel:+855969195566">+855 96 919 5566</a></li>
            <li><a href="mailto:nik.onsenspa@gmail.com">nik.onsenspa@gmail.com</a></li>
            <li><a href="#" onClick={(e)=>{e.preventDefault(); onGift();}}>{t("foot.gift")}</a></li>
            <li><a href="#">Instagram</a> · <a href="#">Facebook</a></li>
          </ul>
        </div>
      </div>
      <div className="foot-bottom">
        <div>© 2026 Nik Onsen Spa Cambodia</div>
        <div>日本のお風呂文化を、プノンペンで。</div>
        <div>Privacy · Terms</div>
      </div>
    </footer>
  );
}

function Tweaks({ tweaks, set }) {
  uE(() => {
    document.documentElement.style.setProperty("--brand-red", tweaks.accentRed);
    document.documentElement.style.setProperty("--cream", tweaks.background);
    document.documentElement.style.setProperty("--font-display", `"${tweaks.displayFont}", "Noto Serif JP", "Cormorant Garamond", Georgia, serif`);
  }, [tweaks]);
  return (
    <window.TweaksPanel title="Tweaks">
      <window.TweakSection label="Brand">
        <window.TweakColor label="Accent / Hanko Red" value={tweaks.accentRed} onChange={v => set('accentRed', v)} />
        <window.TweakColor label="Page Background" value={tweaks.background} onChange={v => set('background', v)} />
      </window.TweakSection>
      <window.TweakSection label="Typography">
        <window.TweakSelect label="Display Font" value={tweaks.displayFont} onChange={v => set('displayFont', v)}
          options={[
            { value: "Shippori Mincho", label: "Shippori Mincho" },
            { value: "Noto Serif JP", label: "Noto Serif JP" },
            { value: "Cormorant Garamond", label: "Cormorant Garamond" },
            { value: "Lora", label: "Lora" },
            { value: "Playfair Display", label: "Playfair" }
          ]} />
      </window.TweakSection>
      <window.TweakSection label="Hero">
        <window.TweakText label="CTA label override (blank = use translation)" value={tweaks.ctaLabel} onChange={v => set('ctaLabel', v)} />
        <window.TweakToggle label="Shoji grid behind hero" value={tweaks.showShojiGrid} onChange={v => set('showShojiGrid', v)} />
      </window.TweakSection>
    </window.TweaksPanel>
  );
}

function App() {
  const [bookOpen, setBookOpen] = uS(false);
  const [giftOpen, setGiftOpen] = uS(false);
  const [prefilled, setPrefilled] = uS(null);
  const [lang, setLangState] = uS(window.NIK_LANG || "EN");
  const [tweaks, setTweak] = window.useTweaks(TWEAK_DEFAULTS);

  uE(() => {
    const fn = () => setLangState(window.NIK_LANG);
    window.addEventListener("nik-lang-change", fn);
    return () => window.removeEventListener("nik-lang-change", fn);
  }, []);

  const openBook = (svcId) => { setPrefilled(svcId || null); setBookOpen(true); };

  return (
    <>
      <Nav onBook={() => openBook()} onGift={() => setGiftOpen(true)} lang={lang} />
      <Hero onBook={() => openBook()} tweaks={tweaks} />
      <Creds />
      <Onsen onBook={() => openBook("onsen-access")} />
      <Services onBookService={openBook} />
      <Atmosphere />
      <Pull />
      <Reviews />
      <Journal />
      <Visit onBook={() => openBook()} />
      <Footer onGift={() => setGiftOpen(true)} />
      <StickyCta onBook={() => openBook()} />
      <window.BookingDrawer open={bookOpen} onClose={() => setBookOpen(false)} prefilledServiceId={prefilled} />
      <window.GiftDrawer open={giftOpen} onClose={() => setGiftOpen(false)} />
      <Tweaks tweaks={tweaks} set={setTweak} />
    </>
  );
}

ReactDOM.createRoot(document.getElementById("app")).render(<App />);
