/* SER-OS — Casket Selection screen
   ──────────────────────────────────────────────────────────────────
   Presentation-grade casket browser:
     - Per-casket image gallery (swipe + arrows + dots + thumbnails)
     - Sticky comparison bar at the bottom (max 4 caskets)
     - Side-by-side comparison overlay with image galleries + lightbox
     - All built on a single <CasketGallery> primitive so behavior is
       consistent across card, detail, and comparison contexts.
   ────────────────────────────────────────────────────────────────── */

const COMPARE_MAX = 4;

/* Normalise an `images: []` list, falling back to `image` for legacy
   data. Returns at least an empty array — never null. */
function casketImageList(casket) {
  if (Array.isArray(casket.images) && casket.images.length) return casket.images;
  if (casket.image) return [casket.image];
  return [];
}

function CasketScreen({
  caseDetails, selectedPackage, selectedCasket, onSelect,
  serviceData,
  selectedAddOns,
  addOnTotal, addOnCount,
  onBack, onContinue, onEditCase, onJumpTo, notes, setNotes,
  confirmationStatus, onSendForConfirmation, onViewPdf, onResend, onEditArrangement,
  amendmentSnapshot, onEnterEditMode, onFinalizeAmendment, onDiscardAmendment, onSendToCustomer,
  onSimulateSign, onSendSignedForm,
  appliedCoupon = null, onApplyCoupon, onRemoveCoupon,
}) {
  const [detailView, setDetailView]    = React.useState(null);
  const [comparing,  setComparing]     = React.useState([]);
  const [showCompare, setShowCompare]  = React.useState(false);
  const [lightbox,   setLightbox]      = React.useState(null);   // { images:[], index:number, label?:string }

  const toggleCompare = (c) => {
    if (comparing.find((x) => x.id === c.id)) {
      setComparing(comparing.filter((x) => x.id !== c.id));
    } else if (comparing.length < COMPARE_MAX) {
      setComparing([...comparing, c]);
    }
  };
  const removeFromCompare = (id) => setComparing((cs) => cs.filter((c) => c.id !== id));
  const clearCompare = () => setComparing([]);

  return (
    <div style={{ display: "flex", alignItems: "stretch", minHeight: "calc(100vh - 84px)", position: "relative" }}>
      <main style={{
        flex: 1, padding: "24px 40px 64px", background: "#FAFAFA",
        overflowY: "auto",
        paddingBottom: comparing.length > 0 ? 140 : 64,
        transition: "padding-bottom 240ms ease",
      }}>
        <div style={{ maxWidth: 1280, margin: "0 auto", display: "flex", flexDirection: "column", gap: 20 }}>
          {confirmationStatus !== "amendment_draft" && (
            <button onClick={onBack} style={{
              background: "transparent", border: "none", padding: 0, cursor: "pointer",
              fontFamily: "inherit", fontSize: 13, color: "var(--fg-secondary)", alignSelf: "flex-start",
              display: "inline-flex", alignItems: "center", gap: 6,
            }}>
              <SerIcons.ArrowLeft size={18} />Back to Package Selection
            </button>
          )}

          {/* Confirmation / amendment status banners */}
          {(confirmationStatus === "confirmed" || confirmationStatus === "confirmed_updated") && (
            <div style={{
              display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12,
              padding: "12px 16px", borderRadius: 10, background: "#EAF2E3", border: "1px solid #C4D9B8",
            }}>
              <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                <SerIcons.CheckCircle size={18} color="#5B7D4F" />
                <span style={{ fontSize: 14, fontWeight: 500, color: "#5B7D4F", letterSpacing: "-0.15px" }}>
                  {confirmationStatus === "confirmed_updated"
                    ? "Confirmed (Updated) — this arrangement has been re-confirmed."
                    : "Confirmed — this arrangement has been signed by the customer."}
                </span>
              </div>
              {onEnterEditMode && (
                <Button variant="outline" size="sm" icon={<SerIcons.Edit size={18} />} onClick={onEnterEditMode}
                  style={{ flexShrink: 0, borderColor: "#9CAE82", color: "#5B7D4F" }}>
                  Enter Edit Mode
                </Button>
              )}
            </div>
          )}
          {confirmationStatus === "amendment_draft" && (
            <div style={{
              display: "flex", alignItems: "center", gap: 10,
              padding: "12px 16px", borderRadius: 10, background: "#E8EDF5", border: "1px solid #B8C8E0",
            }}>
              <SerIcons.Edit size={16} color="#2D4E7D" />
              <span style={{ fontSize: 14, fontWeight: 500, color: "#2D4E7D", letterSpacing: "-0.15px" }}>
                Amendment Draft — changes to casket will be included in the updated arrangement.
              </span>
            </div>
          )}
          {(confirmationStatus === "awaiting" || confirmationStatus === "amended_awaiting") && (
            <div style={{
              padding: "12px 16px", borderRadius: 10, background: "#FDF4E3", border: "1px solid #E8C98A",
              display: "flex", alignItems: "center", gap: 10,
            }}>
              <SerIcons.Clock size={18} color="#9A6B1F" />
              <span style={{ fontSize: 14, fontWeight: 500, color: "#9A6B1F", letterSpacing: "-0.15px" }}>
                Awaiting customer confirmation — the arrangement has been sent for signing.
              </span>
            </div>
          )}

          <header style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 12 }}>
            <div>
              <h1 style={{ font: "500 24px/32px Inter", letterSpacing: "0.07px", color: "var(--fg-primary)", margin: 0 }}>Select Casket</h1>
              <p style={{ fontSize: 14, color: "var(--fg-secondary)", letterSpacing: "-0.15px", margin: "4px 0 0" }}>
                Choose a casket that reflects your preferences. Tap an image to view, or add up to {COMPARE_MAX} to compare side by side.
              </p>
            </div>
          </header>

          <div style={{ display: "grid", gridTemplateColumns: "repeat(3, minmax(0, 1fr))", gap: 18 }}>
            {CASKETS.map((c) => (
              <CasketCardFull
                key={c.id} casket={c}
                selected={selectedCasket && selectedCasket.id === c.id}
                compareChecked={!!comparing.find((x) => x.id === c.id)}
                compareDisabled={comparing.length >= COMPARE_MAX && !comparing.find((x) => x.id === c.id)}
                onSelect={() => onSelect(c)}
                onToggleCompare={() => toggleCompare(c)}
                onOpenDetails={() => setDetailView(c)}
                onOpenLightbox={(images, index) => setLightbox({ images, index, label: `${c.name} (${c.finish})` })}
              />
            ))}
          </div>
        </div>
      </main>

      <OrderSummarySidebar
        caseDetails={caseDetails} caseBrand={brandForReligion(caseDetails.religion)}
        serviceData={serviceData}
        selectedPackage={selectedPackage} selectedCasket={selectedCasket}
        selectedAddOns={selectedAddOns}
        addOnTotal={addOnTotal} addOnCount={addOnCount}
        notes={notes} setNotes={setNotes}
        onEditCase={onEditCase} onJumpTo={onJumpTo}
        onContinue={onContinue}
        continueLabel="Continue to Add-Ons"
        continueDisabled={!selectedCasket}
        activeStep="casket"
        confirmationStatus={confirmationStatus}
        onSendForConfirmation={onSendForConfirmation}
        onViewPdf={onViewPdf}
        onResend={onResend}
        onEditArrangement={onEditArrangement}
        amendmentSnapshot={amendmentSnapshot}
        onEnterEditMode={onEnterEditMode}
        onFinalizeAmendment={onFinalizeAmendment}
        onDiscardAmendment={onDiscardAmendment}
        onSendToCustomer={onSendToCustomer}
        onSimulateSign={onSimulateSign}
        onSendSignedForm={onSendSignedForm}
        appliedCoupon={appliedCoupon}
        onApplyCoupon={onApplyCoupon}
        onRemoveCoupon={onRemoveCoupon}
      />

      {/* Sticky comparison selection bar */}
      <CompareSelectionBar
        caskets={comparing}
        max={COMPARE_MAX}
        onRemove={removeFromCompare}
        onClear={clearCompare}
        onCompare={() => setShowCompare(true)}
      />

      {detailView && (
        <CasketDetailModal
          casket={detailView}
          onClose={() => setDetailView(null)}
          onSelect={() => { onSelect(detailView); setDetailView(null); }}
          onOpenLightbox={(images, index) => setLightbox({ images, index, label: `${detailView.name} (${detailView.finish})` })}
        />
      )}

      {showCompare && comparing.length >= 2 && (
        <CompareCasketModal
          caskets={comparing}
          selectedId={selectedCasket?.id}
          onClose={() => setShowCompare(false)}
          onRemove={removeFromCompare}
          onSelect={(c) => { onSelect(c); setShowCompare(false); }}
          onOpenLightbox={(images, index, label) => setLightbox({ images, index, label })}
        />
      )}

      {lightbox && (
        <Lightbox
          images={lightbox.images}
          startIndex={lightbox.index}
          label={lightbox.label}
          onClose={() => setLightbox(null)}
        />
      )}
    </div>
  );
}

