// digital-af-app.jsx — DIGITAL AF teaser / wishlist landing.
// Depends on window.FXLayer, window.useTweaks + Tweak* controls.

/* ----------------------------------------------------------------------------
   STORAGE
   Emails are saved to localStorage on this device, and (optionally) POSTed to a
   shared backend if you paste a URL into ENDPOINT below. The admin page
   (admin.html) reads the same localStorage key to show / export the list.
---------------------------------------------------------------------------- */
const STORAGE_KEY = "digitalaf_wishlist_v1";
// To collect emails from real visitors across devices, paste ONE endpoint URL
// here (Formspree form URL, Google Apps Script web-app URL, or Supabase REST).
// Leave "" to keep everything local-only for now.
const ENDPOINT = "";

function loadList() {
  try { return JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]"); }
  catch { return []; }
}
function persist(list) {
  localStorage.setItem(STORAGE_KEY, JSON.stringify(list));
}
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

async function submitEmail(rawEmail) {
  const email = rawEmail.trim().toLowerCase();
  if (!EMAIL_RE.test(email)) return { ok: false, reason: "invalid" };
  const list = loadList();
  if (list.some((e) => (e.email || "").toLowerCase() === email)) {
    return { ok: false, reason: "duplicate" };
  }
  const entry = {
    email,
    date: new Date().toISOString(),
    source: "landing",
  };
  list.push(entry);
  persist(list);

  if (ENDPOINT) {
    try {
      await fetch(ENDPOINT, {
        method: "POST",
        headers: { "Content-Type": "application/json", Accept: "application/json" },
        body: JSON.stringify(entry),
      });
    } catch (e) { /* still saved locally; non-fatal */ }
  }
  return { ok: true };
}

/* ----------------------------------------------------------------------------
   WISHLIST FORM
---------------------------------------------------------------------------- */
function WishlistForm({ layout }) {
  const [email, setEmail] = React.useState("");
  const [state, setState] = React.useState("idle"); // idle | sending | done | error
  const [msg, setMsg] = React.useState("");

  async function onSubmit(e) {
    e.preventDefault();
    if (state === "sending" || state === "done") return;
    if (!EMAIL_RE.test(email.trim())) {
      setState("error"); setMsg("Please enter a valid email address.");
      return;
    }
    setState("sending"); setMsg("");
    const res = await submitEmail(email);
    if (res.ok) {
      setState("done");
      setMsg("Thank you. You're on the list.");
    } else if (res.reason === "duplicate") {
      setState("done");
      setMsg("You're already on the list. We'll be in touch.");
    } else {
      setState("error"); setMsg("Please enter a valid email address.");
    }
  }

  const stacked = layout === "vitrine";

  if (state === "done") {
    return (
      <div className="wl-done" role="status">
        <span className="wl-done__tick" aria-hidden="true">
          <svg viewBox="0 0 24 24" width="18" height="18" fill="none"
               stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round">
            <path d="M4 12.5l5 5L20 6" />
          </svg>
        </span>
        <span className="wl-done__txt">{msg}</span>
      </div>
    );
  }

  return (
    <form className={`wl-form wl-form--${stacked ? "stacked" : "inline"}`} onSubmit={onSubmit} noValidate>
      <div className="wl-field">
        <input
          type="email"
          inputMode="email"
          autoComplete="email"
          placeholder="Enter your email"
          aria-label="Email address"
          value={email}
          onChange={(e) => { setEmail(e.target.value); if (state === "error") setState("idle"); }}
          className={state === "error" ? "is-error" : ""}
        />
        <button type="submit" disabled={state === "sending"}>
          <span>{state === "sending" ? "Joining…" : "Join the Wishlist"}</span>
          <svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor"
               strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
            <path d="M5 12h14M13 6l6 6-6 6" />
          </svg>
        </button>
      </div>
      <div className={`wl-msg ${state === "error" ? "is-error" : ""}`}>
        {msg || "Drops · private previews · opening. No spam — unsubscribe anytime."}
      </div>
    </form>
  );
}

