// mariusson — secondary surfaces
// DetailModal · CommissionDialog · SubmitDialog · RoomDrawer · SavedDrawer · AccountGate
// All Bauhaus-headed, all account-aware.

// Local mobile-detection hook — each surfaces.jsx component subscribes
// to the same (max-width:600px) breakpoint Atlas uses.
function useIsMobileLocal() {
  const [m, setM] = React.useState(() =>
    typeof window !== 'undefined' && window.matchMedia('(max-width: 760px)').matches
  );
  React.useEffect(() => {
    if (typeof window === 'undefined') return;
    const mq = window.matchMedia('(max-width: 760px)');
    const fn = () => setM(mq.matches);
    if (mq.addEventListener) mq.addEventListener('change', fn);
    else mq.addListener(fn);
    return () => {
      if (mq.removeEventListener) mq.removeEventListener('change', fn);
      else mq.removeListener(fn);
    };
  }, []);
  return m;
}

// ─── DETAIL MODAL ─────────────────────────────────────────
function DetailModal({ work, role, visible, onClose, onArtist }) {
  const isMobile = useIsMobileLocal();
  return (
    <div data-atlas-panel style={{
      position: 'absolute', inset: 0, zIndex: 45,
      background: visible ? 'var(--paper-veil)' : 'transparent',
      display: 'flex', alignItems: isMobile ? 'stretch' : 'center', justifyContent: 'center',
      transition: 'background 320ms var(--ease-out)',
      opacity: visible ? 1 : 0,
      padding: isMobile ? 8 : 0,
      boxSizing: 'border-box',
    }} onClick={onClose}>
      <div data-atlas-dialog onClick={(e) => e.stopPropagation()} style={{
        width: isMobile ? '100%' : 'min(900px, 92%)',
        height: isMobile ? '100%' : 'min(580px, 92%)',
        maxHeight: isMobile ? 'calc(100vh - 16px)' : undefined,
        background: BAU.paper, border: `1px solid ${BAU.ink}`,
        borderRadius: isMobile ? 'var(--r-lg)' : 0,
        display: isMobile ? 'flex' : 'grid',
        flexDirection: isMobile ? 'column' : undefined,
        gridTemplateColumns: isMobile ? undefined : '1.1fr 1fr',
        transform: visible ? 'scale(1) translateY(0)' : 'scale(0.96) translateY(8px)',
        opacity: visible ? 1 : 0,
        transition: 'transform 320ms var(--ease-out), opacity 280ms var(--ease-out)',
        overflow: isMobile ? 'auto' : 'hidden',
        boxSizing: 'border-box',
      }}>
        <div style={{
          background: BAU.paper2, position: 'relative',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          padding: isMobile ? 16 : 32,
          flex: isMobile ? '0 0 auto' : undefined,
          minHeight: isMobile ? 240 : undefined,
        }}>
          <MagnifyingArtwork work={work} maxSize={isMobile ? 260 : 420} />
          <div style={{ position: 'absolute', top: 16, left: 16, display: 'flex', gap: 4 }}>
            <span style={{ width: 12, height: 12, borderRadius: '50%', background: BAU.red }} />
            <span style={{ width: 12, height: 12, background: BAU.yellow }} />
            <span style={{ width: 0, height: 0, borderLeft: '6px solid transparent', borderRight: '6px solid transparent', borderBottom: `12px solid ${BAU.blue}` }} />
          </div>
        </div>
        <div style={{
          padding: isMobile ? 20 : 36,
          display: 'flex', flexDirection: 'column', gap: isMobile ? 12 : 14,
          minWidth: 0,
        }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.18em', color: BAU.graphite, textTransform: 'uppercase' }}>
              {work.id} · {work.year}
            </span>
            <button onClick={onClose} style={{
              width: isMobile ? 36 : 24, height: isMobile ? 36 : 24,
              background: 'transparent', border: `1px solid ${BAU.ink}`,
              borderRadius: isMobile ? '50%' : 0,
              cursor: 'pointer', fontSize: isMobile ? 18 : 14, color: BAU.ink, lineHeight: 1, padding: 0,
            }}>×</button>
          </div>
          <h2 style={{ fontFamily: 'var(--serif)', fontSize: isMobile ? 30 : 44, margin: 0, lineHeight: 0.95, letterSpacing: '-0.02em', fontWeight: 400 }}>
            <span style={{ fontStyle: 'italic' }}>{work.title}</span>
          </h2>
          <button onClick={onArtist} style={{
            padding: 0, background: 'transparent', border: 'none',
            fontSize: 15, color: BAU.ink, cursor: 'pointer', textAlign: 'left',
            borderBottom: `1px solid ${BAU.ink}`, alignSelf: 'flex-start',
          }}>{work.artist} · {work.region} →</button>

          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10, marginTop: 8 }}>
            <DetailRow label="Style" value={work.style} />
            <DetailRow label="Method" value={work.method} />
            <DetailRow label="Theme" value={work.theme} />
            <DetailRow label="Year" value={String(work.year)} />
          </div>

          <p style={{ fontSize: 13, color: BAU.ink, lineHeight: 1.55, margin: '8px 0 0', fontFamily: 'var(--serif)' }}>
            A {work.method.toLowerCase()} on {work.style.toLowerCase()} register, made in {work.year}. Part of an ongoing study on {work.theme.toLowerCase()}.
          </p>

          <div style={{ flex: 1 }} />

          {work.price && (
            <div style={{
              padding: 14, background: BAU.paper2, border: `1px solid ${BAU.rule}`,
              display: 'flex', justifyContent: 'space-between', alignItems: 'center',
            }}>
              <div>
                <div style={{ fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.16em', color: BAU.graphite, textTransform: 'uppercase' }}>List price</div>
                <div style={{ fontFamily: 'var(--serif)', fontSize: 22, fontStyle: 'italic' }}>€{work.price.toLocaleString()}</div>
              </div>
              <button onClick={onArtist} style={{
                background: BAU.ink, color: BAU.paper, border: 'none', padding: '10px 18px',
                fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: '0.16em',
                textTransform: 'uppercase', cursor: 'pointer',
              }}>To artist →</button>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

function DetailRow({ label, value }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 2, paddingBottom: 6, borderBottom: `1px solid ${BAU.rule}` }}>
      <span style={{ fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.16em', color: BAU.graphite, textTransform: 'uppercase' }}>{label}</span>
      <span style={{ fontFamily: 'var(--serif)', fontSize: 16, fontStyle: 'italic' }}>{value}</span>
    </div>
  );
}

// ─── MAGNIFYING ARTWORK ───────────────────────────────────
// Hover (or touch-and-drag) to magnify any part of the work. Click to lock
// the lens onto a chosen detail; click again or press Escape to release.
//
// Implementation: a circular div with the same image as background, scaled
// up. CSS background-position percentages align the image's chosen point
// with the lens centre — no canvas, no extra fetches.
function MagnifyingArtwork({ work, maxSize = 420 }) {
  const aspect = work.aspect || 1;
  const w = aspect >= 1 ? maxSize : Math.round(maxSize * aspect);
  const h = aspect >= 1 ? Math.round(maxSize / aspect) : maxSize;

  const ZOOM = 2.8;
  const LENS = 320;
  const containerRef = React.useRef(null);
  const [pos, setPos] = React.useState(null);   // { x, y } as 0..100 of container
  const [locked, setLocked] = React.useState(false);
  const [hover, setHover] = React.useState(false);

  // Track the cursor as a raw container-relative percentage (can be
  // negative or >100 when the cursor wanders outside the painting). The
  // lens centre uses the raw value so it follows the cursor smoothly —
  // when reading the magnified content we clamp to 0..100 so we keep
  // showing the nearest edge of the image instead of a blank.
  const updateFromEvent = React.useCallback((clientX, clientY) => {
    const r = containerRef.current?.getBoundingClientRect();
    if (!r) return;
    const x = ((clientX - r.left) / r.width) * 100;
    const y = ((clientY - r.top) / r.height) * 100;
    setPos({ x, y });
  }, []);

  // Grace zone: how far past the painting edge the cursor can drift before
  // the lens releases. ~80px ≈ 2 cm at typical 96 dpi. Lets the user park
  // the lens centre on a corner and keep nudging the cursor outwards to
  // keep that detail centred — without the bubble vanishing.
  const GRACE_PX = 80;

  const onClick = (e) => {
    updateFromEvent(e.clientX, e.clientY);
    setLocked((v) => !v);
  };
  const onTouchMove = (e) => {
    const t = e.touches[0]; if (!t) return;
    e.preventDefault();
    updateFromEvent(t.clientX, t.clientY);
    setHover(true);
  };

  // Window-level mousemove tracks cursor as long as we're hovered or locked.
  // While inside the painting OR the grace ring, we keep updating `pos` —
  // since pos is RAW (unclamped), the lens centre follows the cursor past
  // the painting edge while the magnified content (which uses a clamped
  // 0..100 lookup) keeps showing the corner. Smooth tracking, no snag.
  // Once the cursor leaves the extended zone entirely we release.
  React.useEffect(() => {
    if (!hover && !locked) return;
    const onWin = (e) => {
      const r = containerRef.current?.getBoundingClientRect();
      if (!r) return;
      const x = e.clientX, y = e.clientY;
      const inGrace =
        x >= r.left - GRACE_PX && x <= r.right + GRACE_PX &&
        y >= r.top - GRACE_PX && y <= r.bottom + GRACE_PX;

      if (inGrace) {
        if (!locked) updateFromEvent(x, y);
      } else {
        // Cursor has truly left the painting region — release.
        if (!locked) { setHover(false); setPos(null); }
      }
    };
    window.addEventListener('mousemove', onWin);
    return () => window.removeEventListener('mousemove', onWin);
  }, [hover, locked, updateFromEvent]);

  // Esc unlocks the loupe
  React.useEffect(() => {
    if (!locked) return;
    const onKey = (e) => { if (e.key === 'Escape') setLocked(false); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [locked]);

  const showLens = (hover || locked) && pos;

  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 12 }}>
      <div
        ref={containerRef}
        onMouseEnter={(e) => { setHover(true); updateFromEvent(e.clientX, e.clientY); }}
        onTouchStart={onTouchMove}
        onTouchMove={onTouchMove}
        onTouchEnd={() => { if (!locked) { setHover(false); setPos(null); } }}
        onClick={onClick}
        style={{
          position: 'relative',
          width: w, height: h,
          boxShadow: '0 40px 80px rgba(0,0,0,0.22)',
          cursor: locked ? 'zoom-out' : 'zoom-in',
          touchAction: 'none',
          userSelect: 'none',
        }}>
        {work.image ? (
          <img src={work.image} alt={work.title}
            draggable={false}
            style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block', pointerEvents: 'none' }} />
        ) : (
          <ArtTile work={work} width={w} height={h} />
        )}

        {/* Lens — circular. The lens CENTRE follows the raw cursor (can sit
            past the painting edges, in the grace zone). The MAGNIFIED CONTENT
            uses a clamped 0..100 lookup so we keep showing the nearest edge
            of the image instead of a blank — the corner detail stays in the
            centre of the bubble while you keep nudging outwards. */}
        {showLens && work.image && (() => {
          const cx = Math.max(0, Math.min(100, pos.x));
          const cy = Math.max(0, Math.min(100, pos.y));
          return (
            <div style={{
              position: 'absolute',
              left: `${pos.x}%`, top: `${pos.y}%`,
              width: LENS, height: LENS,
              marginLeft: -LENS / 2, marginTop: -LENS / 2,
              borderRadius: '50%', overflow: 'hidden',
              backgroundImage: `url(${work.image})`,
              backgroundRepeat: 'no-repeat',
              backgroundSize: `${ZOOM * 100}% auto`,
              backgroundPosition: `${cx}% ${cy}%`,
              border: `1.5px solid ${locked ? BAU.red : BAU.ink}`,
              boxShadow: `0 14px 36px rgba(0,0,0,0.38), 0 0 0 6px ${locked ? 'rgba(230,57,70,0.18)' : 'rgba(255,255,255,0.10)'} inset`,
              pointerEvents: 'none',
              transition: locked ? 'border-color 200ms var(--ease-out), box-shadow 200ms var(--ease-out)' : 'none',
            }} />
          );
        })()}

        {/* Locked badge */}
        {locked && (
          <div style={{
            position: 'absolute', top: 12, right: 12,
            background: BAU.red, color: BAU.paper,
            padding: '3px 8px',
            fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.18em',
            textTransform: 'uppercase', pointerEvents: 'none',
          }}>● Locked</div>
        )}
      </div>

      {/* Hint — explicit since the loupe behaviour isn't obvious */}
      <div style={{
        display: 'flex', alignItems: 'center', gap: 8,
        fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.16em',
        color: BAU.graphite, textTransform: 'uppercase', textAlign: 'center',
      }}>
        <svg width="13" height="13" viewBox="0 0 13 13" fill="none" stroke="currentColor" strokeWidth="1.2">
          <circle cx="5.5" cy="5.5" r="3.5" />
          <line x1="8" y1="8" x2="11.5" y2="11.5" strokeLinecap="round" />
          <line x1="4" y1="5.5" x2="7" y2="5.5" strokeLinecap="round" />
          <line x1="5.5" y1="4" x2="5.5" y2="7" strokeLinecap="round" />
        </svg>
        <span>{locked ? 'Locked — click to release' : 'Hover to magnify · click to lock'}</span>
      </div>
    </div>
  );
}

// ─── COMMISSION DIALOG ─────────────────────────────────────
function CommissionDialog({ work, bio, buyer, visible, onClose, onSubmit }) {
  // Two modes: 'commission' (default) or 'donate'.  Donation only enabled
  // if the artist has it on; default to commission either way.
  const [mode, setMode] = React.useState('commission');
  const [step, setStep] = React.useState('compose'); // 'compose' | 'pay' | 'done'
  const [brief, setBrief] = React.useState('');
  const [budget, setBudget] = React.useState(work.price || 5000);
  const [size, setSize] = React.useState('Medium · 60×80');
  const [donation, setDonation] = React.useState(50);
  const [donateMessage, setDonateMessage] = React.useState('');
  const acceptsDonations = bio?.acceptsDonations;

  // Saved cards from this buyer's profile (managed in Studio drawer).
  // If they have any, default to the first; user can switch to "new card"
  // to enter one ad-hoc.
  const savedCards = (buyer && window.useSavedCards) ? window.useSavedCards(buyer.id) : [];
  const [paymentMode, setPaymentMode] = React.useState('saved'); // 'saved' | 'new'
  const [selectedCardId, setSelectedCardId] = React.useState(null);
  React.useEffect(() => {
    if (savedCards.length && !selectedCardId) {
      setSelectedCardId(savedCards[0].id);
      setPaymentMode('saved');
    } else if (!savedCards.length) {
      setPaymentMode('new');
    }
  }, [savedCards.length]);

  // Card form state (only relevant when paymentMode === 'new')
  const [card, setCard] = React.useState({
    holder: buyer?.name || '', number: '', expMonth: '', expYear: '', cvc: '',
  });
  const [saveCardForLater, setSaveCardForLater] = React.useState(true);
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState(null);
  const [order, setOrder] = React.useState(null);

  const amount = mode === 'donate' ? Number(donation) || 0 : Number(budget) || 0;
  const canPay = amount > 0;

  const handleCharge = async () => {
    setBusy(true); setError(null);
    try {
      const usingSaved = paymentMode === 'saved' && selectedCardId;
      const savedCard = usingSaved ? savedCards.find((c) => c.id === selectedCardId) : null;
      const ord = await window.AN_PAY.processPayment({
        card: usingSaved ? null : card,
        savedCard,
        amount,
        type: mode,
        work,
        artistName: work.artist,
        buyer,
        extra: { brief, size, note: donateMessage },
      });
      // If user paid with a brand-new card and asked to save it, persist
      // it now (after the charge succeeded so we don't save bad cards).
      if (!usingSaved && saveCardForLater && buyer && window.AN_PAY?.addCard) {
        try { window.AN_PAY.addCard(buyer.id, card); } catch {}
      }
      setOrder(ord);
      setStep('done');
      onSubmit && onSubmit({ mode, amount, order: ord });
    } catch (e) {
      setError(e.message || 'Payment failed');
    } finally {
      setBusy(false);
    }
  };
  const contactOptions = [];
  if (bio?.website) contactOptions.push({ kind: 'Website', label: bio.website, href: `https://${bio.website}`, accent: BAU.red });
  if (bio?.email) contactOptions.push({ kind: 'Email', label: bio.email, href: `mailto:${bio.email}`, accent: BAU.yellow });
  (bio?.socials || []).forEach((s) => contactOptions.push({ kind: s.kind, label: s.handle, href: `https://${s.url}`, accent: BAU.blue }));
  return (
    <div data-atlas-panel style={{
      position: 'absolute', inset: 0, zIndex: 60,
      background: visible ? 'rgba(14,14,12,0.45)' : 'rgba(14,14,12,0)',
      backdropFilter: visible ? 'blur(8px)' : 'blur(0px)',
      WebkitBackdropFilter: visible ? 'blur(8px)' : 'blur(0px)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      transition: 'background 280ms var(--ease-out), backdrop-filter 280ms var(--ease-out), -webkit-backdrop-filter 280ms var(--ease-out)',
    }} onClick={onClose}>
      <div data-atlas-dialog onClick={(e) => e.stopPropagation()} style={{
        width: 540, background: BAU.paper, border: `1px solid ${BAU.ink}`,
        transform: visible ? 'scale(1) translateY(0)' : 'scale(0.96) translateY(8px)',
        opacity: visible ? 1 : 0,
        transition: 'transform 280ms var(--ease-out), opacity 240ms var(--ease-out)',
      }}>
        <div style={{ display: 'flex', borderBottom: `1px solid ${BAU.ink}`, height: 8 }}>
          <div style={{ background: BAU.yellow, flex: 4 }} />
          <div style={{ background: BAU.red, flex: 1 }} />
          <div style={{ background: BAU.ink, flex: 2 }} />
        </div>
        <div style={{ padding: 28, display: 'flex', flexDirection: 'column', gap: 14 }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
            <div>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.18em', color: BAU.graphite, textTransform: 'uppercase' }}>
                {step === 'pay' ? `Payment · ${mode === 'donate' ? 'Donation' : 'Commission'}` : step === 'done' ? 'Receipt' : (mode === 'donate' ? 'Donate' : 'Commission')} · {work.artist}
              </div>
              <h2 style={{ fontFamily: 'var(--serif)', fontSize: 28, margin: '4px 0 0', lineHeight: 1.05, fontWeight: 400 }}>
                <span style={{ fontStyle: 'italic' }}>
                  {step === 'pay' ? `Pay €${amount.toLocaleString()}` :
                   step === 'done' ? 'Confirmed' :
                   mode === 'donate' ? 'Support the studio' : 'A new work, in the spirit of'}
                </span>{step === 'compose' && mode !== 'donate' ? ` ${work.title}` : ''}
              </h2>
            </div>
            <button onClick={onClose} style={{
              width: 24, height: 24, background: 'transparent', border: `1px solid ${BAU.ink}`,
              cursor: 'pointer', fontSize: 14, color: BAU.ink, lineHeight: 1, padding: 0,
            }}>×</button>
          </div>

          {/* Step strip — only shown for the multi-step flow */}
          {step !== 'done' && (
            <div style={{ display: 'flex', gap: 4 }}>
              <div style={{ flex: 1, height: 3, background: BAU.ink }} />
              <div style={{ flex: 1, height: 3, background: step === 'pay' ? BAU.ink : BAU.rule }} />
            </div>
          )}

          {step === 'compose' && (
          <>
          {/* Mode toggle — Commission / Donate (Donate only if artist accepts) */}
          <div style={{ display: 'grid', gridTemplateColumns: acceptsDonations ? '1fr 1fr' : '1fr', border: `1px solid ${BAU.ink}` }}>
            <button onClick={() => setMode('commission')} style={{
              padding: '10px 12px', cursor: 'pointer', textAlign: 'left',
              background: mode === 'commission' ? BAU.ink : BAU.paper,
              color: mode === 'commission' ? BAU.paper : BAU.ink,
              border: 'none', borderRight: acceptsDonations ? `1px solid ${BAU.ink}` : 'none',
              fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase',
            }}>● Commission a work</button>
            {acceptsDonations && (
              <button onClick={() => setMode('donate')} style={{
                padding: '10px 12px', cursor: 'pointer', textAlign: 'left',
                background: mode === 'donate' ? BAU.ink : BAU.paper,
                color: mode === 'donate' ? BAU.paper : BAU.ink,
                border: 'none',
                fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase',
              }}>♡ Donate to the studio</button>
            )}
          </div>

          {mode === 'commission' && (
            <>
              <Input label="Brief" value={brief} onChange={setBrief} multi placeholder="A quiet domestic scene, north light, cool whites…" />
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
                <Input label="Size" value={size} onChange={setSize} placeholder="Medium · 60×80" />
                <Input label="Budget · EUR" value={budget} onChange={(v) => setBudget(v)} placeholder="5000" />
              </div>
            </>
          )}

          {mode === 'donate' && (
            <>
              <div style={{ fontFamily: 'var(--serif)', fontSize: 14, fontStyle: 'italic', color: BAU.graphite, lineHeight: 1.5, textWrap: 'pretty' }}>
                A direct contribution to the studio — covers materials, time, and the long quiet stretches between shows. No work changes hands.
              </div>
              <div>
                <div style={{ fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.18em', color: BAU.graphite, textTransform: 'uppercase', marginBottom: 6 }}>Amount · EUR</div>
                <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                  {[20, 50, 100, 250, 500].map((v) => (
                    <button key={v} onClick={() => setDonation(v)} style={{
                      padding: '8px 14px', cursor: 'pointer',
                      background: donation === v ? BAU.ink : BAU.paper,
                      color: donation === v ? BAU.paper : BAU.ink,
                      border: `1px solid ${BAU.ink}`,
                      fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: '0.12em',
                    }}>€{v}</button>
                  ))}
                  <input type="number" value={donation} onChange={(e) => setDonation(Number(e.target.value) || 0)} style={{
                    width: 90, padding: '8px 10px', border: `1px solid ${BAU.ink}`, background: BAU.paper2,
                    fontFamily: 'var(--mono)', fontSize: 11, color: BAU.ink, outline: 'none',
                  }} />
                </div>
              </div>
              <Input label="A note (optional)" value={donateMessage} onChange={setDonateMessage} multi placeholder="What this work means to me…" />
            </>
          )}

          {/* Direct contact channels — always visible if any exist */}
          {contactOptions.length > 0 && (
            <div style={{ borderTop: `1px solid ${BAU.rule}`, paddingTop: 12 }}>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.18em', color: BAU.graphite, textTransform: 'uppercase', marginBottom: 8 }}>
                ↳ Or reach the studio directly
              </div>
              <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                {contactOptions.map((c) => (
                  <a key={c.kind} href={c.href} target="_blank" rel="noreferrer" style={{
                    display: 'inline-flex', alignItems: 'center', gap: 6,
                    padding: '6px 10px', border: `1px solid ${BAU.ink}`,
                    background: BAU.paper, color: BAU.ink, textDecoration: 'none',
                    fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.14em', textTransform: 'uppercase',
                  }}>
                    <span style={{ width: 5, height: 5, background: c.accent }} />
                    {c.kind} · <span style={{ fontFamily: 'var(--serif)', fontSize: 13, fontStyle: 'italic', textTransform: 'none', letterSpacing: 0 }}>{c.label}</span> ↗
                  </a>
                ))}
              </div>
            </div>
          )}

          <div style={{ display: 'flex', gap: 8, marginTop: 6 }}>
            <button onClick={onClose} style={{
              background: 'transparent', border: `1px solid ${BAU.ink}`, padding: '10px 16px',
              fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em',
              textTransform: 'uppercase', cursor: 'pointer', color: BAU.ink,
            }}>← Cancel</button>
            <div style={{ flex: 1 }} />
            <button
              onClick={() => { if (canPay) setStep('pay'); else setError('Set an amount above 0'); }}
              disabled={!canPay}
              style={{
                background: canPay ? BAU.ink : BAU.graphite,
                color: BAU.paper, border: 'none', padding: '10px 18px',
                fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em',
                textTransform: 'uppercase', cursor: canPay ? 'pointer' : 'not-allowed',
              }}>{mode === 'donate' ? `Donate €${donation} →` : `Continue · €${amount.toLocaleString()} →`}</button>
          </div>
          </>
          )}

          {step === 'pay' && (
            <>
              {/* Order summary */}
              <div style={{
                border: `1px solid ${BAU.rule}`, padding: '12px 14px',
                background: BAU.paper2,
                fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: '0.04em',
                display: 'grid', gridTemplateColumns: '1fr auto', gap: 4,
              }}>
                <span style={{ color: BAU.graphite }}>{mode === 'donate' ? 'Donation to' : 'Commission to'}</span>
                <span style={{ color: BAU.ink, textAlign: 'right' }}>{work.artist}</span>
                {mode === 'commission' && (<>
                  <span style={{ color: BAU.graphite }}>Size</span>
                  <span style={{ color: BAU.ink, textAlign: 'right' }}>{size}</span>
                </>)}
                <span style={{ color: BAU.graphite, paddingTop: 8, borderTop: `1px solid ${BAU.rule}` }}>Total</span>
                <span style={{ color: BAU.ink, textAlign: 'right', paddingTop: 8, borderTop: `1px solid ${BAU.rule}`, fontWeight: 600 }}>
                  €{amount.toLocaleString()}
                </span>
              </div>

              {/* Saved cards picker (if any) — radio list, plus a "use a
                  different card" option that swaps in the manual form. */}
              {savedCards.length > 0 && (
                <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                  <div style={{ fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.18em', color: BAU.graphite, textTransform: 'uppercase' }}>
                    Pay with
                  </div>
                  {savedCards.map((c) => {
                    const sel = paymentMode === 'saved' && selectedCardId === c.id;
                    return (
                      <button key={c.id} type="button"
                        onClick={() => { setPaymentMode('saved'); setSelectedCardId(c.id); }}
                        style={{
                          display: 'flex', alignItems: 'center', gap: 10,
                          padding: '10px 12px', cursor: 'pointer', textAlign: 'left',
                          background: sel ? BAU.paper2 : BAU.paper,
                          border: `1px solid ${sel ? BAU.ink : BAU.rule}`,
                        }}>
                        <span style={{
                          width: 12, height: 12, borderRadius: '50%',
                          border: `1px solid ${BAU.ink}`,
                          background: sel ? BAU.ink : 'transparent',
                          flexShrink: 0,
                        }} />
                        <span style={{ flex: 1, fontFamily: 'var(--mono)', fontSize: 11.5, color: BAU.ink }}>
                          {c.brand} ····{c.last4}
                          <span style={{ color: BAU.graphite, marginLeft: 8 }}>
                            {c.holder} · exp {c.expMonth}/{String(c.expYear).slice(-2)}
                          </span>
                        </span>
                      </button>
                    );
                  })}
                  <button type="button"
                    onClick={() => { setPaymentMode('new'); setSelectedCardId(null); }}
                    style={{
                      display: 'flex', alignItems: 'center', gap: 10,
                      padding: '10px 12px', cursor: 'pointer', textAlign: 'left',
                      background: paymentMode === 'new' ? BAU.paper2 : BAU.paper,
                      border: `1px solid ${paymentMode === 'new' ? BAU.ink : BAU.rule}`,
                    }}>
                    <span style={{
                      width: 12, height: 12, borderRadius: '50%',
                      border: `1px solid ${BAU.ink}`,
                      background: paymentMode === 'new' ? BAU.ink : 'transparent',
                      flexShrink: 0,
                    }} />
                    <span style={{ fontFamily: 'var(--mono)', fontSize: 11.5, color: BAU.ink }}>
                      Use a different card
                    </span>
                  </button>
                </div>
              )}

              {/* Manual card form — visible when "new" or no saved cards. */}
              {paymentMode === 'new' && (
                <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
                  <Input label="Cardholder name"
                    value={card.holder}
                    onChange={(v) => setCard((c) => ({ ...c, holder: v }))}
                    placeholder="As printed on the card" />
                  <CardNumberInput
                    value={card.number}
                    onChange={(v) => setCard((c) => ({ ...c, number: v }))}
                    brand={window.AN_PAY?.detectBrand(card.number)} />
                  <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 14 }}>
                    <Input label="Exp month" value={card.expMonth}
                      onChange={(v) => setCard((c) => ({ ...c, expMonth: v.replace(/\D/g, '').slice(0, 2) }))}
                      placeholder="MM" />
                    <Input label="Exp year" value={card.expYear}
                      onChange={(v) => setCard((c) => ({ ...c, expYear: v.replace(/\D/g, '').slice(0, 4) }))}
                      placeholder="YY or YYYY" />
                    <Input label="CVC" value={card.cvc}
                      onChange={(v) => setCard((c) => ({ ...c, cvc: v.replace(/\D/g, '').slice(0, 4) }))}
                      placeholder="123" type="password" />
                  </div>
                  {buyer && (
                    <label style={{
                      display: 'flex', alignItems: 'center', gap: 8,
                      cursor: 'pointer',
                      fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.14em',
                      color: BAU.graphite, textTransform: 'uppercase',
                    }}>
                      <input type="checkbox" checked={saveCardForLater}
                        onChange={(e) => setSaveCardForLater(e.target.checked)}
                        style={{ width: 14, height: 14 }} />
                      Save card for next time
                    </label>
                  )}
                  <div style={{
                    fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.14em',
                    color: BAU.graphite, textTransform: 'uppercase',
                  }}>
                    ▢ Test: 4242 4242 4242 4242 succeeds · 4000 0000 0000 0002 declines
                  </div>
                </div>
              )}

              {error && <ErrorLine message={error} />}

              <div style={{ display: 'flex', gap: 8, marginTop: 6 }}>
                <button onClick={() => { setStep('compose'); setError(null); }} disabled={busy} style={{
                  background: 'transparent', border: `1px solid ${BAU.ink}`, padding: '10px 16px',
                  fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em',
                  textTransform: 'uppercase', cursor: busy ? 'wait' : 'pointer', color: BAU.ink,
                }}>← Back</button>
                <div style={{ flex: 1 }} />
                <button onClick={handleCharge} disabled={busy} style={{
                  background: busy ? BAU.graphite : BAU.ink,
                  color: BAU.paper, border: 'none', padding: '10px 18px',
                  fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em',
                  textTransform: 'uppercase', cursor: busy ? 'wait' : 'pointer',
                }}>{busy ? 'Processing…' : `Pay €${amount.toLocaleString()} →`}</button>
              </div>
            </>
          )}

          {step === 'done' && order && (
            <>
              <div style={{
                padding: '20px 24px', background: BAU.paper2,
                border: `1px solid ${BAU.ink}`,
                display: 'flex', flexDirection: 'column', gap: 14,
              }}>
                {/* Bauhaus tick */}
                <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
                  <div style={{
                    width: 40, height: 40, background: BAU.blue,
                    display: 'flex', alignItems: 'center', justifyContent: 'center',
                    color: BAU.paper, fontFamily: 'var(--serif)', fontSize: 24, fontWeight: 600,
                  }}>✓</div>
                  <div>
                    <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.18em', color: BAU.graphite, textTransform: 'uppercase' }}>
                      Paid · {new Date(order.createdAt).toLocaleString()}
                    </div>
                    <div style={{ fontFamily: 'var(--serif)', fontSize: 22, fontStyle: 'italic' }}>
                      €{order.amount.toLocaleString()} to {order.artistName}
                    </div>
                  </div>
                </div>
                <div style={{
                  fontFamily: 'var(--mono)', fontSize: 11, color: BAU.ink,
                  display: 'grid', gridTemplateColumns: '1fr auto', rowGap: 4,
                }}>
                  <span style={{ color: BAU.graphite }}>Transaction</span>
                  <span style={{ textAlign: 'right' }}>{order.id}</span>
                  <span style={{ color: BAU.graphite }}>Card</span>
                  <span style={{ textAlign: 'right' }}>{order.card.brand} ····{order.card.last4}</span>
                  <span style={{ color: BAU.graphite }}>Type</span>
                  <span style={{ textAlign: 'right', textTransform: 'uppercase' }}>{order.type}</span>
                  {order.workTitle && (<>
                    <span style={{ color: BAU.graphite }}>In the spirit of</span>
                    <span style={{ textAlign: 'right', fontFamily: 'var(--serif)', fontStyle: 'italic', textTransform: 'none' }}>{order.workTitle}</span>
                  </>)}
                </div>
                <div style={{ fontFamily: 'var(--serif)', fontSize: 13, fontStyle: 'italic', color: BAU.graphite, lineHeight: 1.5 }}>
                  {order.type === 'donate'
                    ? 'A receipt has been sent to your email. The studio has been notified.'
                    : 'Your brief is on its way. The artist will respond within seven days.'}
                </div>
              </div>

              <div style={{ display: 'flex', gap: 8, marginTop: 6 }}>
                <div style={{ flex: 1 }} />
                <button onClick={onClose} style={{
                  background: BAU.ink, color: BAU.paper, border: 'none', padding: '10px 18px',
                  fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em',
                  textTransform: 'uppercase', cursor: 'pointer',
                }}>Done</button>
              </div>
            </>
          )}
        </div>
      </div>
    </div>
  );
}

// CardNumberInput — formats the card number with spaces every 4 digits and
// shows the detected brand in the corner.
function CardNumberInput({ value, onChange, brand }) {
  const handle = (s) => {
    const clean = s.replace(/\D/g, '').slice(0, 19);
    onChange(clean);
  };
  const formatted = value.replace(/(.{4})/g, '$1 ').trim();
  return (
    <label style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
      <span style={{ fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.18em', color: BAU.graphite, textTransform: 'uppercase' }}>
        Card number
      </span>
      <div style={{ position: 'relative' }}>
        <input value={formatted} onChange={(e) => handle(e.target.value)}
          placeholder="4242 4242 4242 4242"
          autoComplete="cc-number" inputMode="numeric"
          style={{
            width: '100%', boxSizing: 'border-box',
            border: 'none', borderBottom: `1px solid ${BAU.ink}`,
            background: 'transparent', padding: '8px 0',
            fontFamily: 'var(--serif)', fontSize: 17, fontStyle: 'italic',
            color: BAU.ink, outline: 'none',
            letterSpacing: '0.04em',
          }} />
        {value && (
          <span style={{
            position: 'absolute', right: 0, top: 8,
            fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.16em',
            textTransform: 'uppercase', color: BAU.graphite,
          }}>{brand}</span>
        )}
      </div>
    </label>
  );
}

// ─── SUBMIT (artist consign) DIALOG ────────────────────────
// Two-step: (1) the work, (2) listing & protection.
function SubmitDialog({ visible, onClose, onSubmit, defaultRegion }) {
  const [step, setStep] = React.useState(0);
  const [title, setTitle] = React.useState('');
  const [method, setMethod] = React.useState('Oil');
  const [year, setYear] = React.useState(new Date().getFullYear());
  const [region, setRegion] = React.useState(defaultRegion || 'France');
  const [style, setStyle] = React.useState('Modernist');
  const [theme, setTheme] = React.useState('Memory');
  const [viewOnly, setViewOnly] = React.useState(false);
  const [price, setPrice] = React.useState('4500');
  const [edition, setEdition] = React.useState('Unique');
  const [protections, setProtections] = React.useState({
    watermark: true,        // forensic invisible watermark
    overlay: true,          // visible session overlay over image
    screenshot: true,       // anti-screenshot (interstitial blur on capture)
    rightclick: true,       // disable right-click + drag-save
    provenance: true,       // chain-of-custody / cert. of authenticity
    zoom: false,            // limit max zoom
  });
  const toggle = (k) => setProtections((p) => ({ ...p, [k]: !p[k] }));

  // Image upload state
  const [file, setFile] = React.useState(null);
  const [preview, setPreview] = React.useState(null);
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState(null);
  const fileInputRef = React.useRef(null);

  const pickFile = () => fileInputRef.current?.click();
  const handleFile = (f) => {
    if (!f) return;
    if (!/^image\//.test(f.type)) {
      setError('Pick an image file (JPEG, PNG, etc.)'); return;
    }
    if (f.size > 25 * 1024 * 1024) {
      setError('Image is over 25 MB. Please pick a smaller file.'); return;
    }
    setError(null);
    setFile(f);
    const reader = new FileReader();
    reader.onload = () => setPreview(reader.result);
    reader.readAsDataURL(f);
  };
  const handleDrop = (e) => {
    e.preventDefault(); e.stopPropagation();
    const f = e.dataTransfer?.files?.[0];
    handleFile(f);
  };

  const canAdvance = !!file && !!title.trim();

  const submit = () => {
    if (!file) { setStep(0); setError('Pick an image first'); return; }
    setBusy(true); setError(null);
    onSubmit({
      file,
      title, method, year, region, style, theme,
      listing: viewOnly ? 'view-only' : 'for-sale',
      price: viewOnly ? null : Number(price) || null,
      edition,
      protections,
    }, (err) => {
      setBusy(false);
      if (err) setError(err.message || 'Could not consign work');
    });
  };

  return (
    <div data-atlas-panel style={{
      position: 'absolute', inset: 0, zIndex: 60,
      background: visible ? 'rgba(14,14,12,0.45)' : 'rgba(14,14,12,0)',
      backdropFilter: visible ? 'blur(8px)' : 'blur(0px)',
      WebkitBackdropFilter: visible ? 'blur(8px)' : 'blur(0px)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      transition: 'background 280ms var(--ease-out), backdrop-filter 280ms var(--ease-out), -webkit-backdrop-filter 280ms var(--ease-out)',
    }} onClick={onClose}>
      <div data-atlas-dialog onClick={(e) => e.stopPropagation()} style={{
        width: 620, maxHeight: '90%', overflow: 'hidden',
        background: BAU.paper, border: `1px solid ${BAU.ink}`,
        transform: visible ? 'scale(1) translateY(0)' : 'scale(0.96) translateY(8px)',
        opacity: visible ? 1 : 0,
        transition: 'transform 280ms var(--ease-out), opacity 240ms var(--ease-out)',
        display: 'flex', flexDirection: 'column',
      }}>
        <div style={{ display: 'flex', borderBottom: `1px solid ${BAU.ink}`, height: 8, flexShrink: 0 }}>
          <div style={{ background: BAU.red, flex: 1 }} />
          <div style={{ background: BAU.ink, flex: 4 }} />
          <div style={{ background: BAU.blue, flex: 2 }} />
        </div>
        <div style={{ padding: '24px 28px 14px', flexShrink: 0, borderBottom: `1px solid ${BAU.rule}` }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.18em', color: BAU.graphite, textTransform: 'uppercase' }}>
                Consign · {step === 0 ? 'STEP 01 / THE WORK' : 'STEP 02 / LISTING & PROTECTION'}
              </div>
              <h2 style={{ fontFamily: 'var(--serif)', fontSize: 30, margin: '4px 0 0', lineHeight: 1.05, fontWeight: 400 }}>
                <span style={{ fontStyle: 'italic' }}>{step === 0 ? 'Submit a work for review' : 'How it should live on the platform'}</span>
              </h2>
            </div>
            <button onClick={onClose} style={{
              width: 24, height: 24, background: 'transparent', border: `1px solid ${BAU.ink}`,
              cursor: 'pointer', fontSize: 14, color: BAU.ink, lineHeight: 1, padding: 0, flexShrink: 0,
            }}>×</button>
          </div>
          {/* step strip */}
          <div style={{ marginTop: 14, display: 'flex', gap: 4 }}>
            <div style={{ flex: 1, height: 3, background: BAU.ink }} />
            <div style={{ flex: 1, height: 3, background: step >= 1 ? BAU.ink : BAU.rule }} />
          </div>
        </div>

        <div style={{ padding: '22px 28px 24px', display: 'flex', flexDirection: 'column', gap: 14, overflowY: 'auto' }}>
        {step === 0 && (
          <>
            {/* Hidden file input + click/drop area */}
            <input ref={fileInputRef} type="file" accept="image/*" style={{ display: 'none' }}
              onChange={(e) => handleFile(e.target.files && e.target.files[0])} />
            <div onClick={pickFile}
              onDragOver={(e) => { e.preventDefault(); e.stopPropagation(); }}
              onDrop={handleDrop}
              style={{
                border: `1px dashed ${BAU.ink}`,
                minHeight: preview ? 220 : 140,
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                background: BAU.paper2,
                cursor: 'pointer', position: 'relative', overflow: 'hidden',
              }}>
              {preview ? (
                <>
                  <img src={preview} alt="upload preview" style={{
                    maxWidth: '100%', maxHeight: 320, display: 'block',
                  }} />
                  <div style={{
                    position: 'absolute', top: 8, right: 8,
                    background: BAU.ink, color: BAU.paper,
                    padding: '5px 10px',
                    fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.16em',
                    textTransform: 'uppercase',
                  }}>
                    {file?.name?.slice(0, 32) || 'image'} · click to replace
                  </div>
                </>
              ) : (
                <div style={{
                  fontFamily: 'var(--mono)', fontSize: 10.5, letterSpacing: '0.16em',
                  color: BAU.graphite, textTransform: 'uppercase', textAlign: 'center', padding: 16,
                }}>↑ Drag image here · or click to browse<br />
                <span style={{ fontSize: 9, opacity: 0.7 }}>JPEG, PNG, WebP — up to 25 MB</span></div>
              )}
            </div>
            {error && <ErrorLine message={error} />}
            <Input label="Title" value={title} onChange={setTitle} placeholder="Untitled (Salt, II)" />
            <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: 14 }}>
              <SelectField label="Method" value={method} onChange={setMethod}
                options={window.METHODS || []} />
              <Input label="Year" value={year} onChange={setYear} placeholder="2025" />
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 14 }}>
              <SelectField label="Region" value={region} onChange={setRegion}
                options={window.REGIONS || []} />
              <SelectField label="Style" value={style} onChange={setStyle}
                options={window.STYLES || []} />
              <SelectField label="Theme" value={theme} onChange={setTheme}
                options={window.THEMES || []} />
            </div>
          </>
        )}

        {step === 1 && (
          <>
            {/* Listing mode toggle */}
            <div>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.18em', color: BAU.graphite, textTransform: 'uppercase', marginBottom: 8 }}>
                Listing mode
              </div>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', border: `1px solid ${BAU.ink}` }}>
                <ModeCell active={!viewOnly} onClick={() => setViewOnly(false)}
                  accent={BAU.red} title="For sale"
                  body="Available for purchase or private offer. Listed price visible to verified collectors." />
                <ModeCell active={viewOnly} onClick={() => setViewOnly(true)}
                  accent={BAU.blue} title="View only"
                  body="Displayed in the catalogue but not for sale. Use for archival or non-commercial works." />
              </div>
            </div>

            {/* Price (collapses smoothly when view-only) */}
            <div style={{
              maxHeight: viewOnly ? 0 : 200,
              opacity: viewOnly ? 0 : 1,
              overflow: 'hidden',
              transition: 'max-height 0.4s var(--ease-out), opacity 0.3s',
            }}>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14, paddingTop: 4 }}>
                <Input label="Price (€)" value={price} onChange={setPrice} placeholder="4500" />
                <Input label="Edition" value={edition} onChange={setEdition} placeholder="Unique · 1/1" />
              </div>
            </div>

            {/* Protection */}
            <div style={{ marginTop: 4 }}>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.18em', color: BAU.graphite, textTransform: 'uppercase', marginBottom: 4 }}>
                Protection · how the image is shown
              </div>
              <div style={{ fontFamily: 'var(--serif)', fontSize: 13, fontStyle: 'italic', color: BAU.graphite, marginBottom: 12, textWrap: 'pretty' }}>
                mariusson never serves your full-resolution file to a viewer's browser. These layers stack on top.
              </div>
              <div style={{ border: `1px solid ${BAU.rule}`, display: 'flex', flexDirection: 'column' }}>
                <ProtectionRow
                  on={protections.watermark} onToggle={() => toggle('watermark')}
                  accent={BAU.red}
                  title="Forensic watermark"
                  body="Each viewer's session embeds an invisible signature. Leaked images can be traced to the account that captured them." />
                <ProtectionRow
                  on={protections.overlay} onToggle={() => toggle('overlay')}
                  accent={BAU.yellow}
                  title="Session overlay"
                  body="A faint, animated mosaic floats over the artwork while it's on screen — visible enough to spoil any direct screen capture." />
                <ProtectionRow
                  on={protections.screenshot} onToggle={() => toggle('screenshot')}
                  accent={BAU.blue}
                  title="Anti-screenshot interstitial"
                  body="On supported devices, screenshot attempts blur the canvas and log the event to the work's provenance trail." />
                <ProtectionRow
                  on={protections.rightclick} onToggle={() => toggle('rightclick')}
                  accent={BAU.ink}
                  title="No right-click / drag-save"
                  body="Disables save-as, drag-to-desktop, and the iOS long-press image menu on the public surface." />
                <ProtectionRow
                  on={protections.provenance} onToggle={() => toggle('provenance')}
                  accent={BAU.red}
                  title="Provenance ledger"
                  body="Issues a signed certificate of authenticity. Every view, offer, and transfer is appended to a tamper-evident chain." />
                <ProtectionRow
                  on={protections.zoom} onToggle={() => toggle('zoom')}
                  accent={BAU.blue} last
                  title="Limit zoom resolution"
                  body="Caps in-browser zoom so detail-level pixels can't be mosaicked together from multiple captures." />
              </div>
            </div>
          </>
        )}

        <div style={{ display: 'flex', gap: 8, marginTop: 6 }}>
          <button onClick={() => step === 0 ? onClose() : setStep(0)} style={{
            background: 'transparent', border: `1px solid ${BAU.ink}`, padding: '10px 16px',
            fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em',
            textTransform: 'uppercase', cursor: 'pointer', color: BAU.ink,
          }}>← {step === 0 ? 'Cancel' : 'Back'}</button>
          <div style={{ flex: 1 }} />
          {step === 0 ? (
            <button onClick={() => { if (canAdvance) setStep(1); else setError('Pick an image and a title first'); }}
              disabled={!canAdvance}
              style={{
                background: canAdvance ? BAU.ink : BAU.graphite,
                color: BAU.paper, border: 'none', padding: '10px 18px',
                fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em',
                textTransform: 'uppercase', cursor: canAdvance ? 'pointer' : 'not-allowed',
              }}>Next · listing →</button>
          ) : (
            <>
              {error && <ErrorLine message={error} />}
              <button onClick={submit} disabled={busy} style={{
                background: busy ? BAU.graphite : BAU.ink,
                color: BAU.paper, border: 'none', padding: '10px 18px',
                fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em',
                textTransform: 'uppercase', cursor: busy ? 'wait' : 'pointer',
              }}>{busy ? 'Consigning…' : 'Consign →'}</button>
            </>
          )}
        </div>
        </div>
      </div>
    </div>
  );
}

function ModeCell({ active, onClick, accent, title, body }) {
  return (
    <button onClick={onClick} style={{
      textAlign: 'left', padding: '14px 16px',
      background: active ? BAU.ink : BAU.paper,
      color: active ? BAU.paper : BAU.ink,
      border: 'none', borderRight: `1px solid ${active ? BAU.ink : BAU.rule}`,
      cursor: 'pointer', position: 'relative',
      transition: 'background 0.25s, color 0.25s',
    }}>
      <div style={{ position: 'absolute', top: 0, left: 0, width: 24, height: 4, background: accent }} />
      <div style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.18em', textTransform: 'uppercase', marginTop: 4 }}>
        {active ? '● ' : '○ '}{title}
      </div>
      <div style={{ fontFamily: 'var(--serif)', fontSize: 13, fontStyle: 'italic', marginTop: 6, lineHeight: 1.4, opacity: active ? 0.85 : 0.7 }}>
        {body}
      </div>
    </button>
  );
}

function ProtectionRow({ on, onToggle, title, body, accent, last }) {
  return (
    <div onClick={onToggle} style={{
      display: 'grid', gridTemplateColumns: '36px 1fr 44px',
      gap: 12, padding: '12px 14px',
      borderBottom: last ? 'none' : `1px solid ${BAU.rule}`,
      cursor: 'pointer', alignItems: 'center',
      background: on ? BAU.paper2 : BAU.paper,
      transition: 'background 0.2s',
    }}>
      <div style={{ width: 18, height: 18, background: accent, alignSelf: 'flex-start', marginTop: 2 }} />
      <div>
        <div style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em', color: BAU.ink, textTransform: 'uppercase' }}>
          {title}
        </div>
        <div style={{ fontFamily: 'var(--serif)', fontSize: 13, fontStyle: 'italic', color: BAU.graphite, marginTop: 3, lineHeight: 1.35, textWrap: 'pretty' }}>
          {body}
        </div>
      </div>
      {/* mini toggle */}
      <div style={{
        width: 36, height: 20, borderRadius: 10,
        background: on ? BAU.ink : BAU.rule,
        position: 'relative', transition: 'background 0.25s',
        justifySelf: 'flex-end',
      }}>
        <div style={{
          position: 'absolute', top: 2, left: on ? 18 : 2,
          width: 16, height: 16, borderRadius: '50%',
          background: BAU.paper,
          transition: 'left 0.25s var(--ease-spring)',
        }} />
      </div>
    </div>
  );
}

// ─── ROLE SWITCH DIALOG ────────────────────────────────────
// Toggle between Artist and Collector. Shows what each surfaces.
function RoleSwitchDialog({ role, visible, onClose, onPick }) {
  return (
    <div data-atlas-panel style={{
      position: 'absolute', inset: 0, zIndex: 60,
      background: visible ? 'rgba(14,14,12,0.45)' : 'rgba(14,14,12,0)',
      backdropFilter: visible ? 'blur(8px)' : 'blur(0px)',
      WebkitBackdropFilter: visible ? 'blur(8px)' : 'blur(0px)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      transition: 'background 280ms var(--ease-out), backdrop-filter 280ms var(--ease-out), -webkit-backdrop-filter 280ms var(--ease-out)',
    }} onClick={onClose}>
      <div data-atlas-dialog onClick={(e) => e.stopPropagation()} style={{
        width: 560, background: BAU.paper, border: `1px solid ${BAU.ink}`,
        transform: visible ? 'scale(1) translateY(0)' : 'scale(0.96) translateY(8px)',
        opacity: visible ? 1 : 0,
        transition: 'transform 280ms var(--ease-out), opacity 240ms var(--ease-out)',
      }}>
        <div style={{ display: 'flex', borderBottom: `1px solid ${BAU.ink}`, height: 8 }}>
          <div style={{ background: BAU.red, flex: 2 }} />
          <div style={{ background: BAU.yellow, flex: 1 }} />
          <div style={{ background: BAU.blue, flex: 3 }} />
        </div>
        <div style={{ padding: '24px 28px 22px' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
            <div>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.18em', color: BAU.graphite, textTransform: 'uppercase' }}>
                Switch role
              </div>
              <h2 style={{ fontFamily: 'var(--serif)', fontSize: 28, margin: '4px 0 0', lineHeight: 1.05, fontWeight: 400 }}>
                <span style={{ fontStyle: 'italic' }}>How are you here today?</span>
              </h2>
              <p style={{ fontFamily: 'var(--serif)', fontSize: 14, fontStyle: 'italic', color: BAU.graphite, margin: '8px 0 0', maxWidth: 440 }}>
                Your account holds both. Switching changes what's foregrounded — actions, surfaces, even the chrome's accent.
              </p>
            </div>
            <button onClick={onClose} style={{
              width: 24, height: 24, background: 'transparent', border: `1px solid ${BAU.ink}`,
              cursor: 'pointer', fontSize: 14, color: BAU.ink, lineHeight: 1, padding: 0,
            }}>×</button>
          </div>

          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginTop: 20 }}>
            <RoleCard
              active={role === 'artist'} onClick={() => onPick('artist')}
              accent={BAU.red} mark="A"
              title="Artist"
              caption="Submit, sell, manage portfolio"
              bullets={['Consign new works', 'Cover Flow portfolio', 'Commission inbox', 'Listing & protection controls']} />
            <RoleCard
              active={role === 'collector'} onClick={() => onPick('collector')}
              accent={BAU.blue} mark="C"
              title="Collector"
              caption="Discover, acquire, follow"
              bullets={['Spatial discovery', 'Private offers', 'The Room (commentary)', 'Provenance ledger access']} />
          </div>

          <div style={{ marginTop: 18, fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.16em', color: BAU.graphite, textTransform: 'uppercase' }}>
            ↳ Currently signed in as <span style={{ color: BAU.ink }}>{role}</span>
          </div>
        </div>
      </div>
    </div>
  );
}

function RoleCard({ active, onClick, accent, mark, title, caption, bullets }) {
  return (
    <button onClick={onClick} style={{
      textAlign: 'left', padding: '18px 16px 16px',
      background: active ? BAU.ink : BAU.paper,
      color: active ? BAU.paper : BAU.ink,
      border: `1px solid ${BAU.ink}`,
      cursor: 'pointer', position: 'relative',
      transition: 'background 0.25s, color 0.25s, transform 0.25s',
    }}
      onMouseEnter={(e) => { if (!active) e.currentTarget.style.transform = 'translateY(-2px)'; }}
      onMouseLeave={(e) => { e.currentTarget.style.transform = 'translateY(0)'; }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
        <div style={{
          width: 38, height: 38, background: accent,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          fontFamily: 'var(--serif)', fontSize: 22, fontStyle: 'italic',
          color: BAU.paper,
        }}>{mark}</div>
        <div>
          <div style={{ fontFamily: 'var(--serif)', fontSize: 22, fontStyle: 'italic', lineHeight: 1 }}>{title}</div>
          <div style={{ fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.16em', textTransform: 'uppercase', marginTop: 4, opacity: 0.7 }}>
            {caption}
          </div>
        </div>
      </div>
      <ul style={{ margin: '14px 0 0', padding: 0, listStyle: 'none', display: 'flex', flexDirection: 'column', gap: 6 }}>
        {bullets.map((b, i) => (
          <li key={i} style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.12em', textTransform: 'uppercase', opacity: 0.85, display: 'flex', gap: 8 }}>
            <span style={{ color: accent }}>→</span> {b}
          </li>
        ))}
      </ul>
      <div style={{ marginTop: 12, fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.18em', textTransform: 'uppercase', opacity: 0.6 }}>
        {active ? '● Active' : '○ Switch to'}
      </div>
    </button>
  );
}

// ─── ROOM (commentary) DRAWER ──────────────────────────────
function RoomDrawer({ work, visible, onClose, onPost }) {
  const [draft, setDraft] = React.useState('');
  // Posts the user has actually submitted in this room — persisted via
  // localStorage so they accumulate. Newest first.
  const userPosts = window.useRoomPosts ? window.useRoomPosts(work.id) : [];
  const seedComments = React.useMemo(() => {
    const r = rng(hash('room' + work.id));
    const handles = ['m.lange', 'henrik', 'iris.k', 'anouk', 'pavel.n'];
    const lines = [
      'The light at the edge feels deliberate — like a held breath.',
      'I keep returning to the corner. It refuses to settle.',
      'Something about the materials reminds me of Morandi.',
      'Bought one from this period. Aged into something quieter.',
      'The artist is in Antwerp this week — saw them at the studio.',
    ];
    return Array.from({ length: 3 }, (_, i) => ({
      who: handles[Math.floor(r() * handles.length)],
      when: ['2h', '6h', '1d', '2d'][Math.floor(r() * 4)],
      text: lines[Math.floor(r() * lines.length)],
    }));
  }, [work.id]);
  const allComments = [...userPosts, ...seedComments];

  return (
    <div data-atlas-panel style={{
      position: 'absolute', inset: 0, zIndex: 50,
      background: visible ? 'rgba(14,14,12,0.4)' : 'rgba(14,14,12,0)',
      backdropFilter: visible ? 'blur(8px)' : 'blur(0px)',
      WebkitBackdropFilter: visible ? 'blur(8px)' : 'blur(0px)',
      transition: 'background 320ms var(--ease-out), backdrop-filter 320ms var(--ease-out), -webkit-backdrop-filter 320ms var(--ease-out)',
    }} onClick={onClose}>
      <div data-atlas-drawer onClick={(e) => e.stopPropagation()} style={{
        position: 'absolute', top: 0, left: 0, bottom: 0, width: 'min(440px, 92%)',
        background: BAU.paper, borderRight: `1px solid ${BAU.ink}`,
        transform: visible ? 'translateX(0)' : 'translateX(-100%)',
        transition: 'transform 380ms var(--ease-out)',
        display: 'flex', flexDirection: 'column',
      }}>
        <div style={{ display: 'flex', height: 8 }}>
          <div style={{ background: BAU.blue, flex: 2 }} />
          <div style={{ background: BAU.yellow, flex: 1 }} />
          <div style={{ background: BAU.ink, flex: 3 }} />
        </div>
        <div style={{ padding: '20px 24px', borderBottom: `1px solid ${BAU.rule}`, display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
          <div>
            <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.18em', color: BAU.graphite, textTransform: 'uppercase' }}>
              The Room · {work.id}
            </div>
            <h2 style={{ fontFamily: 'var(--serif)', fontSize: 26, margin: '4px 0 0', lineHeight: 1, fontWeight: 400, fontStyle: 'italic' }}>
              {work.title}
            </h2>
          </div>
          <button onClick={onClose} style={{
            width: 24, height: 24, background: 'transparent', border: `1px solid ${BAU.ink}`,
            cursor: 'pointer', fontSize: 14, color: BAU.ink, lineHeight: 1, padding: 0,
          }}>×</button>
        </div>
        <div style={{ flex: 1, overflowY: 'auto', padding: '12px 24px', display: 'flex', flexDirection: 'column', gap: 14 }}>
          {allComments.map((c, i) => (
            <div key={c.id || i} style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <span style={{ width: 6, height: 6, borderRadius: '50%', background: [BAU.red, BAU.yellow, BAU.blue][i % 3] }} />
                <span style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.14em', color: BAU.ink, textTransform: 'uppercase' }}>{c.who}</span>
                <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.14em', color: BAU.graphite, textTransform: 'uppercase' }}>· {c.when}</span>
              </div>
              <div style={{ fontFamily: 'var(--serif)', fontSize: 14.5, fontStyle: 'italic', color: BAU.ink, lineHeight: 1.4, paddingLeft: 14 }}>
                {c.text}
              </div>
            </div>
          ))}
        </div>
        <div style={{ borderTop: `1px solid ${BAU.rule}`, padding: 16 }}>
          <textarea
            value={draft}
            onChange={(e) => setDraft(e.target.value)}
            placeholder="Add to the room…"
            style={{
              width: '100%', minHeight: 60, resize: 'none', boxSizing: 'border-box',
              border: `1px solid ${BAU.rule}`, padding: 10,
              fontFamily: 'var(--serif)', fontSize: 14, fontStyle: 'italic', color: BAU.ink,
              outline: 'none', background: BAU.paper2,
            }} />
          <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: 8 }}>
            <button onClick={() => { onPost(draft); setDraft(''); }} style={{
              background: BAU.ink, color: BAU.paper, border: 'none', padding: '8px 16px',
              fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em',
              textTransform: 'uppercase', cursor: 'pointer',
            }}>Post →</button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ─── SAVED DRAWER (collection) ─────────────────────────────
function SavedDrawer({ saved, catalogue, visible, onClose, onPick }) {
  const works = catalogue.filter((w) => saved.has(w.id));
  return (
    <div data-atlas-panel style={{
      position: 'absolute', inset: 0, zIndex: 50,
      background: visible ? 'rgba(14,14,12,0.4)' : 'rgba(14,14,12,0)',
      backdropFilter: visible ? 'blur(8px)' : 'blur(0px)',
      WebkitBackdropFilter: visible ? 'blur(8px)' : 'blur(0px)',
      transition: 'background 320ms var(--ease-out), backdrop-filter 320ms var(--ease-out), -webkit-backdrop-filter 320ms var(--ease-out)',
    }} onClick={onClose}>
      <div data-atlas-drawer onClick={(e) => e.stopPropagation()} style={{
        position: 'absolute', top: 0, right: 0, bottom: 0, width: 'min(520px, 92%)',
        background: BAU.paper, borderLeft: `1px solid ${BAU.ink}`,
        transform: visible ? 'translateX(0)' : 'translateX(100%)',
        transition: 'transform 380ms var(--ease-out)',
        display: 'flex', flexDirection: 'column',
      }}>
        <div style={{ display: 'flex', height: 8 }}>
          <div style={{ background: BAU.yellow, flex: 1 }} />
          <div style={{ background: BAU.ink, flex: 5 }} />
        </div>
        <div style={{ padding: '20px 24px', borderBottom: `1px solid ${BAU.rule}`, display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
          <div>
            <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.18em', color: BAU.graphite, textTransform: 'uppercase' }}>
              Your collection
            </div>
            <h2 style={{ fontFamily: 'var(--serif)', fontSize: 30, margin: '4px 0 0', lineHeight: 1, fontWeight: 400 }}>
              <span style={{ fontStyle: 'italic' }}>Saved · {works.length}</span>
            </h2>
          </div>
          <button onClick={onClose} style={{
            width: 24, height: 24, background: 'transparent', border: `1px solid ${BAU.ink}`,
            cursor: 'pointer', fontSize: 14, color: BAU.ink, lineHeight: 1, padding: 0,
          }}>×</button>
        </div>
        <div style={{ flex: 1, overflowY: 'auto', padding: 16, display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 16, alignContent: 'start' }}>
          {works.length === 0 && (
            <div style={{ gridColumn: '1 / -1', padding: 60, textAlign: 'center', color: BAU.graphite, fontFamily: 'var(--serif)', fontStyle: 'italic', fontSize: 16 }}>
              Nothing here yet — save a work and it appears here.
            </div>
          )}
          {works.map((w) => (
            <button key={w.id} onClick={() => onPick(w)} style={{
              padding: 0, background: 'transparent', border: 'none', cursor: 'pointer',
              display: 'flex', flexDirection: 'column', textAlign: 'left', gap: 6,
            }}>
              <div style={{ width: '100%', boxShadow: '0 16px 32px rgba(0,0,0,0.16)' }}>
                <ArtTile work={w} width={220} height={Math.round(220 / (w.aspect || 1))} />
              </div>
              <div style={{ fontFamily: 'var(--serif)', fontSize: 14, fontStyle: 'italic', color: BAU.ink }}>{w.title}</div>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.16em', color: BAU.graphite, textTransform: 'uppercase' }}>{w.artist} · {w.year}</div>
            </button>
          ))}
        </div>
      </div>
    </div>
  );
}

// ─── ACCOUNT GATE ─────────────────────────────────────────
function AccountGate({ intent, visible, onAccept, onCancel }) {
  // Two top-level modes — sign in (returning user) or create account.
  // Inside `create`, we walk role → form just like before.
  const [mode, setMode] = React.useState('signin');
  const [step, setStep] = React.useState('choose');
  const [role, setRole] = React.useState('collector');
  const [name, setName] = React.useState('');
  const [email, setEmail] = React.useState('');
  const [password, setPassword] = React.useState('');
  const [error, setError] = React.useState(null);
  const [busy, setBusy] = React.useState(false);

  // If there are no users yet, default to "create" instead of "sign in" so
  // the very first visitor isn't staring at a sign-in form for an account
  // they haven't made.
  React.useEffect(() => {
    try {
      const raw = localStorage.getItem(window.AN_AUTH.USERS_KEY);
      const users = raw ? JSON.parse(raw) : [];
      if (!users.length) setMode('create');
    } catch {}
  }, []);

  const intentMsg = ({
    save: 'To save this work to your collection, you need a profile.',
    like: 'To mark a work, sign in.',
    room: 'To post in The Room, sign in.',
    commission: 'To brief an artist, you need a Collector profile.',
    'submit-work': 'To consign a work, you need an Artist profile.',
    'open-artist': 'Sign in to view full artist profiles.',
    null: 'Enter mariusson.',
  })[intent || 'null'];

  const reset = () => { setError(null); setPassword(''); };

  const handleSignIn = () => {
    setError(null); setBusy(true);
    try {
      const acc = window.AN_AUTH.login({ email, password });
      onAccept(acc);
    } catch (e) {
      setError(e.message || 'Sign in failed');
    } finally { setBusy(false); }
  };

  const handleCreate = () => {
    setError(null); setBusy(true);
    try {
      if (!name.trim()) throw new Error('Name is required');
      if (!email.trim()) throw new Error('Email is required');
      if (password.length < 4) throw new Error('Pick a password (4+ characters)');
      const acc = window.AN_AUTH.register({ name: name.trim(), email: email.trim(), password, role });
      onAccept(acc);
    } catch (e) {
      setError(e.message || 'Could not create account');
    } finally { setBusy(false); }
  };

  const stepLabel = mode === 'signin'
    ? 'Sign in'
    : (step === 'choose' ? 'Create — step 01 / 02' : 'Create — step 02 / 02');

  return (
    <div data-atlas-panel style={{
      position: 'absolute', inset: 0, zIndex: 70,
      background: visible ? 'rgba(14,14,12,0.5)' : 'rgba(14,14,12,0)',
      backdropFilter: visible ? 'blur(10px)' : 'blur(0px)',
      WebkitBackdropFilter: visible ? 'blur(10px)' : 'blur(0px)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      transition: 'background 280ms var(--ease-out), backdrop-filter 280ms var(--ease-out), -webkit-backdrop-filter 280ms var(--ease-out)',
    }}>
      <div data-atlas-dialog style={{
        width: 500, background: BAU.paper, border: `1px solid ${BAU.ink}`,
        transform: visible ? 'scale(1) translateY(0)' : 'scale(0.96) translateY(8px)',
        opacity: visible ? 1 : 0,
        transition: 'transform 280ms var(--ease-out), opacity 240ms var(--ease-out)',
      }}>
        <div style={{ display: 'flex', borderBottom: `1px solid ${BAU.ink}`, height: 36 }}>
          <div style={{ background: BAU.red, flex: 1 }} />
          <div style={{ background: BAU.yellow, width: 90 }} />
          <div style={{ background: BAU.blue, width: 60 }} />
        </div>

        <div style={{ padding: 32, display: 'flex', flexDirection: 'column', gap: 16 }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <span style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.18em', color: BAU.graphite, textTransform: 'uppercase' }}>
              {stepLabel}
            </span>
            <button onClick={onCancel} style={{
              width: 22, height: 22, background: 'transparent', border: `1px solid ${BAU.ink}`,
              cursor: 'pointer', color: BAU.ink, fontSize: 12, padding: 0,
            }}>×</button>
          </div>

          <h2 style={{ fontFamily: 'var(--serif)', fontSize: 30, margin: 0, lineHeight: 1.05, letterSpacing: '-0.01em', fontWeight: 400 }}>
            <span style={{ fontStyle: 'italic' }}>{intentMsg}</span>
          </h2>

          {/* Mode switch */}
          <div style={{
            display: 'flex', gap: 0, border: `1px solid ${BAU.ink}`,
            marginBottom: 4,
          }}>
            {[
              { v: 'signin', label: 'Sign in' },
              { v: 'create', label: 'Create account' },
            ].map((m, i) => (
              <button key={m.v}
                onClick={() => { setMode(m.v); setStep('choose'); reset(); }}
                style={{
                  flex: 1,
                  background: mode === m.v ? BAU.ink : 'transparent',
                  color: mode === m.v ? BAU.paper : BAU.ink,
                  border: 'none', cursor: 'pointer',
                  padding: '10px 0',
                  fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.18em',
                  textTransform: 'uppercase',
                  borderRight: i === 0 ? `1px solid ${BAU.ink}` : 'none',
                }}>{m.label}</button>
            ))}
          </div>

          {mode === 'signin' && (
            <>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
                <Input label="Email" value={email} onChange={setEmail} placeholder="you@studio.eu" type="email" />
                <Input label="Password" value={password} onChange={setPassword} placeholder="••••••••" type="password" />
              </div>
              {error && <ErrorLine message={error} />}
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 4 }}>
                <span style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.14em', color: BAU.graphite, textTransform: 'uppercase' }}>
                  No account? <button onClick={() => { setMode('create'); reset(); }} style={{ background: 'none', border: 'none', borderBottom: `1px solid ${BAU.ink}`, color: BAU.ink, cursor: 'pointer', fontFamily: 'inherit', fontSize: 'inherit', letterSpacing: 'inherit', textTransform: 'inherit', padding: 0 }}>Create one</button>
                </span>
                <div style={{ flex: 1 }} />
                <button onClick={handleSignIn} disabled={busy} style={primaryBtn(busy)}>
                  {busy ? 'Signing in…' : 'Sign in →'}
                </button>
              </div>
            </>
          )}

          {mode === 'create' && step === 'choose' && (
            <>
              <div style={{ fontSize: 13, color: BAU.graphite, lineHeight: 1.5, fontFamily: 'var(--serif)', fontStyle: 'italic' }}>
                Pick a role. You can change it later. Browsing stays anonymous either way.
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                {[
                  { v: 'collector', label: 'Collector', sub: 'Acquire, commission, build a collection.', color: BAU.yellow, glyph: 'square' },
                  { v: 'artist',    label: 'Artist',    sub: 'Consign work, accept commissions, build your record.', color: BAU.red, glyph: 'circle' },
                  { v: 'viewer',    label: 'Viewer',    sub: 'Save works and follow artists. No commerce.', color: BAU.ink, glyph: 'triangle' },
                ].map((r) => (
                  <button key={r.v} onClick={() => { setRole(r.v); setStep('form'); reset(); }} style={{
                    background: BAU.paper, border: `1px solid ${BAU.ink}`, padding: '14px 16px',
                    display: 'flex', alignItems: 'center', gap: 14,
                    cursor: 'pointer', textAlign: 'left',
                    transition: 'background 0.2s var(--ease-out)',
                  }}
                  onMouseEnter={(e) => { e.currentTarget.style.background = BAU.paper2; }}
                  onMouseLeave={(e) => { e.currentTarget.style.background = BAU.paper; }}>
                    <Glyph kind={r.glyph} color={r.color} size={20} />
                    <div style={{ flex: 1 }}>
                      <div style={{ fontFamily: 'var(--serif)', fontSize: 20, fontStyle: 'italic' }}>{r.label}</div>
                      <div style={{ fontSize: 11.5, color: BAU.graphite, fontFamily: 'var(--sans)' }}>{r.sub}</div>
                    </div>
                    <span style={{ color: BAU.graphite }}>→</span>
                  </button>
                ))}
              </div>
            </>
          )}

          {mode === 'create' && step === 'form' && (
            <>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.16em', color: BAU.graphite, textTransform: 'uppercase' }}>
                Joining as {role}
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
                <Input label="Your name" value={name} onChange={setName} placeholder="Elena Marchetti" />
                <Input label="Email — for verification" value={email} onChange={setEmail} placeholder="elena@studio.it" type="email" />
                <Input label="Password" value={password} onChange={setPassword} placeholder="••••••••" type="password" />
              </div>
              {error && <ErrorLine message={error} />}
              <div style={{ display: 'flex', gap: 8, marginTop: 4 }}>
                <button onClick={() => { setStep('choose'); reset(); }} style={{
                  background: 'transparent', border: `1px solid ${BAU.ink}`, padding: '10px 16px',
                  fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em',
                  textTransform: 'uppercase', cursor: 'pointer', color: BAU.ink,
                }}>← Back</button>
                <div style={{ flex: 1 }} />
                <button onClick={handleCreate} disabled={busy} style={primaryBtn(busy)}>
                  {busy ? 'Creating…' : 'Create account →'}
                </button>
              </div>
            </>
          )}

          <div style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.16em', color: BAU.graphite, textTransform: 'uppercase', marginTop: 4 }}>
            ↘ Or keep browsing — <button onClick={onCancel} style={{ background: 'none', border: 'none', color: BAU.ink, cursor: 'pointer', fontFamily: 'inherit', fontSize: 'inherit', letterSpacing: 'inherit', textTransform: 'inherit', padding: 0, borderBottom: `1px solid ${BAU.ink}` }}>stay as a viewer</button>
          </div>
        </div>
      </div>
    </div>
  );
}

function primaryBtn(busy) {
  return {
    background: busy ? BAU.graphite : BAU.ink,
    color: BAU.paper, border: 'none', padding: '10px 18px',
    fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.16em',
    textTransform: 'uppercase', cursor: busy ? 'wait' : 'pointer',
  };
}

function ErrorLine({ message }) {
  return (
    <div role="alert" style={{
      fontFamily: 'var(--mono)', fontSize: 10.5, letterSpacing: '0.08em',
      color: BAU.red, padding: '6px 10px',
      border: `1px solid ${BAU.red}`,
      background: 'rgba(230,57,70,0.06)',
    }}>{message}</div>
  );
}

function SelectField({ label, value, onChange, options }) {
  return (
    <label style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
      <span style={{ fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.18em', color: BAU.graphite, textTransform: 'uppercase' }}>{label}</span>
      <select value={value} onChange={(e) => onChange(e.target.value)} style={{
        border: 'none', borderBottom: `1px solid ${BAU.ink}`,
        background: 'transparent', padding: '8px 0',
        fontFamily: 'var(--serif)', fontSize: 17, fontStyle: 'italic',
        color: BAU.ink, outline: 'none', appearance: 'none',
        backgroundImage: `url("data:image/svg+xml,${encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="12" height="8" viewBox="0 0 12 8"><path d="M1 1l5 6 5-6" stroke="black" stroke-width="1.4" fill="none"/></svg>')}")`,
        backgroundRepeat: 'no-repeat',
        backgroundPosition: 'right 4px center',
        paddingRight: 22,
      }}>
        {options.map((opt) => (<option key={opt} value={opt}>{opt}</option>))}
      </select>
    </label>
  );
}

function Input({ label, value, onChange, placeholder, multi, type }) {
  const Tag = multi ? 'textarea' : 'input';
  return (
    <label style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
      <span style={{ fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.18em', color: BAU.graphite, textTransform: 'uppercase' }}>{label}</span>
      <Tag
        value={value}
        onChange={(e) => onChange(e.target.value)}
        placeholder={placeholder}
        rows={multi ? 3 : undefined}
        type={multi ? undefined : (type || 'text')}
        autoComplete={type === 'password' ? 'current-password' : undefined}
        style={{
          border: 'none', borderBottom: `1px solid ${BAU.ink}`,
          background: 'transparent', padding: '8px 0',
          fontFamily: 'var(--serif)', fontSize: 17, fontStyle: 'italic',
          color: BAU.ink, outline: 'none', resize: 'none',
          // Use a roomier letter spacing for the password dots so they don't
          // crush together when masked.
          letterSpacing: type === 'password' ? '0.18em' : 'normal',
        }} />
    </label>
  );
}

function Glyph({ kind, color, ring, size = 12 }) {
  const fill = color || 'transparent';
  if (kind === 'circle') return <span style={{ width: size, height: size, borderRadius: '50%', background: fill, border: ring ? `1.5px solid ${ring}` : 'none', display: 'inline-block' }} />;
  if (kind === 'square') return <span style={{ width: size, height: size, background: fill, border: ring ? `1.5px solid ${ring}` : 'none', display: 'inline-block' }} />;
  if (kind === 'triangle') {
    return <span style={{ width: 0, height: 0, borderLeft: `${size/2}px solid transparent`, borderRight: `${size/2}px solid transparent`, borderBottom: `${size}px solid ${fill}`, display: 'inline-block' }} />;
  }
  return null;
}

Object.assign(window, {
  DetailModal, CommissionDialog, SubmitDialog, RoomDrawer, SavedDrawer, AccountGate,
  SelectField, MagnifyingArtwork,
  RoleSwitchDialog, ModeCell, ProtectionRow, RoleCard,
  Input, Glyph, DetailRow,
});
