/* MostlyPDF e-sign sender screens (F185/F189/F190) — the authed side of the workflow:
     • RequestSignature — upload → recipients (1..5, routing, access codes) → per-signer
       field placement (colour-coded) → send; templates (save / start-from, F189)
     • Agreements — status list with per-recipient chips, void, download
   Registered as window.MostlyPDFEsignScreens; app.jsx builds it with its firebase/auth
   helpers + the SignKit primitives. Evaluated during SSR via prerender.shared. */
(function () {
  'use strict';
  if (typeof window === 'undefined') return;

  window.MostlyPDFEsignScreens = function makeEsignScreens({ React, SignKit, initFirebase, authUser, idpLoginUrl }) {
    const { useState, useEffect } = React;
    const h = React.createElement;
    const { PagePlacer, S, fileToB64, chip, RCOLORS } = SignKit;
    const label = 'font-size:12px;font-weight:500;color:var(--fg);';
    const hint = 'font-size:11.5px;color:var(--fg-subtle);';
    const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

    const signInCard = (continueHash, note) => h('div', { className: 'forge-card', style: S('max-width:520px;margin:40px auto;padding:28px;text-align:center;') },
      h('div', { style: S('font-family:var(--font-display);font-size:19px;font-weight:600;') }, 'Sign in to continue'),
      h('p', { style: S('font-size:13.5px;color:var(--fg-muted);margin:8px 0 16px;') }, note),
      h('button', {
        className: 'forge-btn forge-btn--primary',
        onClick: () => {
          try {
            // Hashless continue: the IdP appends the one-time token as `#token=…`, so the
            // return URL must NOT already carry a hash route (`#/request-signature`) — the two
            // collide in the fragment and the hash router mangles the token before the
            // identity-landing check reads it. The app lands on the request-signature flow by
            // default post-login, so no destination is lost.
            window.MostlyAuth.redirectToIdentitySignIn({
              idpLoginUrl: idpLoginUrl || 'https://id.mostlytiny.io/login',
              product: 'mostlysign',
              continueUrl: location.href.split('#')[0],
            });
          } catch (e) { location.hash = '#/keys'; }
        },
      }, 'Sign in with Mostly Tiny'));

    function RequestSignature({ go }) {
      const [user, setUser] = useState(undefined);
      const [file, setFile] = useState(null);
      const [placements, setPlacements] = useState([]);
      const [recipients, setRecipients] = useState([{ email: '', name: '', accessCode: '' }]);
      const [routing, setRouting] = useState('parallel');
      const [active, setActive] = useState(0); // which recipient new fields belong to
      const [title, setTitle] = useState('');
      const [message, setMessage] = useState('');
      const [templates, setTemplates] = useState(null);
      const [tplName, setTplName] = useState('');
      const [tplSaving, setTplSaving] = useState(false);
      const [phase, setPhase] = useState('edit'); // edit|sending|sent|error
      const [errMsg, setErrMsg] = useState('');
      const [sentLinks, setSentLinks] = useState([]); // [{email, signingUrl}] from create — shown once
      const [copiedIdx, setCopiedIdx] = useState(-1);

      useEffect(() => {
        authUser().then(async (u) => {
          setUser(u || null);
          if (!u) return;
          try {
            const fb = initFirebase();
            const r = await fb.fns.httpsCallable('templateList')({});
            setTemplates((r.data && r.data.templates) || []);
          } catch (e) { setTemplates([]); }
        });
      }, []);

      const pick = (ev) => { const f = ev.target.files && ev.target.files[0]; if (f) { setFile(f); if (!title) setTitle(f.name); } };
      const setRecip = (i, patch) => setRecipients(recipients.map((r, j) => (j === i ? { ...r, ...patch } : r)));
      const addRecip = () => { if (recipients.length < 5) setRecipients(recipients.concat([{ email: '', name: '', accessCode: '' }])); };
      const dropRecip = (i) => {
        if (recipients.length <= 1) return;
        setRecipients(recipients.filter((_, j) => j !== i));
        // Fields shift with their signers: drop that signer's fields, renumber the rest.
        setPlacements(placements.filter((p) => p.recipient !== i).map((p) => (p.recipient > i ? { ...p, recipient: p.recipient - 1 } : p)));
        setActive(0);
      };
      const applyTemplate = (t) => {
        if (!t) return;
        setTitle(t.title || ''); setMessage(t.message || ''); setRouting(t.routing || 'parallel');
        setPlacements(t.placements || []);
        setRecipients((t.roles || [{ name: '' }]).map((role) => ({ email: '', name: role.name === 'Signer 1' ? '' : role.name, accessCode: '' })));
        setActive(0);
      };
      const saveTemplate = async () => {
        if (!tplName.trim()) return;
        setTplSaving(true);
        try {
          const fb = initFirebase();
          const r = await fb.fns.httpsCallable('templateSave')({
            name: tplName.trim(), title, message, routing,
            roles: recipients.map((r2, i) => ({ name: r2.name || `Signer ${i + 1}` })),
            placements,
          });
          setTemplates([...(templates || []), { id: r.data.id, name: r.data.name, title, message, routing, roles: recipients.map((r2, i) => ({ name: r2.name || `Signer ${i + 1}` })), placements }]);
          setTplName('');
        } catch (e) { setErrMsg((e && e.message) || 'Could not save the template.'); }
        setTplSaving(false);
      };

      const everySignerHasField = recipients.every((_, i) => placements.some((p) => p.recipient === i && p.kind === 'signature'));
      const valid = file && everySignerHasField && recipients.every((r) => EMAIL_RE.test(r.email.trim()));
      const send = async () => {
        setPhase('sending'); setErrMsg('');
        try {
          const fb = initFirebase();
          if (!fb || !fb.fns) throw new Error('Service unavailable — try again shortly.');
          const pdfBase64 = await fileToB64(file);
          const res = await fb.fns.httpsCallable('envelopeCreate')({
            title: title || file.name, message, routing,
            recipients: recipients.map((r) => ({ email: r.email.trim(), name: r.name.trim(), ...(r.accessCode.trim() ? { accessCode: r.accessCode.trim() } : {}) })),
            placements, pdfBase64, origin: location.origin,
          });
          setSentLinks((res.data && res.data.recipients) || []);
          setPhase('sent');
        } catch (e) { setErrMsg((e && e.message) || 'Could not send the request.'); setPhase('error'); }
      };

      if (user === undefined) return h('div', { style: S('padding:60px;text-align:center;color:var(--fg-muted);') }, 'Loading…');
      if (user === null) return signInCard('#/request-signature', 'Sign in with your Mostly Tiny ID to send documents for signature — 3 documents a month are free; unlimited documents are on Pro ($12/month, or $10 billed yearly — no per-envelope caps).');
      if (phase === 'sent') return h('div', { className: 'forge-card', style: S('max-width:560px;margin:40px auto;padding:28px;text-align:center;') },
        h('div', { style: S('font-family:var(--font-display);font-size:20px;font-weight:600;') }, 'Request sent ✓'),
        h('p', { style: S('font-size:13.5px;color:var(--fg-muted);margin:10px 0 16px;') },
          (routing === 'sequential' && recipients.length > 1
            ? 'We emailed the first signer a secure link; each signer is invited in order. '
            : 'We emailed every signer a secure signing link. ') +
          'You’ll get an email when it completes — everyone receives the sealed PDF with its audit certificate.'),
        // The signing links, shown ONCE (they are never stored server-side). Lets the
        // sender hand a link over chat/in person — and is how embedded flows get links.
        sentLinks.length > 0 && h('div', { style: S('text-align:left;margin-bottom:16px;display:flex;flex-direction:column;gap:6px;') },
          h('span', { style: S(hint) }, 'Signing links (shown once — each is unique to its signer):'),
          sentLinks.map((l, i) => h('div', { key: i, style: S('display:flex;gap:6px;align-items:center;') },
            h('input', { readOnly: true, value: l.signingUrl, className: 'forge-input', style: S('flex:1;font-size:11.5px;'), onFocus: (ev) => ev.target.select() }),
            h('button', {
              className: 'forge-btn forge-btn--secondary forge-btn--sm',
              onClick: async () => { try { await navigator.clipboard.writeText(l.signingUrl); setCopiedIdx(i); setTimeout(() => setCopiedIdx(-1), 1500); } catch (e) {} },
            }, copiedIdx === i ? 'Copied ✓' : 'Copy')))),
        h('button', { className: 'forge-btn forge-btn--secondary', onClick: () => go('agreements') }, 'Track your requests'));

      const rc = (i) => RCOLORS[i % RCOLORS.length];
      return h('div', { style: S('max-width:1100px;margin:0 auto;padding:26px 28px 8px;') },
        h('h1', { style: S('font-family:var(--font-display);font-size:30px;font-weight:600;letter-spacing:-0.03em;margin:0;') }, 'Request a signature'),
        h('p', { style: S('font-size:14.5px;color:var(--fg-muted);margin:8px 0 18px;max-width:46em;') }, 'Upload a PDF, add up to 5 signers, place each signer’s fields, and send. The completed document comes back digitally sealed with a certificate of completion.'),
        templates && templates.length > 0 && h('div', { style: S('display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:14px;') },
          h('span', { style: S(label) }, 'Start from template:'),
          templates.map((t) => h('button', { key: t.id, style: S(chip(false)), onClick: () => applyTemplate(t) }, t.name))),
        h('div', { style: S('display:grid;grid-template-columns:minmax(0,1fr) 360px;gap:20px;align-items:start;') },
          h('div', { className: 'forge-card', style: S('padding:20px;') },
            !file
              ? h('div', { onClick: () => document.getElementById('mp-req-file').click(), style: S('display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:48px 24px;border-radius:var(--radius-xl);border:2px dashed var(--border-strong);background:var(--bg-elev);cursor:pointer;') },
                  h('div', { style: S('font-family:var(--font-display);font-size:17px;font-weight:600;') }, 'Choose the PDF to be signed'),
                  h('div', { style: S(hint + 'margin-top:6px;') }, 'PDF · up to 10 MB'))
              : h('div', null,
                  h('div', { style: S('display:flex;align-items:center;gap:10px;margin-bottom:10px;') },
                    h('span', { style: S('font-size:13.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;') }, file.name),
                    h('button', { className: 'forge-btn forge-btn--ghost forge-btn--sm', onClick: () => { setFile(null); setPlacements([]); } }, 'Replace')),
                  recipients.length > 1 && h('div', { style: S('display:flex;gap:6px;flex-wrap:wrap;margin-bottom:8px;') },
                    h('span', { style: S(hint + 'align-self:center;') }, 'Placing fields for:'),
                    recipients.map((r, i) => h('button', {
                      key: i, onClick: () => setActive(i),
                      style: S('display:inline-flex;align-items:center;gap:6px;height:28px;padding:0 11px;border-radius:999px;font-size:12px;font-weight:600;cursor:pointer;border:1.5px solid ' + rc(i) + ';' + (active === i ? 'background:' + rc(i) + ';color:#fff;' : 'background:transparent;color:' + rc(i) + ';')),
                    }, (i + 1) + ' · ' + (r.name || r.email || 'Signer ' + (i + 1))))),
                  h(PagePlacer, { file, placements, onPlacements: setPlacements, recipients, activeRecipient: active })),
            h('input', { id: 'mp-req-file', type: 'file', accept: 'application/pdf', onChange: pick, style: S('display:none;') })),
          h('div', { className: 'forge-card', style: S('padding:20px;position:sticky;top:84px;') },
            h('div', { style: S('display:flex;align-items:center;gap:10px;margin-bottom:12px;') },
              h('div', { style: S('font-family:var(--font-display);font-size:16px;font-weight:600;flex:1;') }, 'Signers'),
              recipients.length > 1 && h('div', { style: S('display:flex;gap:6px;') },
                ['parallel', 'sequential'].map((m) => h('button', { key: m, onClick: () => setRouting(m), style: S(chip(routing === m)) }, m === 'parallel' ? 'All at once' : 'In order')))),
            h('div', { style: S('display:flex;flex-direction:column;gap:12px;') },
              recipients.map((r, i) => h('div', { key: i, style: S('border:1px solid var(--hairline);border-left:3px solid ' + rc(i) + ';border-radius:var(--radius);padding:10px 12px;display:flex;flex-direction:column;gap:7px;') },
                h('div', { style: S('display:flex;align-items:center;gap:8px;') },
                  h('span', { style: S('font-size:12px;font-weight:700;color:' + rc(i) + ';') }, (routing === 'sequential' && recipients.length > 1 ? '#' + (i + 1) + ' ' : '') + 'Signer ' + (i + 1)),
                  recipients.length > 1 && h('button', { onClick: () => dropRecip(i), className: 'forge-btn forge-btn--ghost forge-btn--sm', style: S('margin-left:auto;') }, 'Remove')),
                h('input', { className: 'forge-input', value: r.email, onChange: (ev) => setRecip(i, { email: ev.target.value }), placeholder: 'name@company.com', style: S('width:100%;') }),
                h('input', { className: 'forge-input', value: r.name, onChange: (ev) => setRecip(i, { name: ev.target.value }), placeholder: 'Name (optional)', style: S('width:100%;') }),
                h('input', { className: 'forge-input', value: r.accessCode, onChange: (ev) => setRecip(i, { accessCode: ev.target.value }), placeholder: 'Access code (optional — share it separately)', style: S('width:100%;') }))),
              recipients.length < 5 && h('button', { onClick: addRecip, className: 'forge-btn forge-btn--secondary forge-btn--sm' }, '+ Add signer'),
              h('div', null, h('span', { style: S(label) }, 'Document title'), h('input', { className: 'forge-input', value: title, onChange: (ev) => setTitle(ev.target.value), style: S('width:100%;margin-top:5px;') })),
              h('div', null, h('span', { style: S(label) }, 'Message (optional)'), h('textarea', { className: 'forge-input', value: message, onChange: (ev) => setMessage(ev.target.value), style: S('width:100%;min-height:56px;margin-top:5px;padding:10px 12px;') }))),
            file && !everySignerHasField && h('div', { style: S(hint + 'margin-top:10px;') }, 'Every signer needs at least one signature field — pick the signer above the preview, then “+ Signature”.'),
            phase === 'error' && h('div', { style: S('margin-top:10px;') },
              h('div', { style: S('font-size:12.5px;color:var(--bad);') }, errMsg),
              // Plan-gated refusal (free monthly envelope used) → a calm upgrade path.
              /free envelope|Pro/i.test(errMsg) && h('button', { className: 'forge-btn forge-btn--primary forge-btn--sm', style: S('margin-top:8px;'), onClick: () => { location.hash = '#/pricing'; } }, 'Upgrade to Pro — $12/month, unlimited')),
            h('div', { style: S('margin-top:14px;padding-top:12px;border-top:1px solid var(--hairline);display:flex;flex-direction:column;gap:8px;') },
              h('button', { disabled: !valid || phase === 'sending', onClick: send, className: 'forge-btn forge-btn--primary forge-btn--lg forge-btn--block' }, phase === 'sending' ? 'Sending…' : 'Send signing request'),
              placements.length > 0 && h('div', { style: S('display:flex;gap:6px;') },
                h('input', { className: 'forge-input', value: tplName, onChange: (ev) => setTplName(ev.target.value), placeholder: 'Save as template…', style: S('flex:1;') }),
                h('button', { disabled: tplSaving || !tplName.trim(), onClick: saveTemplate, className: 'forge-btn forge-btn--secondary forge-btn--sm' }, tplSaving ? '…' : 'Save'))))));
    }

    function Agreements({ go }) {
      const [user, setUser] = useState(undefined);
      const [rows, setRows] = useState(null);
      const [err, setErr] = useState('');
      const [busyId, setBusyId] = useState('');
      const load = async () => {
        try {
          const fb = initFirebase();
          const r = await fb.fns.httpsCallable('envelopeList')({});
          setRows((r.data && r.data.envelopes) || []);
        } catch (e) { setErr((e && e.message) || 'Could not load.'); setRows([]); }
      };
      useEffect(() => { authUser().then((u) => { setUser(u || null); if (u) load(); }); }, []);
      const act = async (id, fn) => {
        setBusyId(id);
        try {
          const fb = initFirebase();
          if (fn === 'void') { await fb.fns.httpsCallable('envelopeVoid')({ id }); await load(); }
          else { const r = await fb.fns.httpsCallable('envelopeDownload')({ id }); if (r.data && r.data.url) window.open(r.data.url, '_blank', 'noopener'); }
        } catch (e) { setErr((e && e.message) || 'Action failed.'); }
        setBusyId('');
      };
      const TINT = { pending: 'var(--fg-subtle)', sent: 'var(--fg-muted)', viewed: 'var(--warn)', signed: 'var(--good)', completed: 'var(--good)', declined: 'var(--bad)', voided: 'var(--fg-subtle)', expired: 'var(--bad)' };

      if (user === undefined) return h('div', { style: S('padding:60px;text-align:center;color:var(--fg-muted);') }, 'Loading…');
      if (user === null) return signInCard('#/agreements', 'Sign in to see the status of your signature requests.');
      return h('div', { style: S('max-width:920px;margin:0 auto;padding:26px 28px 8px;') },
        h('div', { style: S('display:flex;align-items:center;gap:12px;margin-bottom:18px;') },
          h('h1', { style: S('font-family:var(--font-display);font-size:28px;font-weight:600;letter-spacing:-0.03em;margin:0;flex:1;') }, 'Signature requests'),
          h('button', { className: 'forge-btn forge-btn--primary', onClick: () => go('request-signature') }, 'New request')),
        err && h('div', { style: S('font-size:12.5px;color:var(--bad);margin-bottom:10px;') }, err),
        rows === null
          ? h('div', { style: S('padding:40px;text-align:center;color:var(--fg-muted);') }, 'Loading…')
          : rows.length === 0
            ? h('div', { className: 'forge-card', style: S('padding:34px;text-align:center;color:var(--fg-muted);font-size:13.5px;') }, 'No signature requests yet — send your first one.')
            : h('div', { style: S('display:flex;flex-direction:column;gap:10px;') }, rows.map((r0) =>
                h('div', { key: r0.id, className: 'forge-card', style: S('padding:14px 18px;display:flex;align-items:center;gap:14px;flex-wrap:wrap;') },
                  h('div', { style: S('flex:1;min-width:220px;') },
                    h('div', { style: S('font-size:14px;font-weight:600;') }, r0.title),
                    h('div', { style: S('display:flex;gap:8px;flex-wrap:wrap;margin-top:4px;') },
                      (r0.recipients || []).map((rp, i) => h('span', { key: i, style: S('font-size:11px;color:' + (TINT[rp.status] || 'var(--fg-muted)') + ';') }, rp.email + ' · ' + rp.status)),
                      h('span', { style: S('font-size:11px;color:var(--fg-subtle);') }, (r0.createdAt || '').slice(0, 10)))),
                  h('span', { style: S('font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:' + (TINT[r0.status] || 'var(--fg-muted)') + ';') },
                    r0.status + (r0.status === 'completed' && r0.sealed === false ? ' (unsealed)' : '')),
                  h('div', { style: S('display:flex;gap:8px;') },
                    r0.status === 'completed' && h('button', { disabled: busyId === r0.id, className: 'forge-btn forge-btn--secondary forge-btn--sm', onClick: () => act(r0.id, 'download') }, 'Download'),
                    ['sent', 'viewed'].includes(r0.status) && h('button', { disabled: busyId === r0.id, className: 'forge-btn forge-btn--ghost forge-btn--sm', onClick: () => act(r0.id, 'void') }, 'Cancel'))))));
    }

    // Bulk send (F202 · Business) — one single-signer document → many recipients, each
    // signing their own sealed copy. Reuses PagePlacer with a single signer role; recipients
    // come from a pasted/loaded list. A batch runs server-side; we poll its progress.
    function BulkSend({ go }) {
      const [user, setUser] = useState(undefined);
      const [file, setFile] = useState(null);
      const [placements, setPlacements] = useState([]);
      const [rowsText, setRowsText] = useState('');
      const [title, setTitle] = useState('');
      const [message, setMessage] = useState('');
      const [phase, setPhase] = useState('edit'); // edit|sending|done|error
      const [errMsg, setErrMsg] = useState('');
      const [batch, setBatch] = useState(null); // { id, total, done, failed, status }

      useEffect(() => { authUser().then((u) => setUser(u || null)); }, []);

      const pick = (ev) => { const f = ev.target.files && ev.target.files[0]; if (f) { setFile(f); if (!title) setTitle(f.name); } };
      const parseRows = (text) => {
        const seen = new Set(); const rows = []; let bad = 0;
        String(text || '').split(/\r?\n/).map((l) => l.trim()).filter(Boolean).forEach((line) => {
          const parts = line.split(/[,;\t]/).map((s) => s.trim()).filter(Boolean);
          const email = (parts.find((p) => EMAIL_RE.test(p)) || '').toLowerCase();
          if (!EMAIL_RE.test(email)) { bad++; return; }
          if (seen.has(email)) return;
          seen.add(email);
          rows.push({ email, name: parts.filter((p) => p.toLowerCase() !== email).join(' ').slice(0, 120) });
        });
        return { rows, bad };
      };
      const loadCsv = (ev) => { const f = ev.target.files && ev.target.files[0]; if (!f) return; const rd = new FileReader(); rd.onload = () => setRowsText((t) => (t ? t + '\n' : '') + String(rd.result || '')); rd.readAsText(f); };

      const parsed = parseRows(rowsText);
      const hasSig = placements.some((p) => p.kind === 'signature');
      const valid = file && hasSig && parsed.rows.length > 0 && parsed.rows.length <= 50;

      const poll = async (id) => {
        for (let n = 0; n < 150; n++) {
          await new Promise((r) => setTimeout(r, 2000));
          try {
            const fb = initFirebase();
            const r = await fb.fns.httpsCallable('envelopeBulkList')({});
            const b = ((r.data && r.data.batches) || []).find((x) => x.id === id);
            if (b) { setBatch(b); if (b.status === 'completed' || b.status === 'error') return; }
          } catch (e) { /* transient — keep polling */ }
        }
      };
      const send = async () => {
        setPhase('sending'); setErrMsg('');
        try {
          const fb = initFirebase();
          if (!fb || !fb.fns) throw new Error('Service unavailable — try again shortly.');
          const pdfBase64 = await fileToB64(file);
          const res = await fb.fns.httpsCallable('envelopeBulkCreate')({
            title: title || file.name, message, placements, pdfBase64, rows: parsed.rows,
          });
          const b = res.data || {};
          setBatch({ id: b.batchId, total: b.total, done: 0, failed: 0, status: 'processing' });
          setPhase('done');
          poll(b.batchId);
        } catch (e) { setErrMsg((e && e.message) || 'Could not start the bulk send.'); setPhase('error'); }
      };

      if (user === undefined) return h('div', { style: S('padding:60px;text-align:center;color:var(--fg-muted);') }, 'Loading…');
      if (user === null) return signInCard('#/bulk', 'Sign in with your Mostly Tiny ID to send one document to many signers at once. Bulk send is a Business-plan feature ($29/month, or $24 billed yearly).');
      if (phase === 'done' && batch) {
        const pct = batch.total ? Math.round(((batch.done + batch.failed) / batch.total) * 100) : 0;
        const finished = batch.status === 'completed' || batch.status === 'error';
        return h('div', { className: 'forge-card', style: S('max-width:560px;margin:40px auto;padding:28px;text-align:center;') },
          h('div', { style: S('font-family:var(--font-display);font-size:20px;font-weight:600;') }, finished ? 'Bulk send complete ✓' : 'Sending…'),
          h('p', { style: S('font-size:13.5px;color:var(--fg-muted);margin:10px 0 16px;') },
            finished
              ? (batch.done + ' of ' + batch.total + ' sent' + (batch.failed ? ', ' + batch.failed + ' failed' : '') + '. Each signer got their own secure link; you’ll see them in your requests as they sign.')
              : ('Creating ' + batch.total + ' signing requests — ' + (batch.done + batch.failed) + ' of ' + batch.total + ' done.')),
          h('div', { style: S('height:8px;border-radius:999px;background:var(--bg-elev);overflow:hidden;margin-bottom:18px;') },
            h('div', { style: S('height:100%;width:' + pct + '%;background:var(--accent);transition:width .4s;') })),
          h('div', { style: S('display:flex;gap:8px;justify-content:center;') },
            h('button', { className: 'forge-btn forge-btn--secondary', onClick: () => go('agreements') }, 'Track requests'),
            finished && h('button', { className: 'forge-btn forge-btn--ghost', onClick: () => { setFile(null); setPlacements([]); setRowsText(''); setBatch(null); setPhase('edit'); } }, 'New bulk send')));
      }

      return h('div', { style: S('max-width:1100px;margin:0 auto;padding:26px 28px 8px;') },
        h('h1', { style: S('font-family:var(--font-display);font-size:30px;font-weight:600;letter-spacing:-0.03em;margin:0;') }, 'Bulk send'),
        h('p', { style: S('font-size:14.5px;color:var(--fg-muted);margin:8px 0 18px;max-width:46em;') }, 'Send one document to many signers at once — each person gets their own copy to sign, sealed and certified like any MostlySign document. Place the fields for a single signer, then paste your recipient list.'),
        h('div', { style: S('display:grid;grid-template-columns:minmax(0,1fr) 360px;gap:20px;align-items:start;') },
          h('div', { className: 'forge-card', style: S('padding:20px;') },
            !file
              ? h('div', { onClick: () => document.getElementById('mp-bulk-file').click(), style: S('display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:48px 24px;border-radius:var(--radius-xl);border:2px dashed var(--border-strong);background:var(--bg-elev);cursor:pointer;') },
                  h('div', { style: S('font-family:var(--font-display);font-size:17px;font-weight:600;') }, 'Choose the PDF to be signed'),
                  h('div', { style: S(hint + 'margin-top:6px;') }, 'PDF · up to 10 MB · one signer per copy'))
              : h('div', null,
                  h('div', { style: S('display:flex;align-items:center;gap:10px;margin-bottom:10px;') },
                    h('span', { style: S('font-size:13.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;') }, file.name),
                    h('button', { className: 'forge-btn forge-btn--ghost forge-btn--sm', onClick: () => { setFile(null); setPlacements([]); } }, 'Replace')),
                  h(PagePlacer, { file, placements, onPlacements: setPlacements, recipients: [{ name: 'Signer' }], activeRecipient: 0 })),
            h('input', { id: 'mp-bulk-file', type: 'file', accept: 'application/pdf', onChange: pick, style: S('display:none;') })),
          h('div', { className: 'forge-card', style: S('padding:20px;position:sticky;top:84px;') },
            h('div', { style: S('font-family:var(--font-display);font-size:16px;font-weight:600;margin-bottom:12px;') }, 'Recipients'),
            h('div', { style: S('display:flex;flex-direction:column;gap:12px;') },
              h('div', null,
                h('span', { style: S(label) }, 'One per line — “Name, email@company.com”'),
                h('textarea', { className: 'forge-input', value: rowsText, onChange: (ev) => setRowsText(ev.target.value), placeholder: 'Ada Lovelace, ada@acme.com\ngrace@navy.mil', style: S('width:100%;min-height:120px;margin-top:5px;padding:10px 12px;font-family:var(--font-mono,monospace);font-size:12.5px;') }),
                h('div', { style: S('display:flex;align-items:center;gap:10px;margin-top:6px;') },
                  h('span', { style: S(hint) }, parsed.rows.length + ' valid recipient' + (parsed.rows.length === 1 ? '' : 's') + (parsed.bad ? ' · ' + parsed.bad + ' line(s) without a valid email' : '') + (parsed.rows.length > 50 ? ' · max 50 per batch' : '')),
                  h('label', { className: 'forge-btn forge-btn--ghost forge-btn--sm', style: S('margin-left:auto;cursor:pointer;') }, 'Load CSV',
                    h('input', { type: 'file', accept: '.csv,text/csv,text/plain', onChange: loadCsv, style: S('display:none;') })))),
              h('div', null, h('span', { style: S(label) }, 'Document title'), h('input', { className: 'forge-input', value: title, onChange: (ev) => setTitle(ev.target.value), style: S('width:100%;margin-top:5px;') })),
              h('div', null, h('span', { style: S(label) }, 'Message (optional)'), h('textarea', { className: 'forge-input', value: message, onChange: (ev) => setMessage(ev.target.value), style: S('width:100%;min-height:56px;margin-top:5px;padding:10px 12px;') }))),
            file && !hasSig && h('div', { style: S(hint + 'margin-top:10px;') }, 'Add at least one signature field for the signer — “+ Signature” above the preview.'),
            phase === 'error' && h('div', { style: S('margin-top:10px;') },
              h('div', { style: S('font-size:12.5px;color:var(--bad);') }, errMsg),
              /Business|upgrade/i.test(errMsg) && h('button', { className: 'forge-btn forge-btn--primary forge-btn--sm', style: S('margin-top:8px;'), onClick: () => { location.hash = '#/pricing'; } }, 'Upgrade to Business — $29/month')),
            h('div', { style: S('margin-top:14px;padding-top:12px;border-top:1px solid var(--hairline);') },
              h('button', { disabled: !valid || phase === 'sending', onClick: send, className: 'forge-btn forge-btn--primary forge-btn--lg forge-btn--block' }, phase === 'sending' ? 'Starting…' : 'Send to ' + parsed.rows.length + ' recipient' + (parsed.rows.length === 1 ? '' : 's'))))));
    }

    // Team (F202 · ADR 0049) — teams/seats are an IDENTITY concern, managed ONCE in Mostly
    // Tiny ID and inherited across the whole portfolio. MostlySign doesn't fork a team model;
    // it explains seats and links to the org dashboard at the IdP.
    function Team({ go }) {
      const [user, setUser] = useState(undefined);
      useEffect(() => { authUser().then((u) => setUser(u || null)); }, []);
      const idBase = (idpLoginUrl && idpLoginUrl.replace(/\/login.*$/, '')) || 'https://id.mostlytiny.io';
      const orgUrl = idBase + '/organization';
      if (user === undefined) return h('div', { style: S('padding:60px;text-align:center;color:var(--fg-muted);') }, 'Loading…');
      if (user === null) return signInCard('#/team', 'Sign in with your Mostly Tiny ID to manage your team. Team seats are part of MostlySign Business ($29/month, or $24 billed yearly).');
      return h('div', { style: S('max-width:760px;margin:0 auto;padding:26px 28px 8px;') },
        h('h1', { style: S('font-family:var(--font-display);font-size:30px;font-weight:600;letter-spacing:-0.03em;margin:0;') }, 'Your team'),
        h('p', { style: S('font-size:14.5px;color:var(--fg-muted);margin:8px 0 20px;max-width:46em;') }, 'MostlySign Business includes team seats. Because your Mostly Tiny ID is shared across every Mostly Tiny product, you manage your organization — invite teammates, assign seats, connect SSO — in ONE place, and it applies everywhere, not just here.'),
        h('div', { className: 'forge-card', style: S('padding:22px;display:flex;flex-direction:column;gap:14px;') },
          h('div', { style: S('display:flex;align-items:flex-start;gap:14px;') },
            h('div', { style: S('font-size:26px;line-height:1;') }, '👥'),
            h('div', null,
              h('div', { style: S('font-family:var(--font-display);font-size:17px;font-weight:600;') }, 'Manage your organization in Mostly Tiny ID'),
              h('p', { style: S('font-size:13.5px;color:var(--fg-muted);margin:6px 0 0;') }, 'Create your organization, invite teammates by email, and manage seats. Everyone you add shares your Business plan across MostlySign and the rest of the portfolio.'))),
          h('a', { href: orgUrl, target: '_blank', rel: 'noopener', className: 'forge-btn forge-btn--primary', style: S('align-self:flex-start;text-decoration:none;') }, 'Open team settings →')),
        h('p', { style: S('font-size:12px;color:var(--fg-subtle);margin-top:14px;') }, 'Business plans include 10 seats. Enterprise SSO (SAML) and automatic provisioning (SCIM) are configured on the same organization.'));
    }

    return { RequestSignature, Agreements, BulkSend, Team };
  };
})();