/* ----------------------------------------------------------------------------
   SHARED BRAND PIECES
---------------------------------------------------------------------------- */
function Kicker() {
  return (
    <div className="kicker">
      <span className="kicker__dot" />
      <span>SEOUL · 연희동</span>
      <span className="kicker__sep">/</span>
      <span>WISHLIST ACCESS</span>
    </div>
  );
}

function Wordmark({ small }) {
  return (
    <div className={`wordmark ${small ? "wordmark--sm" : ""}`}>
      <h1 className="wordmark__en">DIGITAL&nbsp;AF</h1>
      <span className="wordmark__kr">화합</span>
    </div>
  );
}

function VitrineRail() {
  return (
    <div className="rail" aria-hidden="true">
      <span>DIGITAL</span>
      <span>PHYSICAL</span>
      <span>WISHLIST</span>
      <svg className="rail__bolt" viewBox="0 0 24 24" width="22" height="22" fill="currentColor">
        <path d="M13 2L4 14h6l-1 8 9-12h-6l1-8z" />
      </svg>
    </div>
  );
}

function Socials() {
  const items = [
    { k: "ig", path: "M12 8.5a3.5 3.5 0 100 7 3.5 3.5 0 000-7zM17.5 6.5h.01M4 8a4 4 0 014-4h8a4 4 0 014 4v8a4 4 0 01-4 4H8a4 4 0 01-4-4V8z" },
    { k: "x", path: "M4 4l7 9-7 7M20 4l-7 9 7 7", custom: "x" },
    { k: "dc", path: "M8 12a1 1 0 100 .01M16 12a1 1 0 100 .01M7 8c4-1.5 6-1.5 10 0l1.5 9c-1.5 1.2-3 2-4.5 2.2l-.8-1.6M7 8L5.5 17c1.3 1.1 2.7 1.8 4 2l.8-1.6" },
  ];
  return (
    <nav className="socials" aria-label="Social links">
      {items.map((it) => (
        <a key={it.k} href="#" onClick={(e) => e.preventDefault()} aria-label={it.k}>
          {it.custom === "x" ? (
            <svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true">
              <path d="M17.5 3h3l-7.2 8.2L22 21h-6.3l-4.9-6.4L5 21H2l7.7-8.8L2 3h6.4l4.4 5.9L17.5 3zm-1.1 16h1.7L7.7 4.8H5.9L16.4 19z" />
            </svg>
          ) : (
            <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor"
                 strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
              <path d={it.path} />
            </svg>
          )}
        </a>
      ))}
    </nav>
  );
}

const BODY_LINE =
  "Join the wishlist to be the first to access upcoming drops, private previews and the official store opening.";

/* ----------------------------------------------------------------------------
   LAYOUTS
---------------------------------------------------------------------------- */
function LayoutCentered({ tagline, showEnter, onEnter }) {
  return (
    <div className="layout layout--centered" data-screen-label="Centered Portal">
      <div className="stack">
        <Kicker />
        <Wordmark />
        <p className="tagline">{tagline}</p>
        <p className="body">{BODY_LINE}</p>
        <WishlistForm layout="centered" />
        {showEnter && <EnterButton onEnter={onEnter} />}
      </div>
    </div>
  );
}

function LayoutLowerThird({ tagline, showEnter, onEnter }) {
  return (
    <div className="layout layout--lower" data-screen-label="Lower-Third Card">
      <VitrineRail />
      <div className="lower-content">
        <Kicker />
        <Wordmark />
        <p className="tagline">{tagline}</p>
        <p className="body">{BODY_LINE}</p>
        <WishlistForm layout="lower" />
        {showEnter && <EnterButton onEnter={onEnter} />}
      </div>
    </div>
  );
}

function LayoutVitrine({ tagline, showEnter, onEnter }) {
  return (
    <div className="layout layout--vitrine" data-screen-label="Framed Vitrine">
      <div className="vitrine">
        <div className="vitrine__top">
          <Kicker />
          <span className="vitrine__bolt" aria-hidden="true">
            <svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor">
              <path d="M13 2L4 14h6l-1 8 9-12h-6l1-8z" />
            </svg>
          </span>
        </div>
        <Wordmark small />
        <p className="tagline">{tagline}</p>
        <p className="body">{BODY_LINE}</p>
        <WishlistForm layout="vitrine" />
        {showEnter && <EnterButton onEnter={onEnter} />}
      </div>
    </div>
  );
}