/* ─────────────────────────────────────────────────────────────
   <CasketGallery> — image carousel with arrows, dots, swipe.
   Used everywhere caskets appear (card, detail, compare).

   Props:
     images       string[] of URLs (can be empty)
     fallbackName  string — placeholder text when no images
     aspectRatio  CSS aspect-ratio (default "4/3")
     showArrows   boolean (default true)
     showDots     boolean (default true)
     showThumbs   boolean — render thumbnail strip below (default false)
     onTapImage   (index) => void — fires on click of the main image
                  (used to launch the lightbox)
     stopPropagation  whether arrow/dot clicks bubble (default true)
   ───────────────────────────────────────────────────────────── */
function CasketGallery({
  images, fallbackName, aspectRatio = "4/3",
  showArrows = true, showDots = true, showThumbs = false,
  onTapImage,
  stopPropagation = true,
  rounded = 0,
}) {
  const [index, setIndex] = React.useState(0);
  const touchStartX = React.useRef(null);

  // Reset when images list changes
  React.useEffect(() => { setIndex(0); }, [images]);

  const safeImages = Array.isArray(images) ? images : [];
  const count = safeImages.length;
  const go = (next) => {
    if (count === 0) return;
    setIndex(((next % count) + count) % count);
  };

  const onTouchStart = (e) => { touchStartX.current = e.touches[0].clientX; };
  const onTouchEnd   = (e) => {
    if (touchStartX.current == null) return;
    const dx = e.changedTouches[0].clientX - touchStartX.current;
    if (Math.abs(dx) > 36) go(index + (dx < 0 ? 1 : -1));
    touchStartX.current = null;
  };

  const stop = (e) => stopPropagation && e.stopPropagation();

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: showThumbs ? 12 : 0 }}>
      <div
        onTouchStart={onTouchStart}
        onTouchEnd={onTouchEnd}
        style={{
          position: "relative", aspectRatio, overflow: "hidden",
          borderRadius: rounded,
          background: count === 0
            ? "linear-gradient(180deg, #F0EDE6 0%, #E5E2D9 100%)"
            : "#F0EDE6",
        }}
      >
        {/* Slides: stacked & cross-faded via opacity */}
        {count === 0 ? (
          <GalleryPlaceholder name={fallbackName} />
        ) : (
          safeImages.map((src, i) => (
            <button
              key={src + i}
              type="button"
              onClick={(e) => { stop(e); onTapImage && onTapImage(i); }}
              aria-label={`Image ${i + 1} of ${count}`}
              style={{
                all: "unset",
                cursor: onTapImage ? "zoom-in" : "default",
                position: "absolute", inset: 0,
                background: `url(${src}) center / cover no-repeat`,
                opacity: i === index ? 1 : 0,
                transition: "opacity 300ms ease",
              }}
            />
          ))
        )}

        {/* Arrows */}
        {showArrows && count > 1 && (
          <React.Fragment>
            <GalleryArrow direction="left"  onClick={(e) => { stop(e); go(index - 1); }} />
            <GalleryArrow direction="right" onClick={(e) => { stop(e); go(index + 1); }} />
          </React.Fragment>
        )}

        {/* Dots */}
        {showDots && count > 1 && (
          <div style={{
            position: "absolute", left: "50%", bottom: 8, transform: "translateX(-50%)",
            display: "flex", gap: 4, padding: "4px 7px",
            background: "rgba(15,23,42,0.22)", borderRadius: 999,
          }}>
            {safeImages.map((_, i) => (
              <button
                key={i}
                onClick={(e) => { stop(e); setIndex(i); }}
                style={{
                  all: "unset", cursor: "pointer",
                  width: i === index ? 12 : 5, height: 5, borderRadius: 999,
                  background: i === index ? "#FFFFFF" : "rgba(255,255,255,0.55)",
                  transition: "width 200ms ease, background 200ms ease",
                }}
                aria-label={`Show image ${i + 1}`}
              />
            ))}
          </div>
        )}
      </div>

      {/* Thumbnail strip */}
      {showThumbs && count > 1 && (
        <div style={{ display: "flex", gap: 8, overflowX: "auto", paddingBottom: 2 }}>
          {safeImages.map((src, i) => (
            <button
              key={src + i}
              onClick={(e) => { stop(e); setIndex(i); }}
              style={{
                all: "unset", cursor: "pointer", flexShrink: 0,
                width: 72, height: 56, borderRadius: 6, overflow: "hidden",
                border: `2px solid ${i === index ? "#574F40" : "transparent"}`,
                background: `url(${src}) center / cover no-repeat`,
                opacity: i === index ? 1 : 0.78,
                transition: "border-color 160ms ease, opacity 160ms ease",
              }}
              aria-label={`Thumbnail ${i + 1}`}
            />
          ))}
        </div>
      )}
    </div>
  );
}

