// Phase 08 · LIVE artifact.
//
// The final co-authored record. Mediator drafts from the public record. Both parties edit
// (with co-sign on each edit). Both sign to freeze. Export as markdown.
//
// UI — single column, five sections. Each bullet has a "·" menu: edit, remove.
// Edits go into shared.artifact.edits and require approval from the OTHER party to apply.
// Each seat can also propose a new bullet ("+ add") which also requires co-sign.
//
// When shared.artifact.status === 'signed', the artifact is frozen. Download button appears.

(function () {
  const { useState, useEffect } = React;

  window.LiveArtifactPhase = function LiveArtifactPhase({ seat, onPhase }) {
    const [, tick] = useState(0);
    useEffect(() => CG.session.onState(() => tick(t => t + 1)), []);

    const shared = CG.session.shared || {};
    const names = (CG.session.getNames && CG.session.getNames()) || {};
    const mp = CG.session.isMultiplayer && CG.session.isMultiplayer();
    const isHost = !mp || seat === 'A';
    const otherSeat = seat === 'A' ? 'B' : 'A';
    const myName = names[seat] || (seat === 'A' ? 'host' : 'guest');
    const otherName = names[otherSeat] || (otherSeat === 'A' ? 'host' : 'guest');

    const art = shared.artifact || null;
    const [drafting, setDrafting] = useState(false);
    const [draftError, setDraftError] = useState('');

    // Derive signing state defensively — needed by the presence effect below (must stay above early returns)
    const signed = art?.status === 'signed';
    const mySigned = art ? (seat === 'A' ? !!art.signedA : !!art.signedB) : false;
    const theirSigned = art ? (seat === 'A' ? !!art.signedB : !!art.signedA) : false;

    // Presence — always called, no-ops until the artifact is ready
    useEffect(() => {
      if (!art?.draft) return;
      let activity = 'reviewing artifact';
      if (signed) activity = 'signed · complete';
      else if (mySigned && !theirSigned) activity = `waiting on ${otherName}`;
      else if (!mySigned && theirSigned) activity = 'final review';
      else if (art.edits && art.edits.some(e => e.proposedBy === seat && !e.applied)) activity = 'proposing edits';
      try { CG.session.setCursor && CG.session.setCursor({ activity }); } catch (e) {}
    }, [signed, mySigned, theirSigned]);

    // Guard: need phase 07 to be complete
    const ap = shared.apology || {};
    const apDone =
      (ap.continueA && ap.continueB) ||
      // tolerate older sessions: also accept if both parties skipped or responded
      ((ap.A?.status === 'skipped' || (ap.A?.status === 'offered' && ap.B?.response)) &&
       (ap.B?.status === 'skipped' || (ap.B?.status === 'offered' && ap.A?.response)));

    if (!apDone && !art) {
      return (
        <div style={{ padding: 40, maxWidth: 720, margin: '0 auto' }}>
          <div className="tiny">phase 08 · artifact</div>
          <h1 style={{ marginTop: 6 }}>not ready.</h1>
          <p style={{ color: 'var(--ink-2)', lineHeight: 1.55 }}>
            finish the apology on-ramp first.{' '}
            <a onClick={() => onPhase && onPhase('apology')} style={{ color: 'var(--blue)', cursor: 'pointer' }}>← back</a>
          </p>
        </div>
      );
    }

    const runDraft = async () => {
      if (drafting) return;
      setDrafting(true); setDraftError('');
      try {
        const draft = await CG.agents.artifactMediator.draft();
        // only host writes the authoritative draft
        if (isHost) {
          CG.session.setShared({ artifact: { status: 'reviewing', draft, edits: [], signedA: false, signedB: false } });
        } else {
          // guest doesn't normally run this; but if they do somehow, they can't write the draft.
          // Keep it in local state as a preview; but guest should really wait for host. We show an error.
          setDraftError('only the host can commit the initial draft. ask them to click "ask the mediator to draft".');
        }
      } catch (e) {
        setDraftError(String(e.message || e));
      } finally {
        setDrafting(false);
      }
    };

    // no artifact yet — show the drafting invitation
    if (!art || !art.draft) {
      return (
        <div style={{ height: '100vh', overflow: 'auto', background: 'var(--paper-2)' }}>
          <div style={{ maxWidth: 720, margin: '0 auto', padding: '60px 28px' }}>
            <div className="tiny">phase 08 · artifact</div>
            <h1 style={{ marginTop: 6, fontFamily: 'var(--font-prose)', fontWeight: 500, letterSpacing: '-0.02em' }}>
              a record you both keep.
            </h1>
            <p style={{ color: 'var(--ink-2)', lineHeight: 1.6, fontSize: '1rem', marginTop: 14, marginBottom: 20 }}>
              the mediator will draft the shortest true thing from the public record: what you
              disagreed about, what you came to agree on, what each of you offered, and what
              remains open. you'll both edit it together. you both have to sign.
            </p>

            {!isHost && (
              <div className="paper-card p-3" style={{ background: 'var(--paper)', borderLeft: '2px solid var(--ink-3)', marginBottom: 18 }}>
                <div className="mono" style={{ fontSize: '0.8rem', color: 'var(--ink-2)', textTransform: 'none', letterSpacing: 0, lineHeight: 1.5 }}>
                  waiting for {otherName} to ask the mediator for a draft.
                </div>
              </div>
            )}

            {isHost && (
              <button
                className="btn btn-primary"
                disabled={drafting}
                onClick={runDraft}
              >
                {drafting ? 'mediator writing…' : 'ask the mediator to draft'}
              </button>
            )}

            {draftError && (
              <div className="paper-card p-2 mt-3" style={{ background: 'var(--red-soft)', borderLeft: '2px solid var(--red)' }}>
                <div className="micro" style={{ color: 'var(--red)' }}>error</div>
                <div style={{ fontSize: '0.85rem' }}>{draftError}</div>
              </div>
            )}
          </div>
        </div>
      );
    }

    // artifact present — show the document
    const proposeEdit = (edit) => {
      const curEdits = (art.edits || []);
      const newEdits = [...curEdits, { ...edit, id: `e-${Date.now()}-${Math.random().toString(36).slice(2,6)}`, seat, approvedA: seat === 'A', approvedB: seat === 'B', ts: Date.now() }];
      if (isHost) CG.session.setShared({ artifact: { ...art, edits: newEdits } });
      else CG.peer.send('state:propose', { artifact: { edits: newEdits } });
    };
    const approveEdit = (id) => {
      // guest approves via the merge-on-append contract; host materializes applied edits into the draft.
      if (isHost) {
        const e = (art.edits || []).find(x => x.id === id);
        if (!e) return;
        // flip host's side
        const next = { ...art, edits: art.edits.map(x => x.id === id ? { ...x, approvedA: true } : x) };
        const applied = applyIfBothApproved(next, id);
        CG.session.setShared({ artifact: applied });
      } else {
        CG.peer.send('state:propose', { artifact: { edits: [{ id, approvedB: true }] } });
      }
    };
    const rejectEdit = (id) => {
      // remove the edit — allowed on either side as a local decision; host is authoritative.
      if (isHost) {
        CG.session.setShared({ artifact: { ...art, edits: art.edits.filter(x => x.id !== id) } });
      } else {
        // guest can't force removal; they can only decline to approve. But we can propose a rejection
        // by sending the edit back with approvedB=false (no-op under current guard). For v1: guest has
        // to ask the host to reject. UX fallback: disable the reject button for guests.
      }
    };

    const sign = () => {
      if (seat === 'A') {
        if (isHost) {
          const next = { ...art, signedA: true };
          if (next.signedB) { next.status = 'signed'; next.signedAt = Date.now(); }
          CG.session.setShared({ artifact: next });
        }
      } else {
        if (isHost) {
          const next = { ...art, signedB: true };
          if (next.signedA) { next.status = 'signed'; next.signedAt = Date.now(); }
          CG.session.setShared({ artifact: next });
        } else {
          CG.peer.send('state:propose', { artifact: { signedB: true } });
        }
      }
    };

    const draft = art.draft;
    const pendingEdits = (art.edits || []).filter(e => !(e.approvedA && e.approvedB));

    return (
      <div style={{ height: '100vh', overflow: 'auto', background: 'var(--paper-2)' }}>
        <div style={{ maxWidth: 760, margin: '0 auto', padding: '32px 28px 60px' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 14 }}>
            <div>
              <div className="tiny">phase 08 · artifact</div>
              <h1 style={{ marginTop: 4, marginBottom: 0, fontFamily: 'var(--font-prose)', fontWeight: 500, letterSpacing: '-0.02em' }}>
                the record.
              </h1>
            </div>
            {signed && (
              <ExportButtons artifact={art} names={names} />
            )}
          </div>

          {signed && (
            <div className="paper-card p-3 mb-4" style={{ background: 'oklch(97% 0.03 140)', borderLeft: '3px solid var(--green)' }}>
              <div className="mono" style={{ fontSize: '0.8rem', color: 'var(--ink-1)', textTransform: 'none', letterSpacing: 0 }}>
                signed by both parties on {new Date(art.signedAt || Date.now()).toLocaleString()}. this is frozen — a historical record.
              </div>
            </div>
          )}

          {pendingEdits.length > 0 && !signed && (
            <div className="paper-card p-3 mb-4" style={{ background: 'var(--paper)', borderLeft: '3px solid oklch(60% 0.14 85)' }}>
              <div className="tiny mb-2">pending edits · {pendingEdits.length}</div>
              {pendingEdits.map(e => (
                <PendingEditRow
                  key={e.id}
                  edit={e}
                  seat={seat}
                  names={names}
                  isHost={isHost}
                  onApprove={() => approveEdit(e.id)}
                  onReject={() => rejectEdit(e.id)}
                />
              ))}
            </div>
          )}

          <ArtifactDoc
            draft={draft}
            names={names}
            seat={seat}
            signed={signed}
            onPropose={proposeEdit}
          />

          {!signed && (
            <div style={{ marginTop: 28, borderTop: '1px dashed var(--rule)', paddingTop: 20 }}>
              <div className="tiny mb-2">when this is the truest short thing you can both sign</div>
              <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
                <button
                  className="btn btn-primary"
                  disabled={mySigned}
                  onClick={sign}
                >
                  {mySigned ? `✓ you signed` : `sign`}
                </button>
                <div className="mono" style={{ fontSize: '0.76rem', color: 'var(--ink-3)' }}>
                  {mySigned ? 'you ✓' : 'you ·'} {theirSigned ? `· ${otherName} ✓` : `· ${otherName} pending`}
                </div>
              </div>
              {pendingEdits.length > 0 && (
                <div className="mono mt-2" style={{ fontSize: '0.72rem', color: 'oklch(50% 0.14 85)' }}>
                  there are {pendingEdits.length} pending edit{pendingEdits.length === 1 ? '' : 's'}. resolve them before signing.
                </div>
              )}
            </div>
          )}
        </div>
      </div>
    );
  };

  // -------- helpers --------

  function applyIfBothApproved(art, editId) {
    const edit = (art.edits || []).find(e => e.id === editId);
    if (!edit || !(edit.approvedA && edit.approvedB)) return art;
    const draft = { ...art.draft };
    const list = [...(draft[edit.section] || [])];
    if (edit.op === 'replace' && typeof edit.idx === 'number') {
      if (list[edit.idx]) list[edit.idx] = { ...list[edit.idx], text: edit.text, ref: edit.ref || list[edit.idx].ref };
    } else if (edit.op === 'remove' && typeof edit.idx === 'number') {
      list.splice(edit.idx, 1);
    } else if (edit.op === 'add') {
      list.push({ text: edit.text, ref: edit.ref || 'user-added' });
    }
    draft[edit.section] = list;
    return { ...art, draft, edits: art.edits.filter(e => e.id !== editId) };
  }

  function PendingEditRow({ edit, seat, names, isHost, onApprove, onReject }) {
    const byName = edit.seat === 'A' ? (names.A || 'host') : (names.B || 'guest');
    const myApproved = seat === 'A' ? edit.approvedA : edit.approvedB;
    const opLabel = edit.op === 'replace' ? 'edit' : edit.op === 'remove' ? 'remove' : 'add';
    return (
      <div style={{ padding: '6px 0', borderBottom: '1px dashed var(--rule)' }}>
        <div className="mono" style={{ fontSize: '0.68rem', color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: 3 }}>
          {byName} · {opLabel} · {edit.section.replace(/_/g, ' ')}{typeof edit.idx === 'number' ? ` #${edit.idx + 1}` : ''}
        </div>
        {edit.op !== 'remove' && (
          <div style={{ fontSize: '0.87rem', lineHeight: 1.45, marginBottom: 6 }}>{edit.text}</div>
        )}
        {myApproved ? (
          <div className="mono" style={{ fontSize: '0.7rem', color: 'var(--green)' }}>
            you approved · waiting for the other
          </div>
        ) : (
          <div style={{ display: 'flex', gap: 6 }}>
            <button className="btn btn-sm btn-primary" onClick={onApprove}>approve</button>
            {isHost && <button className="btn btn-sm btn-ghost" onClick={onReject}>reject</button>}
          </div>
        )}
      </div>
    );
  }

  function ArtifactDoc({ draft, names, seat, signed, onPropose }) {
    return (
      <div className="paper-card" style={{ background: 'var(--paper)', padding: '26px 30px', fontFamily: 'var(--font-prose)' }}>
        <Section label="topic">
          <div style={{ fontSize: '1.05rem', lineHeight: 1.55, fontWeight: 500 }}>{draft.topic}</div>
        </Section>

        <BulletSection
          label="what we agreed"
          section="what_we_agreed"
          items={draft.what_we_agreed}
          signed={signed}
          onPropose={onPropose}
        />

        {draft.acknowledgments && draft.acknowledgments.length > 0 && (
          <AcknowledgmentsSection items={draft.acknowledgments} names={names} />
        )}

        {draft.action_items && draft.action_items.length > 0 && (
          <ActionItemsSection items={draft.action_items} names={names} />
        )}

        <BulletSection
          label="what remains open"
          section="what_remains_open"
          items={draft.what_remains_open}
          signed={signed}
          onPropose={onPropose}
        />
        <OffersSection items={draft.what_was_offered} names={names} />
        <BulletSection
          label="what we noticed"
          section="what_we_noticed"
          items={draft.what_we_noticed}
          signed={signed}
          onPropose={onPropose}
        />

        {draft.parking_lot && draft.parking_lot.length > 0 && (
          <ParkingLotSection items={draft.parking_lot} />
        )}
      </div>
    );
  }

  function Section({ label, children }) {
    return (
      <div style={{ marginBottom: 22 }}>
        <div className="tiny mb-2">{label}</div>
        {children}
      </div>
    );
  }

  function BulletSection({ label, section, items, signed, onPropose }) {
    const [addMode, setAddMode] = useState(false);
    const [addText, setAddText] = useState('');
    return (
      <div style={{ marginBottom: 22 }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 8 }}>
          <div className="tiny">{label}</div>
          {!signed && !addMode && (
            <button className="btn btn-sm btn-ghost" onClick={() => setAddMode(true)} style={{ fontSize: '0.72rem', padding: '2px 6px' }}>
              + propose add
            </button>
          )}
        </div>
        {(!items || items.length === 0) && !addMode && (
          <div className="mono" style={{ fontSize: '0.75rem', color: 'var(--ink-3)', textTransform: 'none', letterSpacing: 0 }}>
            (none)
          </div>
        )}
        <ul style={{ margin: 0, paddingLeft: 0, listStyle: 'none' }}>
          {(items || []).map((it, i) => (
            <BulletItem
              key={i}
              item={it}
              idx={i}
              section={section}
              signed={signed}
              onPropose={onPropose}
            />
          ))}
        </ul>
        {addMode && (
          <div style={{ marginTop: 6, padding: '8px 10px', background: 'var(--paper-2)', border: '1px dashed var(--rule)' }}>
            <textarea
              className="paper-input"
              rows={2}
              placeholder="your proposed line…"
              value={addText}
              onChange={e => setAddText(e.target.value)}
            />
            <div style={{ display: 'flex', gap: 6, marginTop: 6 }}>
              <button
                className="btn btn-sm btn-primary"
                disabled={!addText.trim()}
                onClick={() => {
                  onPropose({ section, op: 'add', text: addText.trim(), ref: 'user-added' });
                  setAddText(''); setAddMode(false);
                }}
              >propose</button>
              <button className="btn btn-sm btn-ghost" onClick={() => { setAddText(''); setAddMode(false); }}>cancel</button>
            </div>
          </div>
        )}
      </div>
    );
  }

  function BulletItem({ item, idx, section, signed, onPropose }) {
    const [editing, setEditing] = useState(false);
    const [val, setVal] = useState(item.text);
    useEffect(() => setVal(item.text), [item.text]);
    if (editing) {
      return (
        <li style={{ padding: '6px 0' }}>
          <textarea
            className="paper-input"
            rows={2}
            value={val}
            onChange={e => setVal(e.target.value)}
            style={{ fontFamily: 'var(--font-prose)' }}
          />
          <div style={{ display: 'flex', gap: 6, marginTop: 6 }}>
            <button
              className="btn btn-sm btn-primary"
              disabled={!val.trim() || val.trim() === item.text.trim()}
              onClick={() => {
                onPropose({ section, op: 'replace', idx, text: val.trim(), ref: item.ref });
                setEditing(false);
              }}
            >propose edit</button>
            <button className="btn btn-sm btn-ghost" onClick={() => { setVal(item.text); setEditing(false); }}>cancel</button>
          </div>
        </li>
      );
    }
    return (
      <li style={{
        padding: '8px 0 8px 14px',
        borderLeft: '2px solid var(--rule)',
        marginBottom: 4,
        position: 'relative',
      }}>
        <div style={{ fontSize: '0.95rem', lineHeight: 1.55 }}>{item.text}</div>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginTop: 4 }}>
          <div className="mono" style={{ fontSize: '0.65rem', color: 'var(--ink-4)' }}>ref · {item.ref || '—'}</div>
          {!signed && (
            <div style={{ display: 'flex', gap: 6 }}>
              <button className="btn btn-sm btn-ghost" onClick={() => setEditing(true)} style={{ fontSize: '0.7rem', padding: '1px 5px' }}>edit</button>
              <button
                className="btn btn-sm btn-ghost"
                onClick={() => onPropose({ section, op: 'remove', idx })}
                style={{ fontSize: '0.7rem', padding: '1px 5px' }}
              >remove</button>
            </div>
          )}
        </div>
      </li>
    );
  }

  function OffersSection({ items, names }) {
    return (
      <div style={{ marginBottom: 22 }}>
        <div className="tiny mb-2">what was offered</div>
        {(!items || items.length === 0) && (
          <div className="mono" style={{ fontSize: '0.75rem', color: 'var(--ink-3)', textTransform: 'none', letterSpacing: 0 }}>
            (no offers recorded.)
          </div>
        )}
        <ul style={{ margin: 0, paddingLeft: 0, listStyle: 'none' }}>
          {(items || []).map((it, i) => (
            <li key={i} style={{ padding: '8px 0 8px 14px', borderLeft: '2px solid var(--rule)', marginBottom: 4 }}>
              <div className="mono" style={{ fontSize: '0.68rem', color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: 2 }}>
                {it.by === 'A' ? (names.A || 'host') : (names.B || 'guest')}
              </div>
              <div style={{ fontSize: '0.95rem', lineHeight: 1.55 }}>{it.text}</div>
              <div className="mono" style={{ fontSize: '0.65rem', color: 'var(--ink-4)', marginTop: 3 }}>ref · {it.ref}</div>
            </li>
          ))}
        </ul>
      </div>
    );
  }

  function AcknowledgmentsSection({ items, names }) {
    return (
      <div style={{ marginBottom: 22 }}>
        <div className="tiny mb-2">acknowledgments</div>
        <ul style={{ margin: 0, paddingLeft: 0, listStyle: 'none' }}>
          {items.map((it, i) => (
            <li key={i} style={{ padding: '8px 0 8px 14px', borderLeft: '2px solid var(--rule)', marginBottom: 4 }}>
              <div className="mono" style={{ fontSize: '0.68rem', color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: 2 }}>
                {it.by === 'A' ? (names.A || 'host') : (names.B || 'guest')}
              </div>
              <div style={{ fontSize: '0.92rem', lineHeight: 1.5, fontStyle: 'italic', color: 'var(--ink-1)' }}>{it.text}</div>
              {it.ref && <div className="mono" style={{ fontSize: '0.65rem', color: 'var(--ink-4)', marginTop: 3 }}>ref · {it.ref}</div>}
            </li>
          ))}
        </ul>
      </div>
    );
  }

  function ActionItemsSection({ items, names }) {
    return (
      <div style={{ marginBottom: 22 }}>
        <div className="tiny mb-2">action items</div>
        <ul style={{ margin: 0, paddingLeft: 0, listStyle: 'none' }}>
          {items.map((it, i) => {
            const ownerLabel = it.owner === 'both'
              ? `${names.A || 'host'} + ${names.B || 'guest'}`
              : it.owner === 'A' ? (names.A || 'host') : (names.B || 'guest');
            return (
              <li key={i} style={{ padding: '8px 0 8px 14px', borderLeft: '3px solid var(--green)', marginBottom: 6 }}>
                <div className="mono" style={{ fontSize: '0.68rem', color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: 2 }}>
                  {ownerLabel}{it.timeframe ? ` · ${it.timeframe}` : ''}
                </div>
                <div style={{ fontSize: '0.92rem', lineHeight: 1.5 }}>{it.text}</div>
              </li>
            );
          })}
        </ul>
      </div>
    );
  }

  function ParkingLotSection({ items }) {
    return (
      <div style={{ marginBottom: 22 }}>
        <div className="tiny mb-2">parking lot · for another time</div>
        <ul style={{ margin: 0, paddingLeft: 0, listStyle: 'none' }}>
          {items.map((it, i) => (
            <li key={i} style={{ padding: '6px 0 6px 14px', borderLeft: '2px dashed var(--rule)', marginBottom: 4 }}>
              <div style={{ fontSize: '0.88rem', lineHeight: 1.45, color: 'var(--ink-2)' }}>{it.text}</div>
              {it.ref && <div className="mono" style={{ fontSize: '0.65rem', color: 'var(--ink-4)', marginTop: 2 }}>ref · {it.ref}</div>}
            </li>
          ))}
        </ul>
      </div>
    );
  }

  function ExportButtons({ artifact, names }) {
    const makeMarkdown = () => {
      const d = artifact.draft;
      const lines = [];
      lines.push(`# Clarguments · the record`);
      lines.push('');
      lines.push(`_between ${names.A || 'host'} and ${names.B || 'guest'} · signed ${new Date(artifact.signedAt || Date.now()).toLocaleString()}_`);
      lines.push('');
      lines.push(`## topic`);
      lines.push(d.topic || '');
      lines.push('');
      const section = (label, items, isOffers = false) => {
        lines.push(`## ${label}`);
        if (!items || items.length === 0) { lines.push('_(none)_'); lines.push(''); return; }
        items.forEach(it => {
          if (isOffers) {
            const who = it.by === 'A' ? (names.A || 'host') : (names.B || 'guest');
            lines.push(`- **${who}** · ${it.text}`);
          } else {
            lines.push(`- ${it.text}`);
          }
        });
        lines.push('');
      };
      section('what we agreed', d.what_we_agreed);

      if (d.acknowledgments && d.acknowledgments.length > 0) {
        lines.push('## acknowledgments');
        d.acknowledgments.forEach(it => {
          const who = it.by === 'A' ? (names.A || 'host') : (names.B || 'guest');
          lines.push(`- **${who}** · _${it.text}_`);
        });
        lines.push('');
      }

      if (d.action_items && d.action_items.length > 0) {
        lines.push('## action items');
        d.action_items.forEach(it => {
          const who = it.owner === 'both'
            ? `${names.A || 'host'} + ${names.B || 'guest'}`
            : it.owner === 'A' ? (names.A || 'host') : (names.B || 'guest');
          const tf = it.timeframe ? ` _(${it.timeframe})_` : '';
          lines.push(`- **${who}**${tf} · ${it.text}`);
        });
        lines.push('');
      }

      section('what remains open', d.what_remains_open);
      section('what was offered', d.what_was_offered, true);
      section('what we noticed', d.what_we_noticed);

      if (d.parking_lot && d.parking_lot.length > 0) {
        lines.push('## parking lot · for another time');
        d.parking_lot.forEach(it => lines.push(`- ${it.text}`));
        lines.push('');
      }

      return lines.join('\n');
    };
    const download = () => {
      const md = makeMarkdown();
      const blob = new Blob([md], { type: 'text/markdown' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = `clarguments-${Date.now()}.md`;
      a.click();
      URL.revokeObjectURL(url);
    };
    const copy = async () => {
      try {
        await navigator.clipboard.writeText(makeMarkdown());
      } catch {}
    };
    return (
      <div style={{ display: 'flex', gap: 6 }}>
        <button className="btn btn-sm" onClick={copy}>copy markdown</button>
        <button className="btn btn-sm btn-primary" onClick={download}>download</button>
      </div>
    );
  }

  console.log('[phases-artifact-live] loaded');
})();