/* ----------------------------------------------------------------------------
   ENTER (dev) BUTTON
---------------------------------------------------------------------------- */
function EnterButton({ onEnter }) {
  return (
    <button type="button" className="enter-cta" onClick={onEnter}>
      <svg className="enter-cta__bolt" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M13 2L4 14h6l-1 8 9-12h-6l1-8z" /></svg>
      <span>Enter the Pop-Up</span>
      <span className="enter-cta__dev">DEV</span>
    </button>
  );
}

/* ----------------------------------------------------------------------------
   TRANSITION VIDEO (exterior → interior)
---------------------------------------------------------------------------- */
function TransitionVideo({ onDone, poster }) {
  const ref = React.useRef(null);
  const [out, setOut] = React.useState(false);
  const [on, setOn] = React.useState(false);
  const doneRef = React.useRef(false);

  React.useEffect(() => {
    const v = ref.current;
    if (!v) return;
    const finish = () => {
      if (doneRef.current) return;
      doneRef.current = true;
      setOut(true);            // fade the video out, revealing the interior beneath
      setTimeout(onDone, 560);
    };
    let retried = false;
    let started = false;

    // The magic trick: keep the video PAUSED on its first frame while the hero photo shows.
    // Then at the moment of reveal, start the video AND fade it in simultaneously, so the
    // static photo seamlessly becomes the moving video from the very first frame.
    const armStart = () => {
      if (started) return;
      started = true;
      try { v.currentTime = 0; } catch (e) {}
      v.pause();
      // Tiny breath (~120ms) so the eye registers the photo before motion begins.
      setTimeout(() => {
        const p = v.play();
        if (p && p.catch) p.catch(() => {});
        setOn(true);  // crossfade kicks off at the exact moment playback starts
      }, 120);
    };

    v.addEventListener("loadeddata", armStart);
    v.addEventListener("canplay", armStart);
    v.addEventListener("ended", finish);
    v.addEventListener("error", () => {
      if (!retried) { retried = true; try { v.load(); } catch (e) {} }
      else { setTimeout(finish, 400); }
    });
    // If the video is already ready (e.g. from preload cache), arm immediately.
    if (v.readyState >= 2) armStart();

    // Hard safety cap only — covers a video that never fires "ended"
    const tCap = setTimeout(finish, 15000);
    return () => clearTimeout(tCap);
  }, []);

  return (
    <div className={`vstage ${out ? "is-out" : ""}`} style={{ backgroundImage: poster ? `url(${poster})` : "none" }}>
      <video ref={ref} className={on ? "is-on" : ""} muted playsInline autoPlay preload="auto">
        {/* 4K MP4 (~18MB) listed FIRST so modern browsers pick it for quality. The 720p WebM
            stays as fallback for older browsers / bandwidth-constrained clients. */}
        <source src="assets/transition.mp4" type="video/mp4" />
        <source src={TRANSITION_VIDEO} type="video/webm" />
      </video>
      <button type="button" className="vstage__skip" onClick={() => { doneRef.current = true; setOut(true); setTimeout(onDone, 300); }}>Skip →</button>
    </div>
  );
}

/* ----------------------------------------------------------------------------
   INTERIOR GALLERY
---------------------------------------------------------------------------- */
const GX_ITEMS = [
  { id: "book", img: ITEM_BOOK, title: "Antoine Grenez Photo Book", kicker: "Object 02 — Print",
    price: 180, currency: "USD", sizes: null,
    description: "Photo book by Antoine Grenez. Limited edition print." },
  { id: "shoe", img: ITEM_SHOE, title: "Aaron Fowler\u2019s Moon Shoes", kicker: "Object 01 — Footwear",
    price: 1200, currency: "USD",
    productImage: "assets/product_shoe.png",
    sizes: ["US 7","US 7.5","US 8","US 8.5","US 9","US 9.5","US 10","US 10.5","US 11","US 11.5","US 12","US 13"],
    description: "Hand-finished sculptural footwear by Aaron Fowler. Each pair signed and numbered." },
  { id: "ball", img: ITEM_BALL, title: "Mia Basketball", kicker: "Object 03 — Sport" },
];
const GX_SLOTS = {
  center: { x: 51.1, y: 50.2, w: 19.6, op: 1,   br: 1 },
  left:   { x: 13.25, y: 56.25, w: 20.5, op: .82, br: .72 },
  right:  { x: 83.5, y: 31.8, w: 12.6, op: .82, br: .72 },
};
const GX_DEFAULT = { book: "left", shoe: "center", ball: "right" };