function GalleryArrow({ direction, onClick }) {
  const left = direction === "left";
  return (
    <button
      onClick={onClick}
      aria-label={left ? "Previous image" : "Next image"}
      className="ser-gallery-arrow"
      style={{
        all: "unset", cursor: "pointer",
        position: "absolute",
        top: "50%", transform: "translateY(-50%)",
        [left ? "left" : "right"]: 10,
        width: 28, height: 28, borderRadius: "50%",
        background: "rgba(255,255,255,0.86)",
        color: "var(--fg-primary)",
        display: "inline-flex", alignItems: "center", justifyContent: "center",
        boxShadow: "0 2px 6px rgba(15,23,42,0.14)",
        opacity: 0.7,
        transition: "opacity 160ms ease, background 160ms ease",
      }}
      onMouseEnter={(e) => e.currentTarget.style.opacity = 1}
      onMouseLeave={(e) => e.currentTarget.style.opacity = 0.7}
    >
      {left ? <SerIcons.ChevronLeft size={16} /> : <SerIcons.ChevronRight size={16} />}
    </button>
  );
}

function GalleryPlaceholder({ name }) {
  return (
    <div style={{
      position: "absolute", inset: 0, display: "flex", flexDirection: "column",
      alignItems: "center", justifyContent: "center", gap: 8,
    }}>
      <img src="./assets/butterfly-navy.png" alt="" style={{ width: 40, opacity: 0.18 }} />
      <span style={{
        fontFamily: "var(--font-display, 'Cormorant Garamond', serif)",
        fontSize: 22, fontWeight: 500, color: "rgba(31,58,96,0.32)",
        letterSpacing: "0.04em", textAlign: "center", padding: "0 16px",
      }}>{name}</span>
    </div>
  );
}

/* ─────────────────────────────────────────────────────────────
   Casket Card — image-first, matches Package Card patterns
   exactly so selection / compare affordances are consistent
   across both consultation steps:
     - Whole-card click selects
     - Floating selected check in top-left of image
     - Floating compare toggle in top-right of image
     - "View details" as a small text link at the bottom
   ───────────────────────────────────────────────────────────── */
