// House of Noey — Hero, Essay, Listings, Booking, About sections
const { useState: useState2, useEffect: useEffect2, useRef: useRef2, useMemo: useMemo2, useCallback: useCallback2 } = React;

// ——— Interaction hooks ———
// Helper: skip mouse-following effects on touch devices and when user prefers reduced motion.
const supportsHover = () => {
  if (typeof window === "undefined" || !window.matchMedia) return true;
  if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return false;
  return window.matchMedia("(hover: hover) and (pointer: fine)").matches;
};

function useMouseParallax(ref) {
  useEffect2(() => {
    const el = ref.current;
    if (!el) return;
    if (!supportsHover()) return;
    let raf = 0;
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      const x = (e.clientX - r.left - r.width / 2) / (r.width / 2);
      const y = (e.clientY - r.top - r.height / 2) / (r.height / 2);
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => {
        el.style.setProperty("--px", Math.max(-1, Math.min(1, x)).toFixed(3));
        el.style.setProperty("--py", Math.max(-1, Math.min(1, y)).toFixed(3));
      });
    };
    const onLeave = () => {
      el.style.setProperty("--px", "0");
      el.style.setProperty("--py", "0");
    };
    window.addEventListener("mousemove", onMove);
    el.addEventListener("mouseleave", onLeave);
    return () => {
      window.removeEventListener("mousemove", onMove);
      el.removeEventListener("mouseleave", onLeave);
      cancelAnimationFrame(raf);
    };
  }, []);
}

function useTilt(ref, intensity = 6) {
  useEffect2(() => {
    const el = ref.current;
    if (!el) return;
    if (!supportsHover()) return;
    let raf = 0;
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      const x = (e.clientX - r.left) / r.width;
      const y = (e.clientY - r.top) / r.height;
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => {
        el.style.setProperty("--rx", ((0.5 - y) * intensity).toFixed(2));
        el.style.setProperty("--ry", ((x - 0.5) * intensity).toFixed(2));
        el.style.setProperty("--mx", (x * 100).toFixed(1));
        el.style.setProperty("--my", (y * 100).toFixed(1));
      });
    };
    const onLeave = () => {
      el.style.setProperty("--rx", "0");
      el.style.setProperty("--ry", "0");
    };
    el.addEventListener("mousemove", onMove);
    el.addEventListener("mouseleave", onLeave);
    return () => {
      el.removeEventListener("mousemove", onMove);
      el.removeEventListener("mouseleave", onLeave);
      cancelAnimationFrame(raf);
    };
  }, [intensity]);
}

function useMagnetic(ref, pull = 0.35) {
  useEffect2(() => {
    const el = ref.current;
    if (!el) return;
    if (!supportsHover()) return;
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      const x = e.clientX - r.left - r.width / 2;
      const y = e.clientY - r.top - r.height / 2;
      el.style.transform = `translate3d(${(x * pull).toFixed(1)}px, ${(y * pull).toFixed(1)}px, 0)`;
    };
    const onLeave = () => { el.style.transform = ""; };
    el.addEventListener("mousemove", onMove);
    el.addEventListener("mouseleave", onLeave);
    return () => {
      el.removeEventListener("mousemove", onMove);
      el.removeEventListener("mouseleave", onLeave);
    };
  }, [pull]);
}

// Hook: returns true only if the image at `src` successfully loads.
// Gated by window.NOEY_USE_IMAGES so missing assets don't 404 the console.
// Flip the flag to true (in index.html) once you've added files under assets/img/.
function useImageLoads(src) {
  const [ok, setOk] = useState2(false);
  useEffect2(() => {
    if (!src || !window.NOEY_USE_IMAGES) { setOk(false); return; }
    const im = new Image();
    let cancelled = false;
    im.onload = () => { if (!cancelled) setOk(true); };
    im.onerror = () => { if (!cancelled) setOk(false); };
    im.src = src;
    return () => { cancelled = true; };
  }, [src]);
  return ok;
}