function fmtPrice(n, cur) {
  const sym = cur === "EUR" ? "€" : cur === "USD" ? "$" : (cur + " ");
  return sym + n.toLocaleString("en-US");
}

const ORDERS_STORAGE_KEY = "digitalaf_orders_v1";
function saveOrder(order) {
  try {
    const list = JSON.parse(localStorage.getItem(ORDERS_STORAGE_KEY) || "[]");
    list.push({ ...order, id: Date.now() + "-" + Math.random().toString(36).slice(2, 7), createdAt: new Date().toISOString() });
    localStorage.setItem(ORDERS_STORAGE_KEY, JSON.stringify(list));
  } catch (e) {}
}

/* ----------------------------------------------------------------------------
   BUY MODAL — placeholder pre-Stripe.
   Saves the order intent to localStorage so we have data while the real payment
   backend isn't wired yet. Swap saveOrder() with Stripe Checkout / Payment Link
   when ready.
---------------------------------------------------------------------------- */
const COUNTRIES = ["France", "United States", "United Kingdom", "Germany", "Italy", "Spain", "Belgium", "Netherlands", "Switzerland", "Luxembourg", "Japan", "South Korea", "China", "Hong Kong", "Singapore", "Australia", "Canada", "Other"];

function BuyModal({ item, onClose }) {
  const [step, setStep] = React.useState("form");   // form | review | done
  const [form, setForm] = React.useState({
    size: item.sizes ? "" : null,
    quantity: 1,
    fullName: "", email: "", phone: "",
    addressLine1: "", addressLine2: "", city: "", postalCode: "", country: "France",
    notes: "",
  });
  const [err, setErr] = React.useState("");

  const update = (k) => (e) => setForm((f) => ({ ...f, [k]: e.target.value }));

  function validate() {
    if (item.sizes && !form.size) return "Please select a size.";
    if (!form.fullName.trim()) return "Full name is required.";
    if (!EMAIL_RE.test(form.email.trim())) return "Please enter a valid email.";
    if (!form.addressLine1.trim()) return "Shipping address is required.";
    if (!form.city.trim()) return "City is required.";
    if (!form.postalCode.trim()) return "Postal code is required.";
    return "";
  }

  function onSubmit(e) {
    e.preventDefault();
    const v = validate();
    if (v) { setErr(v); return; }
    setErr("");
    setStep("review");
  }

  function confirm() {
    saveOrder({
      itemId: item.id,
      itemTitle: item.title,
      price: item.price,
      currency: item.currency,
      size: form.size,
      quantity: form.quantity,
      buyer: {
        fullName: form.fullName.trim(),
        email: form.email.trim().toLowerCase(),
        phone: form.phone.trim(),
      },
      shipping: {
        addressLine1: form.addressLine1.trim(),
        addressLine2: form.addressLine2.trim(),
        city: form.city.trim(),
        postalCode: form.postalCode.trim(),
        country: form.country,
      },
      notes: form.notes.trim(),
    });
    setStep("done");
  }

  return (
    <div className="buy-modal" role="dialog" aria-modal="true" aria-label={`Buy ${item.title}`}>
      <div className="buy-modal__backdrop" onClick={onClose} />
      <div className="buy-modal__card">
        <button type="button" className="buy-modal__close" aria-label="Close" onClick={onClose}>×</button>

        {step === "form" && (
          <>
            {item.productImage && (
              <div className="buy-modal__hero">
                <img src={item.productImage} alt={item.title} draggable="false" />
              </div>
            )}
            <div className="buy-modal__head">
              <div className="buy-modal__kicker">{item.kicker}</div>
              <h2 className="buy-modal__title">{item.title}</h2>
              <div className="buy-modal__price">{fmtPrice(item.price, item.currency)}</div>
              <p className="buy-modal__desc">{item.description}</p>
            </div>

            <form className="buy-form" onSubmit={onSubmit} noValidate>
              {item.sizes && (
                <div className="buy-field">
                  <label className="buy-label">Size <span className="buy-req">*</span></label>
                  <div className="size-grid">
                    {item.sizes.map((s) => (
                      <button type="button" key={s}
                        className={`size-chip ${form.size === s ? "is-on" : ""}`}
                        onClick={() => setForm((f) => ({ ...f, size: s }))}>{s}</button>
                    ))}
                  </div>
                </div>
              )}

              <div className="buy-section">CONTACT</div>
              <div className="buy-row">
                <div className="buy-field"><label className="buy-label">Full name <span className="buy-req">*</span></label>
                  <input value={form.fullName} onChange={update("fullName")} autoComplete="name" /></div>
                <div className="buy-field"><label className="buy-label">Email <span className="buy-req">*</span></label>
                  <input type="email" value={form.email} onChange={update("email")} autoComplete="email" /></div>
              </div>
              <div className="buy-field"><label className="buy-label">Phone (optional)</label>
                <input type="tel" value={form.phone} onChange={update("phone")} autoComplete="tel" /></div>

              <div className="buy-section">SHIPPING</div>
              <div className="buy-field"><label className="buy-label">Address line 1 <span className="buy-req">*</span></label>
                <input value={form.addressLine1} onChange={update("addressLine1")} autoComplete="address-line1" /></div>
              <div className="buy-field"><label className="buy-label">Address line 2</label>
                <input value={form.addressLine2} onChange={update("addressLine2")} autoComplete="address-line2" /></div>
              <div className="buy-row">
                <div className="buy-field"><label className="buy-label">City <span className="buy-req">*</span></label>
                  <input value={form.city} onChange={update("city")} autoComplete="address-level2" /></div>
                <div className="buy-field"><label className="buy-label">Postal code <span className="buy-req">*</span></label>
                  <input value={form.postalCode} onChange={update("postalCode")} autoComplete="postal-code" /></div>
              </div>
              <div className="buy-field"><label className="buy-label">Country</label>
                <select value={form.country} onChange={update("country")} autoComplete="country-name">
                  {COUNTRIES.map((c) => <option key={c}>{c}</option>)}
                </select>
              </div>

              <div className="buy-field"><label className="buy-label">Notes (optional)</label>
                <textarea rows={2} value={form.notes} onChange={update("notes")} placeholder="Anything we should know about the delivery, signing dedication, etc." /></div>

              {err && <div className="buy-error">{err}</div>}

              <div className="buy-foot">
                <div className="buy-total">
                  <span className="buy-total__lbl">Total</span>
                  <span className="buy-total__val">{fmtPrice(item.price, item.currency)}</span>
                </div>
                <button type="submit" className="buy-cta">
                  <svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M13 2L4 14h6l-1 8 9-12h-6l1-8z" /></svg>
                  <span>Review order</span>
                </button>
              </div>
              <div className="buy-note">Payment isn’t live yet — this records your order intent. We’ll contact you to complete payment and shipping.</div>
            </form>
          </>
        )}

        {step === "review" && (
          <>
            <div className="buy-modal__head">
              <div className="buy-modal__kicker">REVIEW</div>
              <h2 className="buy-modal__title">{item.title}</h2>
              <div className="buy-modal__price">{fmtPrice(item.price, item.currency)}</div>
            </div>
            <div className="buy-review">
              {form.size && <div><span className="buy-review__k">Size</span><span>{form.size}</span></div>}
              <div><span className="buy-review__k">Name</span><span>{form.fullName}</span></div>
              <div><span className="buy-review__k">Email</span><span>{form.email}</span></div>
              {form.phone && <div><span className="buy-review__k">Phone</span><span>{form.phone}</span></div>}
              <div><span className="buy-review__k">Shipping</span><span>{form.addressLine1}{form.addressLine2 ? ", " + form.addressLine2 : ""}, {form.postalCode} {form.city}, {form.country}</span></div>
              {form.notes && <div><span className="buy-review__k">Notes</span><span>{form.notes}</span></div>}
            </div>
            <div className="buy-foot">
              <button type="button" className="buy-secondary" onClick={() => setStep("form")}>← Edit</button>
              <button type="button" className="buy-cta" onClick={confirm}>
                <svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M13 2L4 14h6l-1 8 9-12h-6l1-8z" /></svg>
                <span>Confirm order</span>
              </button>
            </div>
          </>
        )}

        {step === "done" && (
          <div className="buy-done">
            <div className="buy-done__tick">
              <svg viewBox="0 0 24 24" width="36" height="36" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><path d="M4 12.5l5 5L20 6" /></svg>
            </div>
            <h2 className="buy-modal__title">Order recorded</h2>
            <p className="buy-done__txt">Thank you. We’ve saved your order intent for <strong>{item.title}</strong>. Our team will reach out at <strong>{form.email}</strong> to finalize payment and shipping.</p>
            <button type="button" className="buy-cta" onClick={onClose}>Done</button>
          </div>
        )}
      </div>
    </div>
  );
}