function CasketCardFull({ casket, selected, compareChecked, compareDisabled, onSelect, onToggleCompare, onOpenDetails, onOpenLightbox }) {
  const images = casketImageList(casket);
  return (
    <div
      onClick={onSelect}
      style={{
        background: "#FFFFFF", borderRadius: 12, overflow: "hidden",
        border: `1px solid ${selected ? "var(--border-strong)" : "var(--border-subtle)"}`,
        boxShadow: selected ? "0 4px 6px -4px rgba(0,0,0,0.10), 0 10px 15px -3px rgba(0,0,0,0.10)" : "none",
        cursor: "pointer", display: "flex", flexDirection: "column",
        transition: "border-color 150ms ease, box-shadow 150ms ease, transform 150ms ease",
        transform: selected ? "translateY(-1px)" : "translateY(0)",
      }}
    >
      <div style={{ position: "relative" }}>
        <CasketGallery
          images={images}
          fallbackName={`${casket.name}\n(${casket.finish})`}
          aspectRatio="4/3"
          showArrows
          showDots
          onTapImage={(i) => onOpenLightbox(images, i)}
        />

        {/* Selected indicator — matches Package card: 28×28 slate circle, top-left */}
        {selected && (
          <div style={{
            position: "absolute", left: 12, top: 12, width: 28, height: 28,
            borderRadius: "50%", background: "var(--brand-navy)", color: "#FFFFFF",
            display: "flex", alignItems: "center", justifyContent: "center",
            boxShadow: "0 4px 6px -4px rgba(0,0,0,0.10)",
            zIndex: 2,
          }}>
            <SerIcons.Check size={14} />
          </div>
        )}

        {/* Compare toggle — matches Package card: 28×28 square, top-right */}
        <button
          onClick={(e) => { e.stopPropagation(); !compareDisabled && onToggleCompare(); }}
          disabled={compareDisabled}
          title={compareDisabled ? `Up to ${COMPARE_MAX} caskets can be compared` : (compareChecked ? "Remove from comparison" : "Add to comparison")}
          style={{
            position: "absolute", right: 12, top: 12, width: 40, height: 40,
            borderRadius: 10,
            background: compareChecked ? "var(--brand-navy)" : "rgba(255,255,255,0.92)",
            color: compareChecked ? "#FFFFFF" : "var(--fg-primary)",
            border: "none", cursor: compareDisabled ? "not-allowed" : "pointer",
            display: "flex", alignItems: "center", justifyContent: "center",
            opacity: compareDisabled ? 0.45 : 1,
            zIndex: 2,
          }}
        >
          {compareChecked ? <SerIcons.Check size={20} /> : <SerIcons.Compare size={20} />}
        </button>
      </div>

      <div style={{ padding: 18, display: "flex", flexDirection: "column", gap: 10 }}>
        {/* Name */}
        <button
          onClick={(e) => { e.stopPropagation(); onOpenDetails(); }}
          style={{
            all: "unset", cursor: "pointer",
            fontSize: 18, fontWeight: 500, color: "var(--fg-primary)", letterSpacing: "-0.439px",
            wordBreak: "break-word",
          }}
        >
          {casket.name} <span style={{ color: "var(--fg-secondary)", fontWeight: 400 }}>({casket.finish})</span>
        </button>

        {/* Price + tier */}
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 12, paddingTop: 8, borderTop: "1px solid var(--slate-150)" }}>
          <div>
            <div style={{ fontSize: 22, fontWeight: 500, color: "var(--fg-primary)", letterSpacing: "-0.449px", fontFeatureSettings: "'tnum'" }}>
              {casket.included ? "Included" : `+${formatPrice(casket.upgrade)}`}
            </div>
            <div style={{ fontSize: 12, color: "var(--fg-secondary)" }}>
              {casket.included ? "Included in package" : "Upgrade price"}
            </div>
          </div>
          <Tag variant="cream" wrap>{casket.tier}</Tag>
        </div>

        {/* View details — small text link, matches Package's "View full inclusions →" */}
        <button
          onClick={(e) => { e.stopPropagation(); onOpenDetails(); }}
          style={{
            all: "unset", cursor: "pointer",
            fontSize: 12, color: "var(--fg-primary)", fontWeight: 500, marginTop: 2,
          }}
        >View details →</button>
      </div>
    </div>
  );
}

/* ─────────────────────────────────────────────────────────────
   <CompareSelectionBar> — sticky bottom rail
   ───────────────────────────────────────────────────────────── */
