// PDP.jsx — FULL-PAGE product view (replaces the old drawer/sheet).
// Layout: big packshots + a captioned DETAILS gallery own the left column;
// the right column is a sticky spec rail — index, name, blurb, prices, the
// size-run order matrix, fabric/colour facts and colourway brothers.
// Opened via the same onOpenSku(...) everywhere; URL stays /product/:id and
// the back button / ⟵ back both pop history (closeOverlay in App).

function PDPSheet({ product, onClose, orderItem, setOrderQty, onOpenConcept, collection, onOpenSku, concepts, looks }) {
  const ec = React.useContext(window.EditCtx);
  if (!product) return null;
  const brothers = (product.brothers || [])
    .map((id) => (collection || []).find((p) => p.id === id)).filter(Boolean);
  const num = (v) => Number(String(v).replace(/[^\d.]/g, "")) || 0;
  const setImageAt = (i, path) => {
    const next = [...(product.images || [])];
    next[i] = path;
    ec.saveSku(product.id, { images: next.filter(Boolean) });
  };
  const sizes = product.sizes || ["ONE SIZE"];
  const qtys = (orderItem && orderItem.qtys) || {};
  // count EVERY qty entry (incl. the "TBD" line from "sizes later")
  const totalUnits = Object.values(qtys).reduce((s, q) => s + (q || 0), 0);
  const lineTotal = totalUnits * product.ws;

  // ── edit mode: the media library drives the WORN section (show every image
  // tagged with this product, toggle on-page/hidden) and the DETAILS picker.
  const [lib, setLib] = React.useState(null);
  React.useEffect(() => {
    if (!ec.edit) return;
    window.sbAdmin.get("/api/admin/media").then(setLib).catch(() => setLib([]));
  }, [ec.edit]);
  const libSrc = (m) => m.path + (m.ver ? "?v=" + m.ver : "");
  const tagged = ec.edit && lib ? lib.filter((m) => (m.skuIds || []).includes(product.id)) : [];
  // which files the lookbook (draft, in edit mode) already shows — badged on the
  // WORN toggles so the page doesn't repeat images the buyer just scrolled past
  const bookFiles = React.useMemo(() => new Set(
    (looks || []).flatMap((L) => (L.images || []).filter(Boolean).map((u) => String(u).split("?")[0]))
  ), [looks]);
  const inBook = (m) => bookFiles.has(String(m.path).split("?")[0]);

  // WORN grid extras: saved display order (mirrors the server's sort rule),
  // page-preview filter, right-click menu, drag-reorder.
  const [wornOnly, setWornOnly] = React.useState(false);   // hide the HIDDEN picks — see the page as retailers do
  const [wornMenu, setWornMenu] = React.useState(null);    // { x, y, m } | null
  const wornDrag = React.useRef(null);
  const orderedTagged = React.useMemo(() => {
    const o = product.campaignOrder || [];
    const at = (p) => { const i = o.indexOf(p); return i === -1 ? Infinity : i; };
    return tagged.map((m, k) => [m, k])
      .sort((a, b) => (at(a[0].path) - at(b[0].path)) || (a[1] - b[1])).map(([m]) => m);
  }, [tagged, product.campaignOrder]);
  const shownTagged = wornOnly
    ? orderedTagged.filter((m) => (m.pdpSkuIds || []).includes(product.id))
    : orderedTagged;
  const saveWornOrder = (arr) => ec.saveSku(product.id, { campaignOrder: arr.map((m) => m.path) });
  React.useEffect(() => {
    if (!wornMenu) return;
    const close = () => setWornMenu(null);
    window.addEventListener("click", close);
    window.addEventListener("scroll", close, true);
    return () => { window.removeEventListener("click", close); window.removeEventListener("scroll", close, true); };
  }, [wornMenu]);
  const togglePdp = (m) => {
    const on = (m.pdpSkuIds || []).includes(product.id);
    const pdpSkuIds = on ? (m.pdpSkuIds || []).filter((x) => x !== product.id) : [...(m.pdpSkuIds || []), product.id];
    window.sbAdmin.patch("/api/admin/media/" + m.id, { pdpSkuIds })
      .then((u) => setLib((ls) => ls.map((x) => (x.id === m.id ? u : x))))
      .catch(() => {});
  };

  // DETAILS editing — captioned close-ups; add from the library (suggestions =
  // images tagged with this product or its colourway brothers), relabel, remove,
  // or drop/upload a file straight onto the section. Close-ups are colour-family
  // facts, so every save mirrors to the colourway brothers too.
  const details = product.detailImages || [];
  const saveDetails = (arr) => {
    ec.saveSku(product.id, { detailImages: arr });
    for (const b of (product.brothers || [])) ec.saveSku(b, { detailImages: arr });
  };
  const addDetail = (path) => saveDetails([...details, { path, label: "" }]);
  // from the WORN right-click: campaign shots become details CROPPED (cover
  // pan/zoom via the lookbook transform box) — starts centred, tune from there
  const addDetailCropped = (path) => saveDetails([...details, { path, label: "", x: 50, y: 50, s: 1 }]);
  const [detPrev, setDetPrev] = React.useState(null);      // { i, tf } while dragging a crop
  const detDrag = React.useRef(null);                      // grip drag-reorder index
  const [detPick, setDetPick] = React.useState(false);
  const [detQ, setDetQ] = React.useState("");
  const familyIds = [product.id, ...(product.brothers || [])];
  const detCandidates = (lib || []).filter((m) => {
    const term = detQ.trim().toLowerCase();
    if (!term) return (m.skuIds || []).some((id) => familyIds.includes(id));   // suggestions first
    let hay = (m.name || "") + " " + (m.model || "");
    for (const id of (m.skuIds || [])) {
      const p = (collection || []).find((s) => s.id === id);
      if (p) hay += " " + p.name + " " + (p.colorway ? p.colorway.name : "");
    }
    return hay.toLowerCase().includes(term);
  });

  // Page (not overlay): open scrolled to the top; Escape still goes back.
  React.useEffect(() => {
    window.scrollTo(0, 0);
  }, [product.id]);

  // Sticky spec rail without an inner scroll trap: when the rail is taller
  // than the viewport, give it a NEGATIVE sticky top so scrolling the PAGE
  // reveals its bottom (ALSO IN incl.), where it then sticks.
  const infoRef = React.useRef(null);
  React.useEffect(() => {
    const el = infoRef.current;
    if (!el) return;
    const place = () => {
      const overflow = el.offsetHeight + 96 - window.innerHeight;
      el.style.top = overflow > 0 ? -(overflow - 76) + "px" : "";
    };
    const ro = new ResizeObserver(place);
    ro.observe(el);
    window.addEventListener("resize", place);
    place();
    return () => { ro.disconnect(); window.removeEventListener("resize", place); };
  }, [product.id]);
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onClose]);

  const images = (product.images || []);
  const concept = (concepts || []).find((c) => c && String(c.name).toLowerCase() === String(product.series || "").toLowerCase()) || null;
  // click any image → full-screen lightbox (same chrome as the look page)
  const [lightbox, setLightbox] = React.useState(null);
  React.useEffect(() => {
    if (!lightbox) return;
    const esc = (e) => { if (e.key === "Escape") { e.stopPropagation(); setLightbox(null); } };
    window.addEventListener("keydown", esc, true);
    return () => window.removeEventListener("keydown", esc, true);
  }, [lightbox]);

  const setSizeQty = (size, n) => {
    const next = Math.max(0, n);
    setOrderQty(product, size, next);
  };

  // Past the photos + spec (into DETAILS), a frosted pill keeps the front
  // packshot + name pinned at the top; click = back up.
  const [pill, setPill] = React.useState(false);
  React.useEffect(() => {
    const onScroll = () => {
      const info = document.querySelector(".pp-info");
      const media = document.querySelector(".pp-media");
      const anchor = Math.max(
        info ? info.getBoundingClientRect().bottom : 0,
        media ? media.getBoundingClientRect().bottom : 0);
      setPill(anchor < 90);
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener("scroll", onScroll);
  }, [product.id]);

  return (
    <section className="pp" data-screen-label="04 Product">
      <button type="button" className="concept-back" onClick={onClose}>← back</button>
      <div className="pp-grid">
        {/* ── packshots — natural image ratio (no letterboxing = no dead space
               between shots); click for full screen ── */}
        <div className="pp-media">
          {/* packshots live in their own strip: a column on desktop, a
              side-scrolling snap carousel on phones */}
          <div className="pp-shots">
            {(images.length ? images : [null]).map((src, i) => (
              <div className={"photo pp-frame" + (src ? " pp-frame-natural" : "")} key={i}
                style={src ? null : { background: product.bg }}>
                {src && <img className="pp-frame-img" src={src} alt="" draggable={false}
                  loading={i > 0 ? "lazy" : undefined} decoding="async"
                  onClick={() => setLightbox(src)} title="click for full screen" />}
                {i === 0 && <span className="photo-tag">{product.idx}</span>}
                <window.EditableImage title="⤓ replace photo" onPick={(path) => setImageAt(i, path)} />
              </div>
            ))}
            {ec.edit && images.length < 8 && (
              <div className="photo pp-frame pp-frame-add" style={{ background: "var(--sb-bone-deep, #E2DCCF)" }}>
                <window.EditableImage title="＋ add photo" onPick={(path) => setImageAt(images.length, path)} />
              </div>
            )}
          </div>

          {/* campaign shots approved for this product (admin › products / media).
              In EDIT MODE this becomes the full tagged set with on/off toggles. */}
          {ec.edit ? (
            tagged.length > 0 && (
              <div className="pp-worn">
                <div className="pdp-details-h pp-worn-head">
                  <span>WORN · {tagged.filter((m) => (m.pdpSkuIds || []).includes(product.id)).length} of {tagged.length} tagged shown</span>
                  <button type="button" className={"pp-worn-preview" + (wornOnly ? " is-on" : "")}
                    onClick={() => setWornOnly((v) => !v)}
                    title={wornOnly ? "back to all tagged images (incl. hidden)" : "preview the page — hide the HIDDEN picks"}>
                    {wornOnly ? "◉ page preview" : "◎ page preview"}
                  </button>
                </div>
                <div className="pp-worn-grid">
                  {shownTagged.map((m, gi) => {
                    const on = (m.pdpSkuIds || []).includes(product.id);
                    const book = inBook(m);
                    return (
                      <button key={m.id} type="button"
                        className={"pp-worn-toggle" + (on ? " is-on" : "")}
                        title={(on ? "shown on this page — click to hide" : "hidden — click to show on this page")
                          + (book ? " · this photo is already in the lookbook" : " · not used in the lookbook")
                          + " · drag to reorder · right-click for more"}
                        onClick={() => togglePdp(m)}
                        onContextMenu={(e) => { e.preventDefault(); e.stopPropagation(); setWornMenu({ x: e.clientX, y: e.clientY, m }); }}
                        draggable={!wornOnly}
                        onDragStart={(e) => { wornDrag.current = gi; e.dataTransfer.effectAllowed = "move"; }}
                        onDragOver={(e) => { if (wornDrag.current != null) e.preventDefault(); }}
                        onDrop={(e) => {
                          if (wornDrag.current == null) return;
                          e.preventDefault(); e.stopPropagation();
                          saveWornOrder(window.sbMove(orderedTagged, wornDrag.current, gi));
                          wornDrag.current = null;
                        }}
                        onDragEnd={() => { wornDrag.current = null; }}>
                        <img src={libSrc(m)} alt="" loading="lazy" draggable={false}
                          srcSet={window.sbSrcSet(libSrc(m))} sizes="(max-width: 600px) 46vw, 24vw" />
                        <span className={"pp-worn-book" + (book ? " is-in" : "")}>{book ? "▤ IN LOOKBOOK" : "NOT IN BOOK"}</span>
                        <span className="pp-worn-state">{on ? "ON PAGE" : "HIDDEN"}</span>
                      </button>
                    );
                  })}
                </div>
                {wornMenu && (
                  <div className="lb-ctx pp-worn-ctx" style={{ left: wornMenu.x, top: wornMenu.y }}
                    onClick={(e) => e.stopPropagation()}>
                    <button onClick={() => { addDetailCropped(wornMenu.m.path); setWornMenu(null); }}>→ add to details (crop below)</button>
                    <button onClick={() => { togglePdp(wornMenu.m); setWornMenu(null); }}>
                      {(wornMenu.m.pdpSkuIds || []).includes(product.id) ? "hide from this page" : "show on this page"}
                    </button>
                  </div>
                )}
              </div>
            )
          ) : (product.campaignImages || []).length > 0 && (
            <div className="pp-worn">
              <div className="pdp-details-h">WORN</div>
              <div className="pp-worn-grid">
                {product.campaignImages.map((src, i) => (
                  <img key={src + i} src={src} alt="" loading="lazy" draggable={false}
                    srcSet={window.sbSrcSet(src)} sizes="(max-width: 600px) 46vw, 24vw"
                    style={{ cursor: "zoom-in" }} onClick={() => setLightbox(src)} />
                ))}
              </div>
            </div>
          )}
        </div>

        {/* ── spec rail — sticky beside the photos ── */}
        <aside className="pp-info" ref={infoRef}>
          <div className="pdp-spec">
            <div className="idx">{product.idx}  ·  {(product.categories && product.categories.length ? product.categories : [product.category]).join("  ·  ")}</div>
            <h2>
              {product.seriesLogo ? (
                <img className="pdp-series-logo" src={product.seriesLogo} alt={product.series || ""}
                  title={product.series ? "concept · " + product.series.toLowerCase() : ""}
                  onClick={product.series && onOpenConcept ? () => onOpenConcept(product.series) : undefined}
                  style={product.series && onOpenConcept ? { cursor: "pointer" } : null} />
              ) : product.series ? (
                // no logo uploaded for this concept yet — a small text mark instead
                <button type="button" className="pdp-series-chip" title={"concept · " + product.series.toLowerCase()}
                  onClick={onOpenConcept ? () => onOpenConcept(product.series) : undefined}>
                  {product.series.slice(0, 2)}
                </button>
              ) : null}
              <window.EditableText value={product.name} style={{ textTransform: "lowercase" }}
                onSave={(v) => ec.saveSku(product.id, { name: v })} />
            </h2>
            <p className="blurb">
              <window.EditableText tag="span" multiline value={product.blurb || ""}
                placeholder="add a description"
                onSave={(v) => ec.saveSku(product.id, { blurb: v })} />
            </p>

            <div className="pdp-prices">
              <div className="price-cell">
                <span className="lbl">{product.priceMode === "dtc" ? "[ price ]" : "[ wholesale ]"}</span>
                <span className="val">
                  {product.wsOriginal != null && <span className="price-strike">{product.currency}{product.wsOriginal}</span>}
                  {product.currency}<window.EditableText value={String(product.ws)} onSave={(v) => ec.saveSku(product.id, { ws: num(v) })} />
                </span>
              </div>
              {(product.msrp != null || ec.edit) && (
                <div className="price-cell">
                  <span className="lbl">[ msrp ]</span>
                  <span className="val">{product.currency}<window.EditableText value={String(product.msrp)} onSave={(v) => ec.saveSku(product.id, { msrp: num(v) })} /></span>
                </div>
              )}
            </div>

            <div className="size-matrix">
              <div className="size-matrix-head">
                <span className="h">{product.priceMode === "dtc" ? "[ CHOOSE YOUR SIZE ]" : "[ SIZE RUN · ENTER QUANTITIES ]"}</span>
                {product.priceMode !== "dtc" && <span className="h-meta">PACK 1</span>}
              </div>
              {product.priceMode === "dtc" ? (
                /* DTC: picking a size IS choosing the item — tap to select (1), tap again to remove */
                <div className="size-pick">
                  {sizes.map(s => (
                    <button key={s} type="button" ref={window.sbHaptic}
                      className={"size-pick-btn" + ((qtys[s] || 0) > 0 ? " is-on" : "")}
                      onClick={() => setSizeQty(s, (qtys[s] || 0) > 0 ? 0 : 1)}>{s}</button>
                  ))}
                </div>
              ) : (
                <div className="size-matrix-row" style={sizes.length === 1 ? {gridTemplateColumns: "1fr"} : null}>
                  {sizes.map(s => (
                    <div key={s} className={"size-cell" + ((qtys[s] || 0) > 0 ? " is-active" : "")}>
                      <span className="lbl">{s}</span>
                      <input type="number" min="0" value={qtys[s] || 0}
                        onChange={e => setSizeQty(s, parseInt(e.target.value || "0", 10))} />
                      <div className="stepper">
                        <button onClick={() => setSizeQty(s, (qtys[s] || 0) - 1)}>−</button>
                        <button onClick={() => setSizeQty(s, (qtys[s] || 0) + 1)}>+</button>
                      </div>
                    </div>
                  ))}
                </div>
              )}
            </div>

            <div className="qty-summary">
              <span className="lbl">[ line total · {totalUnits} unit{totalUnits === 1 ? "" : "s"} ]</span>
              <span className="val">{product.currency}{lineTotal.toLocaleString()}</span>
            </div>

            <div style={{display: "flex", gap: 12, flexWrap: "wrap"}}>
              {totalUnits > 0 ? (
                <button className="btn btn-primary" onClick={onClose}>
                  added · {totalUnits} units ⟶
                </button>
              ) : (
                <React.Fragment>
                  <button className="btn btn-outline"
                    onClick={() => setSizeQty(sizes[Math.min(2, sizes.length - 1)], 1)}>
                    [ ADD TO ORDER ]
                  </button>
                  <button className="btn btn-ghost" title="put it in the order now — the size run can be filled in before submitting"
                    onClick={() => setOrderQty(product, "TBD", 1)}>
                    add to order · choose sizes later
                  </button>
                </React.Fragment>
              )}
            </div>

            <dl className="pdp-fabric">
              <dt>FIBRE</dt><dd>{product.fabric}</dd>
              {product.weight && (<React.Fragment><dt>WEIGHT</dt><dd>{product.weight}</dd></React.Fragment>)}
              <dt>COLOUR</dt>
              <dd className="pdp-colour">
                {product.pantoneHex && (
                  <span className="pdp-swatch" style={{ background: product.pantoneHex }}
                    title={product.pantone || product.colorway.name} />
                )}
                {product.colorway.name}
              </dd>
              <dt>ORIGIN</dt><dd>{product.origin}</dd>
              {product.care && (<React.Fragment><dt>CARE</dt><dd>{product.care}</dd></React.Fragment>)}
            </dl>

            {brothers.length > 0 && (
              <div className="pdp-brothers">
                <div className="pdp-brothers-h">ALSO IN</div>
                <div className="pdp-brothers-row">
                  {brothers.map((b) => (
                    <button key={b.id} className="pdp-brother" type="button"
                      title={b.name.toLowerCase() + (b.colorway ? " · " + b.colorway.name : "")}
                      onClick={() => onOpenSku && onOpenSku(b)}>
                      <span className="pdp-brother-thumb" style={{ background: b.bg }} />
                      <span className="pdp-brother-c">{b.colorway ? b.colorway.name : ""}</span>
                    </button>
                  ))}
                </div>
              </div>
            )}
          </div>
        </aside>
      </div>

      {/* ── details — captioned close-ups, full width under the packshots ── */}
      <React.Fragment>
        {(details.length > 0 || ec.edit) && (
          <div className="pp-details">
            <div className="pdp-details-h">DETAILS</div>
            <div className="pp-details-grid" {...(ec.edit ? window.dropProps(ec, addDetail) : {})}>
              {details.map((d, i) => {
                // drop (or ⤓ chip) on an existing tile REPLACES its image, caption kept
                const replaceAt = (path) => saveDetails(details.map((x, k) => (k === i ? { ...x, path } : x)));
                // cover crop: live-preview tf while dragging the box, else the saved one
                const tf = (detPrev && detPrev.i === i) ? detPrev.tf
                  : (d.x != null ? { x: d.x, y: d.y, s: d.s || 1 } : null);
                const commitTf = (ntf) => { setDetPrev(null); saveDetails(details.map((x, k) => (k === i ? { ...x, ...ntf } : x))); };
                return (
                <figure className="pdp-detail" key={d.path + i}
                  onDragOver={(e) => { if (detDrag.current != null) e.preventDefault(); }}
                  onDrop={(e) => {
                    if (detDrag.current == null) return;
                    e.preventDefault(); e.stopPropagation();
                    saveDetails(window.sbMove(details, detDrag.current, i));
                    detDrag.current = null;
                  }}>
                  <span className="pdp-detail-img" onClick={() => setLightbox(d.path)}
                    style={tf ? { cursor: "zoom-in" } : { backgroundImage: `url("${window.sbImg(d.path, 800)}")`, cursor: "zoom-in" }}
                    {...(ec.edit ? window.dropProps(ec, replaceAt) : {})}>
                    {tf && (
                      <span className="pdp-detail-clip">
                        <img className="pdp-detail-photo" src={window.sbImg(d.path, 800)} alt="" draggable={false}
                          style={{ objectPosition: tf.x + "% " + tf.y + "%", transform: "scale(" + tf.s + ")", transformOrigin: tf.x + "% " + tf.y + "%" }} />
                      </span>
                    )}
                    {ec.edit && (
                      <window.SBTransformBox tf={tf || { x: 50, y: 50, s: 1 }}
                        onChange={(ntf) => setDetPrev({ i, tf: ntf })} onCommit={commitTf} />
                    )}
                    {ec.edit && (
                      <button className="pp-det-x" title="remove this detail"
                        onClick={(e) => { e.stopPropagation(); saveDetails(details.filter((_, k) => k !== i)); }}>×</button>
                    )}
                    {ec.edit && (
                      <span className="pp-det-grip" title="drag to reorder" draggable
                        onDragStart={(e) => { e.stopPropagation(); detDrag.current = i; e.dataTransfer.effectAllowed = "move"; }}
                        onDragEnd={() => { detDrag.current = null; }}
                        onPointerDown={(e) => e.stopPropagation()}>⠿</span>
                    )}
                    {ec.edit && <window.EditableImage title="⤓ replace · drop" onPick={replaceAt} />}
                  </span>
                  <figcaption>
                    {ec.edit ? (
                      <window.EditableText value={d.label || ""} placeholder="caption…"
                        onSave={(v) => saveDetails(details.map((x, k) => (k === i ? { ...x, label: v } : x)))} />
                    ) : d.label}
                  </figcaption>
                </figure>
              );})}
              {ec.edit && (
                <div className="pp-det-add">
                  <button type="button" className="pp-det-addbtn" onClick={() => { setDetQ(""); setDetPick((v) => !v); }}>
                    {detPick ? "× close" : "＋ add from library"}
                  </button>
                  <label className="pp-det-addbtn pp-det-upload" title="upload a new close-up — or just drop an image anywhere on this section">
                    ⤓ upload / drop
                    <input type="file" accept="image/*" style={{ display: "none" }}
                      onChange={(e) => { const f = e.target.files && e.target.files[0]; if (f) ec.upload(f, addDetail); e.target.value = ""; }} />
                  </label>
                  {detPick && (
                    <div className="pp-det-picker" onClick={(e) => e.stopPropagation()}>
                      <input className="pp-det-q" autoFocus value={detQ}
                        placeholder={"search… (empty = images of " + product.name.toLowerCase() + " & its colourways)"}
                        onChange={(e) => setDetQ(e.target.value)} onKeyDown={(e) => e.stopPropagation()} />
                      <div className="pp-det-grid">
                        {lib === null && <div className="pp-det-empty">loading library…</div>}
                        {detCandidates.slice(0, 60).map((m) => (
                          <button key={m.id} type="button" className="pp-det-tile"
                            title={(m.name || "") + (m.model ? " · " + m.model : "")}
                            onClick={() => { saveDetails([...details, { path: m.path, label: "" }]); setDetPick(false); }}>
                            <img src={window.sbImg(libSrc(m), 480)} alt="" loading="lazy" />
                          </button>
                        ))}
                        {lib !== null && detCandidates.length === 0 && (
                          <div className="pp-det-empty">{detQ ? "no match." : "no images tagged with this product yet — search the whole library above."}</div>
                        )}
                      </div>
                    </div>
                  )}
                </div>
              )}
            </div>
          </div>
        )}

        {/* ── the concept behind the piece — logo, name, first lines; opens
               the full concept page ── */}
        {concept && (
          <div className="pp-concept">
            <div className="pdp-details-h">CONCEPT</div>
            <button type="button" className="pp-concept-card"
              onClick={() => onOpenConcept && onOpenConcept(concept.name)}>
              <span className="pp-concept-mark">
                {concept.logo
                  ? <img src={concept.logo} alt={concept.name} draggable={false} />
                  : <span className="pp-concept-abbr">{concept.name.slice(0, 2)}</span>}
              </span>
              <span className="pp-concept-txt">
                <span className="pp-concept-name">{concept.name.toLowerCase()}</span>
                {(concept.description || "") && (
                  <span className="pp-concept-body">
                    {(concept.description || "").split(/\n\s*\n/)[0]}
                  </span>
                )}
                <span className="pp-concept-link">explore the concept ⟶</span>
              </span>
            </button>
            {(() => {
              const prods = window.sbConceptProducts(collection, concept);
              return prods.length > 0 && (
                <div style={{ marginTop: 24 }}>
                  <window.ConceptProducts products={prods} currentId={product.id} onOpenSku={onOpenSku} bare />
                </div>
              );
            })()}
          </div>
        )}
      </React.Fragment>

      {/* frosted context pill — appears once you scroll past the spec into DETAILS */}
      <button type="button" className={"pp-pill" + (pill ? " is-on" : "")}
        onClick={() => window.scrollTo({ top: 0, behavior: "smooth" })}
        tabIndex={pill ? 0 : -1} aria-hidden={!pill} title="back to the top">
        <span className="pp-pill-thumb" style={{ background: product.bg }} />
        <span className="pp-pill-name">{product.name.toLowerCase()}</span>
        <span className="pp-pill-idx">{product.idx}</span>
      </button>

      {/* full-screen viewer — same chrome as the look-page lightbox */}
      {lightbox && (
        <div className="flp-lightbox" onClick={() => setLightbox(null)}>
          <img src={lightbox} alt="" onClick={(e) => e.stopPropagation()} />
          <button className="flp-lightbox-close" onClick={() => setLightbox(null)}>×</button>
        </div>
      )}
    </section>
  );
}

window.PDPSheet = PDPSheet;