function Interior({ live, onExit }) {
  const [pos, setPos] = React.useState(GX_DEFAULT);
  const [buyOpen, setBuyOpen] = React.useState(false);
  const centerId = Object.keys(pos).find((k) => pos[k] === "center");
  const center = GX_ITEMS.find((i) => i.id === centerId);

  const promote = (id) => {
    setPos((prev) => {
      if (prev[id] === "center") return prev;
      const slot = prev[id];
      const cur = Object.keys(prev).find((k) => prev[k] === "center");
      return { ...prev, [id]: "center", [cur]: slot };
    });
  };

  return (
    <div className={`interior ${live ? "is-live" : ""}`}
         style={{ "--room-empty": `url(${ROOM_EMPTY})`, "--room-full": `url(${ROOM_FULL})` }}>
      <div className="gx-stage">
        <div className="gx-bg gx-bg--empty" />
        <div className="gx-spot" />
        {GX_ITEMS.map((it) => {
          const slot = GX_SLOTS[pos[it.id]];
          const isC = pos[it.id] === "center";
          return (
            <div key={it.id}
                 className={`gx-item ${isC ? "is-center" : "is-side"}`}
                 style={{ left: `${slot.x}%`, top: `${slot.y}%`, width: `${slot.w}%`,
                          opacity: slot.op, filter: `brightness(${slot.br})`, zIndex: isC ? 30 : 20 }}
                 onClick={() => promote(it.id)}>
              <div className="gx-item__halo" />
              <img className="gx-item__img" src={it.img} alt={it.title} draggable="false" />
              <span className="gx-item__tag">{it.title}</span>
            </div>
          );
        })}
        <div className="gx-bg gx-bg--full" />
        <div className="gx-vig" />
      </div>

      <div className="gx-chrome">
        <div className="gx-top">
          <div className="gx-mark">DIGITAL&nbsp;AF <span>POP-UP 화합</span></div>
          <button type="button" className="gx-exit" onClick={onExit}>
            <span className="gx-exit__dev">DEV</span> Exit ✕
          </button>
        </div>
        <div className="gx-caption" key={centerId}>
          <div className="gx-caption__k gx-cap-anim">{center.kicker}</div>
          <h2 className="gx-caption__t gx-cap-anim">{center.title}</h2>
          {center.price && (
            <div className="gx-buyrow gx-cap-anim">
              <span className="gx-price">{fmtPrice(center.price, center.currency)}</span>
              <button type="button" className="gx-buy" onClick={() => setBuyOpen(true)}>
                <svg viewBox="0 0 24 24" width="13" height="13" fill="currentColor" aria-hidden="true"><path d="M13 2L4 14h6l-1 8 9-12h-6l1-8z" /></svg>
                <span>BUY</span>
              </button>
            </div>
          )}
        </div>
        <div className="gx-hint"><span className="gx-hint__dot" /> Select an object to bring it to the center</div>
      </div>
      {buyOpen && <BuyModal item={center} onClose={() => setBuyOpen(false)} />}
    </div>
  );
}