function CompareSelectionBar({ caskets, max, onRemove, onClear, onCompare }) {
  // Slide in/out: render only while content exists, but mount on first show
  // so the entrance transition plays.
  const [visible, setVisible] = React.useState(false);
  React.useEffect(() => {
    if (caskets.length > 0) {
      const t = setTimeout(() => setVisible(true), 10);
      return () => clearTimeout(t);
    }
    setVisible(false);
  }, [caskets.length]);

  if (caskets.length === 0) return null;

  return (
    <div
      style={{
        position: "fixed",
        bottom: 0, left: 0, right: 384,            // clear the order sidebar
        padding: "12px 24px",
        background: "transparent",
        zIndex: 50,
        pointerEvents: "none",
      }}
    >
      <div style={{
        maxWidth: 1280, margin: "0 auto",
        background: "#FFFFFF",
        border: "1px solid var(--border-subtle)",
        borderRadius: 14,
        boxShadow: "0 12px 32px -8px rgba(15,23,42,0.20), 0 4px 12px -4px rgba(15,23,42,0.10)",
        padding: "12px 16px",
        display: "flex", alignItems: "center", gap: 16,
        transform: visible ? "translateY(0)" : "translateY(110%)",
        opacity: visible ? 1 : 0,
        transition: "transform 280ms cubic-bezier(.2,.8,.2,1), opacity 240ms ease",
        pointerEvents: "auto",
      }}>
        <div style={{ display: "flex", flexDirection: "column", gap: 2, flexShrink: 0 }}>
          <span style={{ fontSize: 12, color: "var(--fg-secondary)", letterSpacing: "-0.1px" }}>Comparing</span>
          <span style={{ fontSize: 13, fontWeight: 500, color: "var(--fg-primary)", letterSpacing: "-0.15px" }}>
            {caskets.length} of {max} selected
          </span>
        </div>

        <div style={{
          flex: 1, display: "flex", gap: 8, overflowX: "auto",
          padding: "2px 2px",
        }}>
          {caskets.map((c) => {
            const img = casketImageList(c)[0];
            return (
              <div key={c.id} style={{
                display: "inline-flex", alignItems: "center", gap: 10,
                background: "var(--surface-chip, #EFE7D4)",
                border: "1px solid var(--border-subtle, var(--border-subtle))",
                borderRadius: 10, padding: "4px 10px 4px 4px",
                flexShrink: 0,
              }}>
                <div style={{
                  width: 44, height: 36, borderRadius: 6, overflow: "hidden",
                  background: img
                    ? `url(${img}) center / cover no-repeat`
                    : "linear-gradient(180deg, #F0EDE6 0%, #E5E2D9 100%)",
                  flexShrink: 0,
                }} />
                <div style={{ display: "flex", flexDirection: "column", lineHeight: 1.2 }}>
                  <span style={{ fontSize: 13, fontWeight: 500, color: "var(--fg-primary)", letterSpacing: "-0.15px" }}>
                    {c.name}
                  </span>
                  <span style={{ fontSize: 11, color: "var(--fg-secondary)" }}>
                    {c.finish} · {c.included ? "Included" : `+${formatPrice(c.upgrade)}`}
                  </span>
                </div>
                <button
                  onClick={() => onRemove(c.id)}
                  aria-label={`Remove ${c.name} from comparison`}
                  style={{
                    all: "unset", cursor: "pointer",
                    width: 22, height: 22, borderRadius: 6,
                    display: "inline-flex", alignItems: "center", justifyContent: "center",
                    color: "var(--fg-secondary)",
                  }}
                  onMouseEnter={(e) => e.currentTarget.style.background = "rgba(15,23,42,0.06)"}
                  onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}
                ><SerIcons.Close size={24} /></button>
              </div>
            );
          })}
        </div>

        <div style={{ display: "flex", alignItems: "center", gap: 8, flexShrink: 0 }}>
          <button
            onClick={onClear}
            style={{
              all: "unset", cursor: "pointer",
              fontSize: 13, color: "var(--fg-secondary)", letterSpacing: "-0.15px",
              padding: "8px 10px",
            }}
          >Clear</button>
          <Button
            variant="primary-navy" size="md"
            icon={<SerIcons.Compare size={18} />}
            onClick={onCompare}
            disabled={caskets.length < 2}
          >
            Compare ({caskets.length})
          </Button>
        </div>
      </div>
    </div>
  );
}

/* ─────────────────────────────────────────────────────────────
   <CasketDetailModal> — single-casket detail with gallery
   ───────────────────────────────────────────────────────────── */