// ——— Hero ———
function Hero({ t }) {
  const heroRef = useRef2(null);
  return (
    <header className="hero" id="top" ref={heroRef}>
      <div className="shell">
        <div className="hero__grid">
          <div className="hero__copy">
            <div className="hero__eyebrow">
              <span className="dot"></span>
              <span className="eyebrow">{t.hero.eyebrow}</span>
            </div>
            <h1 className="hero__title">
              {t.hero.title[0]}<br/>
              {t.hero.title[1]}<br/>
              <em>{t.hero.title[2]}</em>
            </h1>
            <p className="hero__sub">{t.hero.sub}</p>
            <div className="hero__meta">
              {t.hero.meta.map((m, i) => (
                <div key={i}>
                  {m.l}
                  <strong>{m.v}</strong>
                </div>
              ))}
            </div>

            <div className="creds-strip">
              <span>Issue 14 · Sathorn</span>
              <span className="creds-strip__dot"></span>
              <span>Q1 2026</span>
              <span className="creds-strip__dot"></span>
              <span>By referral · LINE @noeyrealestate</span>
              <span className="creds-strip__dot"></span>
              <span style={{color:"var(--gold)"}}>3 of 4 mandates active</span>
            </div>
          </div>

          <div className="hero__portrait">
            <div className="hero__portrait-frame">
              <div className="hero__portrait-tilt">
                <img src="assets/noey-portrait.png" alt="Natcha Wiriyaporn, known as Noey" />
              </div>
            </div>
            {/* Floating data plates — outside the framed crop so they bleed past */}
            <div className="hero__plates" aria-hidden="true">
              <div className="hero__plate">
                <span className="l">Current issue</span>
                <span className="v">Sathorn,<span style={{fontSize: 11, color:"var(--ink-sec)", marginLeft: 6}}>№ 14</span></span>
              </div>
              <div className="hero__plate">
                <span className="l">Practice</span>
                <span className="v"><span className="gold">By</span> referral</span>
              </div>
              <div className="hero__plate">
                <span className="l">Languages</span>
                <span className="v">TH · EN · 中文</span>
              </div>
            </div>
            <div className="hero__portrait-caption">
              <span>Natcha Wiriyaporn · Noey · Bangkok · 2026</span>
              <span>Plate 01 / 14</span>
            </div>
          </div>
        </div>

        <div className="hero__scroll">
          <span className="line"></span>
          <span>{t.hero.scroll}</span>
        </div>
      </div>
    </header>
  );
}