/* ----------------------------------------------------------------------------
   ROOT
---------------------------------------------------------------------------- */
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "layout": "lower",
  "hero": "b",
  "tagline": "A new physical / digital experience is coming.",
  "motion": "cinematic",
  "accent": "#7A4DFF",
  "showEnter": true
}/*EDITMODE-END*/;

const TAGLINES = [
  "A new physical / digital experience is coming.",
  "The future of culture opens soon.",
  "Join the list before the doors open.",
  "A hidden pop-up for digital culture.",
  "Physical space. Digital culture. Coming soon.",
];

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [phase, setPhase] = React.useState("teaser"); // teaser | enter | interior
  const [live, setLive] = React.useState(false);
  const heroSrc = t.hero === "a" ? HERO_A : HERO_B;
  const showEnter = t.showEnter !== false;

  const Layout =
    t.layout === "centered" ? LayoutCentered :
    t.layout === "vitrine" ? LayoutVitrine : LayoutLowerThird;

  const enter = () => { setLive(false); setPhase("enter"); };
  const onVideoDone = () => { setPhase("interior"); setTimeout(() => setLive(true), 80); };
  const exit = () => { setPhase("teaser"); setLive(false); };

  return (
    <>
      {(phase === "enter" || phase === "interior") && <Interior live={live} onExit={exit} />}
      {phase === "enter" && <TransitionVideo onDone={onVideoDone} poster={heroSrc} />}

      {phase === "teaser" && (
      <div className={`world world--motion-${t.motion}`} style={{ "--accent": t.accent }}>
        <div className="hero-bg" key={heroSrc}>
          <div className="hero-bg__img" style={{ backgroundImage: `url(${heroSrc})` }} />
          <div className="hero-bg__grade" />
        </div>

        <FXLayer intensity={t.motion} accent={t.accent} />

        <main className="frame">
          <Layout tagline={t.tagline} showEnter={showEnter} onEnter={enter} />
        </main>

        <footer className="footer">
          <span className="footer__mark">DIGITAL&nbsp;AF</span>
          <Socials />
          <a className="footer__admin" href="admin.html" title="Wishlist admin">Wishlist ↗</a>
        </footer>

        <TweaksPanel>
          <TweakSection label="Layout direction" />
          <TweakRadio
            label="Direction"
            value={t.layout}
            options={[
              { value: "centered", label: "Centered" },
              { value: "lower", label: "Title card" },
              { value: "vitrine", label: "Vitrine" },
            ]}
            onChange={(v) => setTweak("layout", v)}
          />
          <TweakSection label="Storefront" />
          <TweakRadio
            label="Hero"
            value={t.hero}
            options={[
              { value: "b", label: "Smoked glass" },
              { value: "a", label: "Lit interior" },
            ]}
            onChange={(v) => setTweak("hero", v)}
          />
          <TweakColor
            label="Glow accent"
            value={t.accent}
            options={["#7A4DFF", "#4D7CFF", "#C04DFF", "#1FB6A8"]}
            onChange={(v) => setTweak("accent", v)}
          />
          <TweakSection label="Copy" />
          <TweakSelect
            label="Tagline"
            value={t.tagline}
            options={TAGLINES}
            onChange={(v) => setTweak("tagline", v)}
          />
          <TweakSection label="Atmosphere" />
          <TweakRadio
            label="Motion"
            value={t.motion}
            options={[
              { value: "cinematic", label: "Cinematic" },
              { value: "subtle", label: "Subtle" },
              { value: "off", label: "Still" },
            ]}
            onChange={(v) => setTweak("motion", v)}
          />
          <TweakSection label="Pop-up access (dev)" />
          <TweakToggle
            label="Show ENTER button"
            value={showEnter}
            onChange={(v) => setTweak("showEnter", v)}
          />
        </TweaksPanel>
      </div>
      )}
    </>
  );
}

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