function CasketDetailModal({ casket, onClose, onSelect, onOpenLightbox }) {
  const images = casketImageList(casket);
  return (
    <div onClick={onClose} style={{
      position: "fixed", inset: 0, background: "rgba(15,23,42,0.55)",
      display: "flex", alignItems: "center", justifyContent: "center", zIndex: 200, padding: 24,
    }}>
      <div onClick={(e) => e.stopPropagation()} style={{
        width: "100%", maxWidth: 1080, maxHeight: "92vh", background: "#FFFFFF",
        borderRadius: 12, overflow: "hidden", display: "flex", flexDirection: "column",
        boxShadow: "0 20px 25px -5px rgba(0,0,0,0.10)",
      }}>
        <div style={{ padding: "20px 28px", borderBottom: "1px solid var(--border-subtle)", display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
          <div>
            <h2 style={{ font: "500 22px/30px Inter", letterSpacing: "-0.449px", color: "var(--fg-primary)", margin: 0 }}>
              {casket.name} ({casket.finish})
            </h2>
            <div style={{ fontSize: 13, color: "var(--fg-secondary)", marginTop: 4 }}>{casket.tier}</div>
          </div>
          <button onClick={onClose} style={{
            background: "transparent", border: "none", padding: 6, borderRadius: 6, cursor: "pointer", color: "var(--fg-secondary)",
          }}><SerIcons.Close size={24} /></button>
        </div>

        <div style={{ flex: 1, overflowY: "auto", display: "grid", gridTemplateColumns: "1fr 1fr", gap: 28, padding: 28 }}>
          <div>
            <CasketGallery
              images={images}
              fallbackName={`${casket.name}\n(${casket.finish})`}
              aspectRatio="4/3"
              showArrows
              showDots
              showThumbs
              rounded={12}
              onTapImage={(i) => onOpenLightbox(images, i)}
            />
          </div>
          <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
            <div>
              <div style={{ fontSize: 28, fontWeight: 500, color: "var(--fg-primary)", letterSpacing: "-0.449px", fontFeatureSettings: "'tnum'" }}>
                {casket.included ? "Included" : `+${formatPrice(casket.upgrade)}`}
              </div>
              <div style={{ fontSize: 13, color: "var(--fg-secondary)" }}>
                {casket.included ? "Included in package" : "Upgrade price"}
              </div>
            </div>
            <DetailRow label="Material"          value={casket.material} />
            <DetailRow label="Interior"          value={casket.interior} />
            <DetailRow label="Design Highlights" value={casket.designHighlights} />
            <Button variant="primary-navy" size="lg" iconRight={<SerIcons.Check size={18} />} onClick={onSelect} style={{ marginTop: 12 }}>
              Select {casket.name} ({casket.finish})
            </Button>
          </div>
        </div>
      </div>
    </div>
  );
}

function DetailRow({ label, value }) {
  return (
    <div>
      <div style={{ fontSize: 12, color: "var(--fg-secondary)", marginBottom: 2 }}>{label}</div>
      <div style={{ fontSize: 14, fontWeight: 500, color: "var(--fg-primary)", letterSpacing: "-0.15px" }}>{value}</div>
    </div>
  );
}

/* ─────────────────────────────────────────────────────────────
   <CompareCasketModal> — side-by-side with galleries + lightbox
   ───────────────────────────────────────────────────────────── */
function CompareCasketModal({ caskets, selectedId, onClose, onRemove, onSelect, onOpenLightbox }) {
  const cols = Math.max(2, caskets.length);
  return (
    <div onClick={onClose} style={{
      position: "fixed", inset: 0, background: "rgba(15,23,42,0.55)",
      display: "flex", alignItems: "center", justifyContent: "center", zIndex: 200, padding: 24,
    }}>
      <div onClick={(e) => e.stopPropagation()} style={{
        width: "100%", maxWidth: 1280, maxHeight: "92vh", background: "#FFFFFF",
        borderRadius: 14, overflow: "hidden", display: "flex", flexDirection: "column",
      }}>
        <div style={{ padding: "20px 28px", borderBottom: "1px solid var(--border-subtle)", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
          <div>
            <h2 style={{ font: "500 20px/28px Inter", letterSpacing: "-0.449px", color: "var(--fg-primary)", margin: 0 }}>Compare Caskets</h2>
            <p style={{ fontSize: 13, color: "var(--fg-secondary)", margin: "4px 0 0", letterSpacing: "-0.15px" }}>
              Side-by-side comparison · {caskets.length} {caskets.length === 1 ? "option" : "options"}
            </p>
          </div>
          <button
            onClick={onClose}
            aria-label="Close"
            style={{
              background: "transparent", border: "none", padding: 6, borderRadius: 6,
              cursor: "pointer", color: "var(--fg-secondary)",
            }}
          ><SerIcons.Close size={24} /></button>
        </div>

        <div style={{ overflow: "auto", padding: 24 }}>
          {/* Cards row: gallery + name + price + select */}
          <div style={{
            display: "grid",
            gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))`,
            gap: 18,
            marginBottom: 24,
          }}>
            {caskets.map((c) => {
              const images = casketImageList(c);
              const isSelected = selectedId === c.id;
              const label = `${c.name} (${c.finish})`;
              return (
                <div key={c.id} style={{
                  display: "flex", flexDirection: "column", gap: 12,
                  background: "#FFFFFF",
                  border: `1px solid ${isSelected ? "var(--border-strong)" : "var(--border-subtle)"}`,
                  borderRadius: 12, padding: 14,
                  boxShadow: isSelected ? "0 4px 6px -4px rgba(0,0,0,0.10), 0 10px 15px -3px rgba(0,0,0,0.10)" : "none",
                  position: "relative",
                }}>
                  <button
                    onClick={() => onRemove(c.id)}
                    aria-label={`Remove ${c.name} from comparison`}
                    style={{
                      position: "absolute", top: 8, right: 8, zIndex: 3,
                      all: "unset", cursor: "pointer",
                      width: 26, height: 26, borderRadius: 6,
                      display: "inline-flex", alignItems: "center", justifyContent: "center",
                      background: "rgba(255,255,255,0.94)", color: "var(--fg-secondary)",
                      boxShadow: "0 2px 8px rgba(15,23,42,0.18)",
                    }}
                  ><SerIcons.Close size={16} /></button>

                  <CasketGallery
                    images={images}
                    fallbackName={label}
                    aspectRatio="4/3"
                    showArrows
                    showDots
                    showThumbs
                    rounded={8}
                    onTapImage={(i) => onOpenLightbox(images, i, label)}
                  />

                  <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
                    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", gap: 10 }}>
                      <h3 style={{
                        font: "500 17px/22px Inter", letterSpacing: "-0.35px", color: "var(--fg-primary)", margin: 0,
                        overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", minWidth: 0,
                      }}>
                        {c.name} <span style={{ color: "var(--fg-secondary)", fontWeight: 400 }}>({c.finish})</span>
                      </h3>
                    </div>
                    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                      <span style={{ fontSize: 22, fontWeight: 500, color: "var(--fg-primary)", letterSpacing: "-0.45px", fontFeatureSettings: "'tnum'" }}>
                        {c.included ? "Included" : `+${formatPrice(c.upgrade)}`}
                      </span>
                      <Tag variant="cream">{c.tier}</Tag>
                    </div>
                  </div>

                  <Button
                    variant={isSelected ? "secondary" : "primary-slate"}
                    size="sm"
                    iconRight={isSelected ? null : <SerIcons.Check size={14} />}
                    onClick={() => onSelect(c)}
                  >
                    {isSelected ? "Selected" : "Select"}
                  </Button>
                </div>
              );
            })}
          </div>

          {/* Aligned attribute table */}
          <CompareAttrTable caskets={caskets} cols={cols} />
        </div>
      </div>
    </div>
  );
}

function CompareAttrTable({ caskets, cols }) {
  const rows = [
    { label: "Price",             render: (c) => c.included ? "Included" : `+${formatPrice(c.upgrade)}`,
                                  highlight: true },
    { label: "Tier",              render: (c) => c.tier },
    { label: "Material",          render: (c) => c.material },
    { label: "Interior",          render: (c) => c.interior },
    { label: "Design Highlights", render: (c) => c.designHighlights, span: true },
  ];

  return (
    <div style={{
      background: "#FFFFFF", border: "1px solid var(--border-subtle)", borderRadius: 12,
      overflow: "hidden",
    }}>
      {rows.map((row, ri) => (
        <div
          key={row.label}
          style={{
            display: "grid",
            gridTemplateColumns: `220px repeat(${cols}, minmax(0, 1fr))`,
            borderBottom: ri === rows.length - 1 ? "none" : "1px solid var(--slate-150)",
            background: row.highlight ? "var(--surface-chip, #EFE7D4)" : "#FFFFFF",
          }}
        >
          <div style={{
            padding: "16px 18px",
            fontSize: 12, color: "var(--fg-secondary)", fontWeight: 500,
            textTransform: "uppercase", letterSpacing: "0.04em",
            borderRight: "1px solid var(--slate-150)",
          }}>{row.label}</div>
          {caskets.map((c) => (
            <div
              key={c.id}
              style={{
                padding: "16px 18px",
                fontSize: row.highlight ? 16 : 14,
                fontWeight: row.highlight ? 500 : 400,
                color: "var(--fg-primary)", letterSpacing: "-0.15px",
                fontFeatureSettings: row.highlight ? "'tnum'" : undefined,
                borderRight: "1px solid var(--slate-150)",
              }}
            >
              {row.render(c) || <span style={{ color: "var(--fg-tertiary)", fontStyle: "italic" }}>—</span>}
            </div>
          ))}
        </div>
      ))}
    </div>
  );
}

/* ─────────────────────────────────────────────────────────────
   <Lightbox> — fullscreen image viewer.
   All chrome is anchored to the viewport so controls never
   shift when image dimensions change:
     Close  → always top-right
     Prev   → always left-center
     Next   → always right-center
     Thumbs → always bottom-center
   Image fills the safe zone between the fixed chrome.
   Keyboard arrows, Esc, and touch swipe all supported.
   ───────────────────────────────────────────────────────────── */
function Lightbox({ images, startIndex = 0, label, onClose }) {
  const [index, setIndex] = React.useState(startIndex);
  const touchStartX = React.useRef(null);

  React.useEffect(() => {
    const onKey = (e) => {
      if (e.key === "Escape")          onClose();
      else if (e.key === "ArrowLeft")  setIndex((i) => (i - 1 + images.length) % images.length);
      else if (e.key === "ArrowRight") setIndex((i) => (i + 1) % images.length);
    };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [images.length, onClose]);

  if (!images || images.length === 0) return null;

  const prev  = () => setIndex((i) => (i - 1 + images.length) % images.length);
  const next  = () => setIndex((i) => (i + 1) % images.length);
  const multi = images.length > 1;

  const onTouchStart = (e) => { touchStartX.current = e.touches[0].clientX; };
  const onTouchEnd   = (e) => {
    if (touchStartX.current === null || images.length < 2) return;
    const dx = e.changedTouches[0].clientX - touchStartX.current;
    if (Math.abs(dx) > 40) { dx < 0 ? next() : prev(); }
    touchStartX.current = null;
  };

  // ── Fixed layout constants (all px) ──────────────────────
  // These define the safe zone for the image area. Every
  // chrome element is pinned to the viewport using these
  // same measurements so nothing moves between images.
  const NAV_EDGE = 20;   // nav buttons: distance from viewport edge
  const NAV_SIZE = 48;   // nav button diameter
  const IMG_TOP  = 76;   // image top: clears close button
  const THUMB_B  = 24;   // thumbnail strip: distance from viewport bottom
  const THUMB_H  = 50;   // thumbnail height
  const LABEL_H  = 44;   // label + counter area height
  // Image bottom edge: leave room for label then thumbs (if multi)
  const IMG_BOT  = multi
    ? THUMB_B + THUMB_H + 10 + LABEL_H + 8   // 136
    : (label ? 68 : 32);
  // Image side inset: clear nav buttons (if multi)
  const IMG_SIDE = multi ? NAV_EDGE + NAV_SIZE + 16 : 32;   // 84 or 32

  // Shared frosted-glass button style (close, prev, next)
  const glassBtn = {
    all: "unset",
    cursor: "pointer", touchAction: "manipulation",
    borderRadius: "50%",
    display: "inline-flex", alignItems: "center", justifyContent: "center",
    background: "rgba(255,255,255,0.10)",
    border: "1px solid rgba(255,255,255,0.16)",
    backdropFilter: "blur(8px)",
    color: "#FFFFFF",
    zIndex: 10,
    boxSizing: "border-box",
  };

  return (
    <div
      onPointerDown={onClose}
      style={{
        position: "fixed", inset: 0,
        background: "rgba(10,16,30,0.94)",
        zIndex: 400,
        overflow: "hidden",
      }}
    >
      {/* ── Close — viewport top-right, never moves ── */}
      <button
        onPointerDown={(e) => { e.stopPropagation(); onClose(); }}
        aria-label="Close"
        style={{
          ...glassBtn,
          position: "absolute", top: 20, right: 20,
          width: 44, height: 44,
        }}
      >
        <SerIcons.Close size={20} />
      </button>

      {/* ── Prev — viewport left-center, never moves ── */}
      {multi && (
        <button
          onPointerDown={(e) => { e.preventDefault(); e.stopPropagation(); prev(); }}
          aria-label="Previous image"
          style={{
            ...glassBtn,
            position: "absolute", left: NAV_EDGE, top: "50%",
            width: NAV_SIZE, height: NAV_SIZE,
            transform: "translateY(-50%)",
          }}
        >
          <SerIcons.ChevronLeft size={22} />
        </button>
      )}

      {/* ── Next — viewport right-center, never moves ── */}
      {multi && (
        <button
          onPointerDown={(e) => { e.preventDefault(); e.stopPropagation(); next(); }}
          aria-label="Next image"
          style={{
            ...glassBtn,
            position: "absolute", right: NAV_EDGE, top: "50%",
            width: NAV_SIZE, height: NAV_SIZE,
            transform: "translateY(-50%)",
          }}
        >
          <SerIcons.ChevronRight size={22} />
        </button>
      )}

      {/* ── Image zone — fills safe area between all fixed chrome ── */}
      <div
        onPointerDown={(e) => e.stopPropagation()}
        onTouchStart={onTouchStart}
        onTouchEnd={onTouchEnd}
        style={{
          position: "absolute",
          top: IMG_TOP, bottom: IMG_BOT,
          left: IMG_SIDE, right: IMG_SIDE,
          display: "flex", alignItems: "center", justifyContent: "center",
        }}
      >
        <img
          src={images[index]}
          alt={label || ""}
          style={{
            maxWidth: "100%",
            maxHeight: "100%",
            objectFit: "contain",
            borderRadius: 10,
            boxShadow: "0 24px 80px rgba(0,0,0,0.60)",
            display: "block",
          }}
        />
      </div>

      {/* ── Label + counter — constant position, above thumbnail strip ── */}
      <div
        onPointerDown={(e) => e.stopPropagation()}
        style={{
          position: "absolute",
          bottom: multi ? THUMB_B + THUMB_H + 10 : 24,
          left: 0, right: 0,
          display: "flex", flexDirection: "column", alignItems: "center", gap: 3,
          pointerEvents: "none",
        }}
      >
        {label && (
          <span style={{
            fontSize: 15, fontWeight: 500,
            color: "rgba(255,255,255,0.90)", letterSpacing: "-0.2px",
          }}>
            {label}
          </span>
        )}
        {multi && (
          <span style={{ fontSize: 12, color: "rgba(255,255,255,0.40)", letterSpacing: "-0.05px" }}>
            {index + 1} of {images.length}
          </span>
        )}
      </div>

      {/* ── Thumbnail strip — fixed viewport bottom, never moves ── */}
      {multi && (
        <div
          onPointerDown={(e) => e.stopPropagation()}
          style={{
            position: "absolute",
            bottom: THUMB_B, left: 0, right: 0,
            display: "flex", gap: 6, alignItems: "center", justifyContent: "center",
            paddingLeft: 24, paddingRight: 24,
            overflowX: "auto",
          }}
        >
          {images.map((src, i) => (
            <button
              key={i}
              onPointerDown={(e) => { e.preventDefault(); e.stopPropagation(); setIndex(i); }}
              aria-label={`Go to image ${i + 1}`}
              style={{
                all: "unset", cursor: "pointer", touchAction: "manipulation",
                width: 62, height: THUMB_H, borderRadius: 6,
                overflow: "hidden", flexShrink: 0, boxSizing: "border-box",
                border: i === index
                  ? "2px solid rgba(255,255,255,0.90)"
                  : "2px solid rgba(255,255,255,0.18)",
                opacity: i === index ? 1 : 0.48,
                transition: "opacity 140ms ease, border-color 140ms ease",
              }}
            >
              <img src={src} alt="" style={{ width: "100%", height: "100%", objectFit: "cover", display: "block" }} />
            </button>
          ))}
        </div>
      )}
    </div>
  );
}

Object.assign(window, {
  CasketScreen, CasketCardFull,
  CasketGallery, CasketDetailModal, CompareCasketModal,
  CompareSelectionBar, Lightbox,
  casketImageList,
});