// ——— Neighborhood Essay (signature scroll-triggered) ———
function NeighborhoodEssay({ t, onComplete }) {
  const ref = useRef2(null);
  const [progress, setProgress] = useState2(0);
  const [inView, setInView] = useState2(false);
  useEffect2(() => {
    if (!ref.current) return;
    let fired = false;
    const onScroll = () => {
      const r = ref.current.getBoundingClientRect();
      const vh = window.innerHeight;
      const total = r.height + vh;
      const seen = Math.max(0, Math.min(total, vh - r.top));
      const p = Math.max(0, Math.min(1, seen / total));
      setProgress(p);
      setInView(r.top < vh * 0.6 && r.bottom > vh * 0.4);
      if (p > 0.8 && !fired) { fired = true; onComplete && onComplete(); }
    };
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, [onComplete]);

  const photoBgs = ["placeholder placeholder--soi", "placeholder placeholder--noir"];

  return (
    <>
      <section className="section essay-section" id="essay" ref={ref}>
        <div className="shell story-book">
          <div className="section__head story-book__head">
            <div>
              <div className="section__num">02 / The Essay</div>
              <Reveal as="div" className="eyebrow eyebrow-gold" style={{marginTop:8}}>{t.essay.eyebrow}</Reveal>
              <Reveal as="h2" className="section__title" style={{marginTop:16}}>{t.essay.title}</Reveal>
            </div>
            <Reveal as="div" delay={120}>
              <div className="eyebrow">{t.essay.author}</div>
              <div className="eyebrow" style={{marginTop:8}}>{t.essay.readtime}</div>
              <div style={{
                marginTop: 24, height: 2, width: "100%",
                background: "var(--rule)", position: "relative"
              }}>
                <div style={{
                  position: "absolute", inset: 0, width: `${progress * 100}%`,
                  background: "var(--gold)", transition: "width 200ms linear"
                }}/>
              </div>
              <div className="eyebrow" style={{marginTop:10}}>Reading progress · {Math.round(progress*100)}%</div>
            </Reveal>
          </div>
          <div className="story-book__body">
            <aside className="story-book__toc" aria-label="Essay chapters">
              <span className="story-book__toc-label">Chapters</span>
              {t.essay.sections.map((s, i) => (
                <a key={i} href={`#essay-chapter-${i + 1}`}>
                  <span>{String(i + 1).padStart(2, "0")}</span>
                  {s.label}
                </a>
              ))}
            </aside>
            <div className="essay story-book__pages">
              <div className="essay__col">
                {t.essay.sections.map((s, i) => (
                  <EssaySection key={i} s={s} idx={i} photoBg={photoBgs[i % photoBgs.length]} />
                ))}
              </div>
            </div>
          </div>
        </div>
      </section>

      {/* Floating reading chip — fixed bottom-left */}
      <div className={`read-chip ${inView ? "is-on" : ""}`} aria-hidden={!inView}>
        <span className="read-chip__dot"></span>
        <span className="read-chip__label">
          Reading · <span className="gold">{t.essay.eyebrow}</span>
        </span>
        <span className="read-chip__bar"><i style={{ "--p": `${progress * 100}%` }}></i></span>
        <span>{Math.round(progress * 100)}%</span>
      </div>
    </>
  );
}

function EssaySection({ s, idx, photoBg }) {
  const ref = useRef2(null);
  const [seen, setSeen] = useState2(false);
  const photoImgOk = useImageLoads(s.photo?.img);
  useEffect2(() => {
    if (!ref.current) return;
    const io = new IntersectionObserver(
      (e) => e.forEach(x => { if (x.isIntersecting) { setSeen(true); io.disconnect(); }}),
      { threshold: 0.15, rootMargin: "0px 0px -60px 0px" }
    );
    io.observe(ref.current);
    return () => io.disconnect();
  }, []);

  // Replace inline data-chip placeholders in body strings with React chips
  const renderPara = (text) => {
    const parts = text.split(/(REIC_YIELD_PLACEHOLDER|FOREIGN_QUOTA_PLACEHOLDER)/g);
    return parts.map((p, i) => {
      if (p === "REIC_YIELD_PLACEHOLDER")    return <span key={i} className="essay__chip">REIC 4.8%</span>;
      if (p === "FOREIGN_QUOTA_PLACEHOLDER") return <span key={i} className="essay__chip">31% avg headroom</span>;
      return <React.Fragment key={i}>{p}</React.Fragment>;
    });
  };

  return (
    <article id={`essay-chapter-${idx + 1}`} ref={ref} className={`essay__section ${seen ? "is-in" : ""}`}>
      <div className="essay__marker">
        <span className="essay__marker-num">§ {idx + 1}</span>
        <span className="essay__marker-rule"></span>
        <span className="essay__marker-label">{s.label}</span>
      </div>
      <h3 className="essay__heading">{s.heading}</h3>
      <div className="essay__body">
        {s.body.map((p, i) => <p key={i}>{renderPara(p)}</p>)}
      </div>
      {s.pull && (
        <blockquote className={`essay__pullquote ${seen ? "is-in" : ""}`}>
          {s.pull}
        </blockquote>
      )}
      {s.photo && (
        <figure className="essay__photo">
          <div className="essay__photo-frame">
            {photoImgOk ? (
              <img src={s.photo.img} alt={s.photo.cap} />
            ) : (
              <div className={photoBg}>Editorial photo placeholder</div>
            )}
          </div>
          <figcaption className="essay__photo-cap">
            <span>{s.photo.cap}</span>
            <span>· {s.photo.time}</span>
            <span>· Plate {String(idx + 2).padStart(2, "0")} / 14</span>
          </figcaption>
        </figure>
      )}
    </article>
  );
}

// ——— Property listings ———
const CURRENCIES = {
  THB: { sym: "฿", rate: 1, label: "THB" },
  USD: { sym: "$", rate: 0.0282, label: "USD" },
  CNY: { sym: "¥", rate: 0.204, label: "CNY" },
  JPY: { sym: "¥", rate: 4.30, label: "JPY" }
};

function fmtMoney(thb, cur) {
  if (!Number.isFinite(Number(thb)) || Number(thb) <= 0) return "Ask";
  const { sym, rate } = CURRENCIES[cur];
  const v = thb * rate;
  if (cur === "JPY") return `${sym}${Math.round(v / 1000)}k`;
  if (cur === "THB") return `${sym}${(v / 1000000).toFixed(2)}M`;
  return `${sym}${(v / 1000).toFixed(1)}k`;
}

function FeaturedListingsCarousel({ currency }) {
  const [items, setItems] = useState2(() => window.HONListingStore ? window.HONListingStore.all() : window.I18N.en.listings.items);
  useEffect2(() => {
    const sync = () => setItems(window.HONListingStore ? window.HONListingStore.all() : window.I18N.en.listings.items);
    window.addEventListener("hon:listings-updated", sync);
    window.addEventListener("storage", sync);
    return () => {
      window.removeEventListener("hon:listings-updated", sync);
      window.removeEventListener("storage", sync);
    };
  }, []);
  return (
    <section className="featured-listings" aria-label="Featured property listings">
      <div className="shell featured-listings__inner">
        <div className="featured-listings__copy">
          <div className="section__num">Current files</div>
          <h2>Properties first, poetry second.</h2>
          <p>Start with the homes on Noey's desk, then read the neighborhood context if one of them feels close.</p>
        </div>
        <div className="featured-listings__rail" tabIndex="0" aria-label="Scrollable listing carousel">
          {items.slice(0, 8).map((it) => {
            const href = window.HONListingStore?.detailHref ? window.HONListingStore.detailHref(it) : `listing.html?listing=${encodeURIComponent(it.slug || it.id || it.n)}`;
            return (
              <a className="featured-card glass" href={href} key={it.id || it.n}>
                <span className="featured-card__tag">{it.tag}</span>
                <img src={it.heroImage || it.img} alt={it.title} />
                <span className="featured-card__title">{it.title}</span>
                <span className="featured-card__meta">{fmtMoney(it.price, currency)} · {it.sqm} sqm · {it.bts} min BTS</span>
              </a>
            );
          })}
        </div>
      </div>
    </section>
  );
}

function Listings({ t, currency, setCurrency }) {
  const [items, setItems] = useState2(() => window.HONListingStore ? window.HONListingStore.all() : window.I18N.en.listings.items);
  useEffect2(() => {
    const sync = () => setItems(window.HONListingStore ? window.HONListingStore.all() : window.I18N.en.listings.items);
    window.addEventListener("hon:listings-updated", sync);
    window.addEventListener("storage", sync);
    return () => {
      window.removeEventListener("hon:listings-updated", sync);
      window.removeEventListener("storage", sync);
    };
  }, []);
  const placeholderBgs = [
    "placeholder",
    "placeholder placeholder--soi",
    "placeholder placeholder--noir",
    "placeholder placeholder--gold",
    "placeholder placeholder--soi",
    "placeholder"
  ];
  return (
    <section className="section section--surface" id="listings">
      <div className="shell">
        <div className="section__head">
          <div>
            <div className="section__num">03 / Currently Advising</div>
            <Reveal as="h2" className="section__title">{t.listings.title}</Reveal>
          </div>
          <Reveal as="div" delay={120}>
            <p className="section__intro">{t.listings.intro}</p>
            <div className="listing-tools">
              <span className="eyebrow">Currency</span>
              <div className="currency">
                {Object.keys(CURRENCIES).map(c => (
                  <button key={c} data-active={currency === c} onClick={() => setCurrency(c)}>
                    {c}
                  </button>
                ))}
              </div>
              <a className="listing-tools__admin" href="admin.html">Admin</a>
            </div>
          </Reveal>
        </div>

        <div className={`listings listings--count-${items.length}`}>
          {items.map((it, i) => (
            <ListingRow key={it.id || it.n} it={it} i={i} total={items.length} t={t} currency={currency} placeholderBg={placeholderBgs[i % placeholderBgs.length]} />
          ))}
        </div>
      </div>
    </section>
  );
}

function ListingRow({ it, i, total, t, currency, placeholderBg }) {
  const photoRef = useRef2(null);
  useTilt(photoRef, 7);
  const imgOk = useImageLoads(it.heroImage || it.img);
  const href = window.HONListingStore?.detailHref ? window.HONListingStore.detailHref(it) : `listing.html?listing=${encodeURIComponent(it.slug || it.id || it.n)}`;
  return (
    <Reveal className="listing" delay={i * 60}>
      <div className="listing__photo tilt" ref={photoRef}>
        {imgOk ? (
          <a href={href} aria-label={`Open ${it.title}`}>
            <img src={it.heroImage || it.img} alt={it.title} />
          </a>
        ) : (
          <div className={placeholderBg}>
            Placeholder · {it.title.split(" ").slice(0, 3).join(" ")}…
          </div>
        )}
        <div className={`listing__badge ${it.tag.includes("Off") ? "listing__badge--gold" : ""}`}>
          {it.tag}
        </div>
      </div>
      <div>
        <div className="listing__num">No. {it.n} · {String(total).padStart(2, "0")}</div>
        <h3 className="listing__title">{it.title}</h3>
        <p className="listing__desc">{it.desc}</p>
        <div className="listing__price">
          {fmtMoney(it.price, currency)} <small>· asking</small>
        </div>
        <div className="listing__data">
          <div>{currency} / sqm<span className="v">{fmtMoney(it.price / it.sqm, currency)}</span></div>
          <div>Size<span className="v">{it.sqm} sqm</span></div>
          <div>BTS<span className="v">{it.bts} min</span></div>
          <div>Aspect<span className="v">{it.aspect}</span></div>
          <div>Built<span className="v">{it.year}</span></div>
        </div>
        <a className="listing__cta" href={href}>
          <span>{t.listings.cta}</span>
          <span>→</span>
        </a>
      </div>
    </Reveal>
  );
}

// ——— About Noey ———
function About({ t }) {
  return (
    <section className="section" id="about">
      <div className="shell">
        <div className="section__head">
          <div>
            <div className="section__num">05 / About</div>
            <Reveal as="h2" className="section__title">{t.about.title}</Reveal>
          </div>
          <Reveal as="p" className="section__intro" delay={120}>
            <span className="f-italic" style={{fontSize:"1.15em", color:"var(--ink)"}}>"{t.about.personal}"</span>
          </Reveal>
        </div>
        <div className="about about--video">
          <Reveal className="about__media glass">
            <div className="about__video-frame">
              <video
                src="assets/video/noey-own-words.mp4"
                poster="assets/img/noey-own-words-poster.jpg"
                muted
                autoPlay
                loop
                playsInline
                preload="metadata"
                aria-label="Natcha Wiriyaporn, known as Noey, guiding clients through a Bangkok property listing."
              />
              <div className="about__video-shade" aria-hidden="true"></div>
              <div className="about__video-label">
                <span>Field note</span>
                <strong>In her own words</strong>
              </div>
            </div>
            <div className="about__media-meta">
              <span>720p field note</span>
              <span>Sathorn morning</span>
              <span>Client walk-through</span>
            </div>
          </Reveal>
          <Reveal className="about__body" delay={100}>
            {t.about.body.map((p, i) => <p key={i}>{p}</p>)}
            <div className="about__stats">
              {(window.I18N.en.about.stats).map((s, i) => (
                <div key={i}>
                  <span className="v">{s.v}<sup>{s.sup}</sup></span>
                  <span className="l">{s.l}</span>
                </div>
              ))}
            </div>
            <div className="about__sig">
              <div className="name">{t.about.sig}</div>
              <small>Noey · Property Guide · Bangkok</small>
            </div>
          </Reveal>
        </div>
      </div>
    </section>
  );
}

// ——— Booking calendar (Calendly-style) ———
function BookingCard({ t, revealed }) {
  const now = new Date();
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
  const [view, setView] = useState2(() => new Date(today.getFullYear(), today.getMonth(), 1));
  const [selDate, setSelDate] = useState2(null);
  const [selTime, setSelTime] = useState2(null);
  const [done, setDone] = useState2(false);
  const [guest, setGuest] = useState2({ name: "", contact: "", note: "" });
  const [bookingStatus, setBookingStatus] = useState2("");
  const ctaRef = useRef2(null);
  useMagnetic(ctaRef, 0.35);
  const contact = window.HON_CONTACT || {};
  const booking = contact.booking || {};
  const availableWeekdays = new Set(booking.availableWeekdays || [1, 2, 3, 4, 5]);
  const unavailableDates = new Set(booking.unavailableDates || []);
  const daysAhead = Number(booking.daysAhead) || 60;
  const meetingLengthMinutes = Number(booking.meetingLengthMinutes) || 30;
  const lastBookable = new Date(today);
  lastBookable.setDate(today.getDate() + daysAhead);
  const keyDate = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;

  const monthMatrix = useMemo2(() => {
    const y = view.getFullYear(), m = view.getMonth();
    const first = new Date(y, m, 1);
    const daysInMonth = new Date(y, m + 1, 0).getDate();
    const startDow = (first.getDay() + 6) % 7; // Mon-first
    const cells = [];
    for (let i = 0; i < startDow; i++) cells.push({ out: true, d: 0 });
    for (let d = 1; d <= daysInMonth; d++) {
      const dt = new Date(y, m, d);
      const past = dt < today;
      const weekend = dt.getDay() === 0 || dt.getDay() === 6;
      const outsideWindow = dt > lastBookable;
      const disabled = past || outsideWindow || !availableWeekdays.has(dt.getDay()) || unavailableDates.has(keyDate(dt));
      cells.push({
        out: false, d, dt,
        disabled, weekend,
        hasSlots: !disabled
      });
    }
    while (cells.length % 7 !== 0) cells.push({ out: true, d: 0 });
    return cells;
  }, [view, daysAhead]);

  const fmtDate = (d) => `${t.booking.months[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`;
  const message = window.HON_makeContactText ? window.HON_makeContactText({
    date: selDate ? fmtDate(selDate) : "",
    time: selTime,
    name: guest.name,
    contact: guest.contact,
    note: guest.note
  }) : "";
  const encodedMessage = encodeURIComponent(message || "House of Noey enquiry");
  const mailHref = `mailto:${contact.email || "noey@houseofnoey.com"}?subject=${encodeURIComponent("House of Noey booking")}&body=${encodedMessage}`;
  const lineHref = `${contact.lineUrl || "https://line.me/R/ti/p/@noeyrealestate"}?text=${encodedMessage}`;
  const whatsAppHref = `${contact.whatsappUrl || "https://wa.me/66812345678"}?text=${encodedMessage}`;
  const calendarHref = (() => {
    if (!selDate || !selTime) return "#";
    const [hh, mm] = selTime.split(":").map(Number);
    const start = new Date(selDate);
    start.setHours(hh, mm || 0, 0, 0);
    const end = new Date(start.getTime() + meetingLengthMinutes * 60 * 1000);
    const stamp = (d) => d.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
    const ics = [
      "BEGIN:VCALENDAR",
      "VERSION:2.0",
      "PRODID:-//House of Noey//Booking//EN",
      "BEGIN:VEVENT",
      `UID:${Date.now()}@houseofnoey.com`,
      `DTSTAMP:${stamp(new Date())}`,
      `DTSTART:${stamp(start)}`,
      `DTEND:${stamp(end)}`,
      "SUMMARY:House of Noey coffee conversation",
      `DESCRIPTION:${message.replace(/\n/g, "\\n")}`,
      `LOCATION:${contact.location || "Bangkok"}`,
      "END:VEVENT",
      "END:VCALENDAR"
    ].join("\r\n");
    return `data:text/calendar;charset=utf-8,${encodeURIComponent(ics)}`;
  })();

  const canConfirm = Boolean(selDate && selTime && guest.name.trim() && guest.contact.trim());
  const isCurrentMonth = view.getFullYear() === today.getFullYear() && view.getMonth() === today.getMonth();
  const confirm = async () => {
    if (!canConfirm) return;
    setDone(true);
    setBookingStatus("");
    if (!contact.bookingWebhook) return;
    try {
      await fetch(contact.bookingWebhook, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          date: selDate ? fmtDate(selDate) : "",
          time: selTime,
          guest,
          createdAt: new Date().toISOString(),
          source: "house-of-noey-static-site"
        })
      });
      setBookingStatus("Noey's desk has received the request.");
    } catch (e) {
      setBookingStatus("The request is saved here. Please also send it by LINE, WhatsApp, or email.");
    }
  };

  return (
    <section className="section" id="booking" style={{ paddingTop: 0 }}>
      <div className="shell">
        <Reveal className="booking" style={{
          opacity: revealed ? 1 : 0.45,
          transform: revealed ? "translateY(0)" : "translateY(20px)",
          transition: "opacity 600ms, transform 600ms"
        }}>
          <span className="booking__corner tl"></span>
          <span className="booking__corner tr"></span>
          <span className="booking__corner bl"></span>
          <span className="booking__corner br"></span>

          <div>
            <div className="booking__eyebrow">{t.cta.eyebrow}</div>
            <h2 className="booking__title">
              {t.cta.title}<br/>
              <em>{t.cta.titleEm}</em>
            </h2>
            <p className="booking__desc">{t.cta.body}</p>
            <div className="booking__sig">{t.cta.sig}</div>
            <div className="booking__sig-line">— {t.cta.sigLine}</div>
            <div style={{ display: "flex", gap: 14, alignItems: "center", flexWrap: "wrap" }}>
              <span className="magnetic" ref={ctaRef}>
                <a className="btn" href="#booking-cal">
                  <span>{t.cta.button}</span>
                  <span>→</span>
                </a>
              </span>
              <span className="eyebrow">{t.cta.tagline}</span>
            </div>
          </div>

          <div className="booking__cal" id="booking-cal">
            {!done ? (
              <>
                <div className="booking__cal-head">
                  <h4>{t.booking.months[view.getMonth()]} {view.getFullYear()}</h4>
                  <div style={{display:"flex", gap:8}}>
                    <button disabled={isCurrentMonth} onClick={() => setView(new Date(view.getFullYear(), view.getMonth() - 1, 1))} aria-label="prev"
                      style={{padding:"4px 8px", border:"1px solid var(--rule)", fontFamily:"var(--f-mono)", fontSize:11}}>‹</button>
                    <button onClick={() => setView(new Date(view.getFullYear(), view.getMonth() + 1, 1))} aria-label="next"
                      style={{padding:"4px 8px", border:"1px solid var(--rule)", fontFamily:"var(--f-mono)", fontSize:11}}>›</button>
                  </div>
                </div>
                <div className="cal-grid">
                  {t.booking.dow.map(d => <div key={d} className="dow">{d}</div>)}
                  {monthMatrix.map((c, i) => (
                    <div
                      key={i}
                      className={`cal-day ${c.out ? "is-out" : ""} ${c.disabled ? "is-disabled" : "is-available"} ${selDate && selDate.getDate() === c.d && selDate.getMonth() === view.getMonth() ? "is-active" : ""}`}
                      onClick={() => { if (!c.out && !c.disabled) { setSelDate(c.dt); setSelTime(null); }}}
                    >
                      {c.out ? "" : c.d}
                    </div>
                  ))}
                </div>
                {selDate && (
                  <>
                    <div className="cal-slots">
                      {t.booking.slots.map(s => (
                        <button key={s}
                          className={`cal-slot ${selTime === s ? "is-active" : ""}`}
                          onClick={() => setSelTime(s)}>{s}</button>
                      ))}
                    </div>
                    <div className="booking-fields">
                      <input value={guest.name} onChange={(e) => setGuest({...guest, name: e.target.value})} placeholder="Your name" />
                      <input value={guest.contact} onChange={(e) => setGuest({...guest, contact: e.target.value})} placeholder="LINE, WhatsApp, or email" />
                      <textarea value={guest.note} onChange={(e) => setGuest({...guest, note: e.target.value})} placeholder="Neighborhood or listing you want to discuss" rows="3"></textarea>
                    </div>
                  </>
                )}
                <div className="cal-confirm">
                  <div>
                    {selDate ? <><strong>{fmtDate(selDate)}</strong>{selTime ? `, ${selTime}` : ` · ${t.booking.pickTime}`}</> : t.booking.pickDate}
                  </div>
                  <button className="cal-confirm-btn" disabled={!canConfirm} onClick={confirm}>
                    {t.booking.confirm}
                  </button>
                  {selDate && selTime && (!guest.name.trim() || !guest.contact.trim()) && (
                    <small className="cal-confirm__hint">Add your name and contact to confirm.</small>
                  )}
                </div>
              </>
            ) : (
              <div style={{textAlign:"center", padding:"36px 12px"}}>
                <div style={{
                  width: 56, height: 56, borderRadius: "50%",
                  background: "var(--gold-soft)", border: "1px solid var(--gold)",
                  display: "inline-flex", alignItems: "center", justifyContent: "center",
                  color: "var(--gold)", fontSize: 26, marginBottom: 18
                }}>✓</div>
                <div className="f-display" style={{fontSize: 28, marginBottom: 8}}>{t.booking.booked}</div>
                <div style={{fontSize: 14, color: "var(--ink-sec)", marginBottom: 14}}>
                  {fmtDate(selDate)}, {selTime}
                </div>
                <div style={{fontSize: 13, color: "var(--ink-sec)", maxWidth: 320, margin: "0 auto"}}>
                  {bookingStatus || t.booking.bookedDesc}
                </div>
                <div className="booking-actions">
                  <a href={lineHref} target="_blank" rel="noopener">Open LINE</a>
                  <a href={whatsAppHref} target="_blank" rel="noopener">WhatsApp</a>
                  <a href={mailHref}>Email Noey</a>
                  <a href={calendarHref} download="house-of-noey-booking.ics">Add to calendar</a>
                </div>
              </div>
            )}
          </div>
        </Reveal>
      </div>
    </section>
  );
}

Object.assign(window, {
  Hero, NeighborhoodEssay, FeaturedListingsCarousel, Listings, About, BookingCard, CURRENCIES, fmtMoney
});
