/* MostlyPDF e-sign kit (F184/F185/F189/F190) — signature capture, click-to-place, and
   the public signer page. Registered as window.MostlyPDFSignKit:
     • SignatureInput — draw (canvas) / type / upload capture → {mode,text,imageBase64,imageType}
     • PagePlacer     — rendered page preview (pdfjs, lazy-vendored) + draggable field boxes in
                        NORMALIZED page coords (top-left fractions); multi-recipient aware
                        (colour-coded per signer) with signature/initials/date/text/checkbox kinds
     • SignerApp      — the public /sign page: capability link (+ optional access code, F189),
                        sequential-turn awareness (F190), text/checkbox inputs for the signer's
                        own fields, and an `?embed=1` mode that posts status via postMessage (F188)
   The authed sender screens live in mp/esign-screens.jsx. Evaluated during SSR via
   prerender.shared; copy is plain English (render-tools precedent). */
(function () {
  'use strict';
  if (typeof window === 'undefined') return;

  const CFG = window.MOSTLYPDF || {};
  const FN_BASE = (CFG.endpoint || '').replace(/\/pdfProcess\/?$/, '');
  const EP = {
    get: CFG.envelopeGetEndpoint || FN_BASE + '/envelopeGet',
    submit: CFG.envelopeSubmitEndpoint || FN_BASE + '/envelopeSubmit',
  };

  window.MostlyPDFSignKit = function makeSignKit(ctx) {
    // Brand-by-host (ADR 0048): the /sign signer page — every recipient's first touch — is
    // served from both mostlypdf.com and mostlysign.com. Resolve the brand name from the host
    // at runtime (Node/SSR → MostlyPDF default). Only the visible name differs; the platform
    // seal cert doing the actual sealing is the same.
    const BRAND = (function () {
      const h = (typeof location !== 'undefined' && location.hostname) || '';
      return /mostlysign|mostly-sign/.test(h) ? { name: 'MostlySign' } : { name: 'MostlyPDF' };
    })();
    const R = (ctx && ctx.React) || window.React;
    const { useState, useEffect, useRef } = R;
    const h = R.createElement;

    function S(str) {
      const o = {};
      (str || '').split(';').forEach((decl) => {
        const i = decl.indexOf(':');
        if (i < 0) return;
        let k = decl.slice(0, i).trim();
        const v = decl.slice(i + 1).trim();
        if (!k) return;
        if (!k.startsWith('--')) k = k.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
        o[k] = v;
      });
      return o;
    }
    const fileToB64 = (f) => new Promise((res, rej) => { const r = new FileReader(); r.onload = () => res(String(r.result).split(',')[1]); r.onerror = rej; r.readAsDataURL(f); });
    const hint = 'font-size:11.5px;color:var(--fg-subtle);';
    const chip = (on) => 'display:inline-flex;align-items:center;gap:5px;height:30px;padding:0 13px;border-radius:999px;font-size:12.5px;font-weight:600;border:1px solid transparent;cursor:pointer;' + (on ? 'background:var(--accent-bg-soft);color:var(--accent);' : 'background:var(--bg-chip);color:var(--fg-muted);');

    // Per-recipient field tints (multi-signer, F190). Index 0 keeps the accent coral.
    const RCOLORS = ['#e5533d', '#2563eb', '#10915a', '#9333ea', '#d97706'];
    const rgba = (hex, a) => {
      const n = parseInt(hex.slice(1), 16);
      return `rgba(${(n >> 16) & 255},${(n >> 8) & 255},${n & 255},${a})`;
    };

    let _pdfjsP = null;
    function loadPdfJs() {
      if (window.pdfjsLib) return Promise.resolve(window.pdfjsLib);
      if (_pdfjsP) return _pdfjsP;
      _pdfjsP = new Promise((resolve, reject) => {
        const s = document.createElement('script');
        s.src = '/vendor/pdfjs/pdf.min.js';
        s.onload = () => {
          try { window.pdfjsLib.GlobalWorkerOptions.workerSrc = '/vendor/pdfjs/pdf.worker.min.js'; } catch (e) {}
          resolve(window.pdfjsLib);
        };
        s.onerror = () => reject(new Error('pdf preview unavailable'));
        document.head.appendChild(s);
      });
      return _pdfjsP;
    }

    // ── SignaturePad ──
    function SignaturePad({ onChange }) {
      const canvasRef = useRef(null);
      const drawing = useRef(false);
      const dirty = useRef(false);
      useEffect(() => {
        const c = canvasRef.current;
        if (!c) return;
        const dpr = window.devicePixelRatio || 1;
        c.width = c.clientWidth * dpr; c.height = 150 * dpr;
        const g = c.getContext('2d');
        g.scale(dpr, dpr);
        g.lineWidth = 2.2; g.lineCap = 'round'; g.lineJoin = 'round'; g.strokeStyle = '#1a2033';
      }, []);
      const pos = (ev) => { const r = canvasRef.current.getBoundingClientRect(); return [ev.clientX - r.left, ev.clientY - r.top]; };
      const down = (ev) => { ev.preventDefault(); drawing.current = true; const g = canvasRef.current.getContext('2d'); const [x, y] = pos(ev); g.beginPath(); g.moveTo(x, y); canvasRef.current.setPointerCapture(ev.pointerId); };
      const move = (ev) => { if (!drawing.current) return; const g = canvasRef.current.getContext('2d'); const [x, y] = pos(ev); g.lineTo(x, y); g.stroke(); dirty.current = true; };
      const up = () => { if (!drawing.current) return; drawing.current = false; if (dirty.current && onChange) onChange(canvasRef.current.toDataURL('image/png').split(',')[1]); };
      const clear = () => { const c = canvasRef.current; c.getContext('2d').clearRect(0, 0, c.width, c.height); dirty.current = false; if (onChange) onChange(null); };
      return h('div', null,
        h('canvas', { ref: canvasRef, onPointerDown: down, onPointerMove: move, onPointerUp: up, onPointerLeave: up, style: S('width:100%;height:150px;border:1px dashed var(--border-strong);border-radius:var(--radius);background:#fff;cursor:crosshair;touch-action:none;display:block;') }),
        h('div', { style: S('display:flex;justify-content:space-between;align-items:center;margin-top:6px;') },
          h('span', { style: S(hint) }, 'Draw your signature above'),
          h('button', { onClick: clear, className: 'forge-btn forge-btn--ghost forge-btn--sm' }, 'Clear')));
    }

    // ── SignatureInput ──
    function SignatureInput({ value, onChange }) {
      const [mode, setMode] = useState((value && value.mode) || 'draw');
      const fileRef = useRef(null);
      const set = (v) => onChange && onChange(v);
      const pick = (m) => { setMode(m); set(null); };
      const onUpload = async (ev) => {
        const f = ev.target.files && ev.target.files[0];
        if (!f) return;
        if (!/image\/(png|jpe?g)/.test(f.type)) { set(null); return; }
        set({ mode: 'upload', imageBase64: await fileToB64(f), imageType: /png/.test(f.type) ? 'png' : 'jpg' });
      };
      return h('div', null,
        h('div', { style: S('display:flex;gap:8px;margin-bottom:10px;') },
          [['draw', 'Draw'], ['type', 'Type'], ['upload', 'Upload']].map(([m, lbl]) =>
            h('button', { key: m, onClick: () => pick(m), style: S(chip(mode === m)) }, lbl))),
        mode === 'draw' && h(SignaturePad, { onChange: (b64) => set(b64 ? { mode: 'draw', imageBase64: b64, imageType: 'png' } : null) }),
        mode === 'type' && h('div', null,
          h('input', { className: 'forge-input', placeholder: 'Type your full name', value: (value && value.text) || '', onChange: (ev) => set(ev.target.value.trim() ? { mode: 'type', text: ev.target.value } : null), style: S('width:100%;') }),
          h('div', { style: S('margin-top:8px;padding:14px;border-radius:var(--radius);background:#fff;border:1px solid var(--hairline);min-height:56px;display:grid;place-items:center;') },
            h('span', { style: S('font-style:italic;font-size:26px;color:#1a2033;font-family:var(--font-display);') }, (value && value.text) || ' '))),
        mode === 'upload' && h('div', null,
          h('button', { onClick: () => fileRef.current && fileRef.current.click(), className: 'forge-btn forge-btn--secondary' }, value && value.mode === 'upload' ? 'Replace image' : 'Choose a PNG or JPG'),
          value && value.mode === 'upload' && h('img', { alt: 'signature', src: 'data:image/' + (value.imageType === 'png' ? 'png' : 'jpeg') + ';base64,' + value.imageBase64, style: S('display:block;max-width:100%;max-height:90px;margin-top:8px;border:1px solid var(--hairline);border-radius:6px;background:#fff;padding:6px;') }),
          h('input', { ref: fileRef, type: 'file', accept: 'image/png,image/jpeg', onChange: onUpload, style: S('display:none;') })));
    }

    // ── PagePlacer ──
    const FIELD_DEFAULTS = {
      signature: { w: 0.32, h: 0.07 }, initials: { w: 0.12, h: 0.04 },
      date: { w: 0.18, h: 0.035 }, text: { w: 0.28, h: 0.04 }, checkbox: { w: 0.035, h: 0.035 },
    };
    const KIND_LABEL = { signature: 'Sign here', initials: 'Initials', date: 'Date', text: 'Text', checkbox: '✓' };
    function PagePlacer({ bytes, file, placements, onPlacements, single, readOnly, onPageSizes, recipients, activeRecipient }) {
      const [page, setPage] = useState(1);
      const [pages, setPages] = useState(1);
      const [err, setErr] = useState('');
      const [ratio, setRatio] = useState('595 / 842');
      const canvasRef = useRef(null);
      const wrapRef = useRef(null);
      const docRef = useRef(null);
      const drag = useRef(null);
      const multi = Array.isArray(recipients) && recipients.length > 1;

      useEffect(() => {
        let dead = false;
        (async () => {
          try {
            const data = bytes || (file ? new Uint8Array(await file.arrayBuffer()) : null);
            if (!data) return;
            const pdfjs = await loadPdfJs();
            const doc = await pdfjs.getDocument({ data: data.slice() }).promise;
            if (dead) return;
            docRef.current = doc;
            setPages(doc.numPages);
            const sizes = {};
            for (let i = 1; i <= doc.numPages; i++) {
              const vp = (await doc.getPage(i)).getViewport({ scale: 1 });
              sizes[i] = { w: vp.width, h: vp.height };
            }
            if (onPageSizes) onPageSizes(sizes);
            setErr('');
          } catch (e) { if (!dead) setErr(String((e && e.message) || e)); }
        })();
        return () => { dead = true; };
      }, [bytes, file]);

      useEffect(() => {
        let dead = false;
        (async () => {
          const doc = docRef.current, c = canvasRef.current;
          if (!doc || !c) return;
          try {
            const p = await doc.getPage(page);
            const cssW = (wrapRef.current && wrapRef.current.clientWidth) || 520;
            const vp1 = p.getViewport({ scale: 1 });
            setRatio(vp1.width + ' / ' + vp1.height);
            const dpr = window.devicePixelRatio || 1;
            const vp = p.getViewport({ scale: (cssW / vp1.width) * dpr });
            c.width = vp.width; c.height = vp.height;
            if (dead) return;
            await p.render({ canvasContext: c.getContext('2d'), viewport: vp }).promise;
          } catch (e) { if (!dead) setErr(String((e && e.message) || e)); }
        })();
        return () => { dead = true; };
      }, [page, pages, err]);

      const list = placements || [];
      const update = (i, patch) => onPlacements(list.map((p, j) => (j === i ? { ...p, ...patch } : p)));
      const removeAt = (i) => onPlacements(list.filter((_, j) => j !== i));
      const add = (kind) => {
        const d = FIELD_DEFAULTS[kind];
        const p = { kind, page, x: 0.5 - d.w / 2, y: 0.62, w: d.w, h: d.h, recipient: activeRecipient || 0 };
        onPlacements(single ? [p] : list.concat([p]));
      };
      const startDrag = (i) => (ev) => {
        if (readOnly) return;
        ev.preventDefault();
        const r = wrapRef.current.getBoundingClientRect();
        const p = list[i];
        drag.current = { i, dx: (ev.clientX - r.left) / r.width - p.x, dy: (ev.clientY - r.top) / r.height - p.y };
        ev.currentTarget.setPointerCapture(ev.pointerId);
      };
      const onMove = (ev) => {
        const d = drag.current;
        if (!d) return;
        const r = wrapRef.current.getBoundingClientRect();
        const p = list[d.i];
        update(d.i, {
          x: Math.min(Math.max((ev.clientX - r.left) / r.width - d.dx, 0), 1 - p.w),
          y: Math.min(Math.max((ev.clientY - r.top) / r.height - d.dy, 0), 1 - p.h),
        });
      };
      const endDrag = () => { drag.current = null; };
      const colorOf = (p) => RCOLORS[(p.recipient || 0) % RCOLORS.length];

      return h('div', null,
        !readOnly && h('div', { style: S('display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px;') },
          single
            ? h('button', { onClick: () => add('signature'), style: S(chip(true)) }, list.length ? 'Reposition signature' : 'Place signature')
            : [['signature', '+ Signature'], ['initials', '+ Initials'], ['date', '+ Date'], ['text', '+ Text'], ['checkbox', '+ Checkbox']].map(([k, lbl]) =>
                h('button', { key: k, onClick: () => add(k), style: S(chip(false)) }, lbl))),
        h('div', { ref: wrapRef, onPointerMove: onMove, onPointerUp: endDrag, style: S('position:relative;width:100%;aspect-ratio:' + ratio + ';border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;background:#fff;') },
          err
            ? h('div', { style: S('position:absolute;inset:0;display:grid;place-items:center;padding:20px;text-align:center;font-size:12.5px;color:var(--fg-subtle);') }, 'Page preview unavailable — fields still apply at the marked positions.')
            : h('canvas', { ref: canvasRef, style: S('position:absolute;inset:0;width:100%;height:100%;') }),
          list.map((p, i) => p.page === page && h('div', {
            key: i,
            onPointerDown: startDrag(i),
            style: S('position:absolute;left:' + p.x * 100 + '%;top:' + p.y * 100 + '%;width:' + p.w * 100 + '%;height:' + p.h * 100 + '%;border:1.5px dashed ' + colorOf(p) + ';border-radius:4px;background:' + rgba(colorOf(p), 0.15) + ';display:flex;align-items:center;justify-content:center;gap:5px;font-size:11px;font-weight:600;color:' + colorOf(p) + ';overflow:hidden;' + (readOnly ? '' : 'cursor:move;')) },
            (multi && !readOnly ? (p.recipient + 1) + '·' : '') + (KIND_LABEL[p.kind] || p.kind),
            !readOnly && h('span', { onPointerDown: (ev) => { ev.stopPropagation(); removeAt(i); }, style: S('cursor:pointer;font-weight:700;padding:0 4px;') }, '×')))),
        pages > 1 && h('div', { style: S('display:flex;align-items:center;justify-content:center;gap:12px;margin-top:8px;font-size:12.5px;color:var(--fg-muted);') },
          h('button', { className: 'forge-btn forge-btn--ghost forge-btn--sm', disabled: page <= 1, onClick: () => setPage(page - 1) }, '‹ Prev'),
          'Page ' + page + ' of ' + pages,
          h('button', { className: 'forge-btn forge-btn--ghost forge-btn--sm', disabled: page >= pages, onClick: () => setPage(page + 1) }, 'Next ›')));
    }

    // ── SignerApp (public /sign page) ──
    function SignerApp() {
      const [state, setState] = useState('loading'); // loading|code|waiting|ready|working|done|closed|error
      const [env, setEnv] = useState(null);
      const [bytes, setBytes] = useState(null);
      const [sig, setSig] = useState(null);
      const [consent, setConsent] = useState(false);
      const [declineOpen, setDeclineOpen] = useState(false);
      const [reason, setReason] = useState('');
      const [errMsg, setErrMsg] = useState('');
      const [code, setCode] = useState('');
      const [fieldVals, setFieldVals] = useState({}); // idx → value for my text/checkbox fields
      const [done, setDone] = useState(null);
      const cred = useRef({ id: '', token: '' });
      const embed = /[?&]embed=1/.test(location.search || '');
      const notifyHost = (status) => { if (embed) { try { window.parent.postMessage({ type: 'mostlypdf:esign', status }, '*'); } catch (e) {} } };

      const load = async (accessCode) => {
        setState('loading');
        try {
          const r = await fetch(EP.get, {
            method: 'POST', headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ envelopeId: cred.current.id, token: cred.current.token, ...(accessCode ? { accessCode } : {}) }),
          });
          const j = await r.json().catch(() => ({}));
          if (!r.ok) throw new Error(j.error || 'This signing link is invalid or expired.');
          setEnv(j);
          if (j.codeRequired) { setState('code'); return; }
          if (j.status === 'completed') { setDone({ sealed: j.sealed, url: j.downloadUrl }); setState('done'); return; }
          if (j.status === 'waiting' || j.status === 'waiting-others') { setState('waiting'); return; }
          if (['declined', 'voided', 'expired'].includes(j.status)) { setState('closed'); return; }
          const bin = atob(j.pdf);
          const u = new Uint8Array(bin.length);
          for (let i = 0; i < bin.length; i++) u[i] = bin.charCodeAt(i);
          setBytes(u);
          const init = {};
          (j.placements || []).forEach((p) => { if (p.kind === 'checkbox') init[p.idx] = !!p.value; if (p.kind === 'text' && p.value) init[p.idx] = p.value; });
          setFieldVals(init);
          setState('ready');
        } catch (e) { setErrMsg(e.message); setState('error'); }
      };

      useEffect(() => {
        const m = /[#&]e=([^&]+)&t=([^&]+)/.exec(location.hash || '');
        if (!m) { setErrMsg('This signing link is incomplete — use the link from your email.'); setState('error'); return; }
        cred.current = { id: m[1], token: decodeURIComponent(m[2]) };
        load();
      }, []);

      const submit = async (decline) => {
        setState('working');
        try {
          const body = decline
            ? { envelopeId: cred.current.id, token: cred.current.token, action: 'decline', reason, ...(code ? { accessCode: code } : {}) }
            : {
                envelopeId: cred.current.id, token: cred.current.token, consent: true,
                signature: sig && sig.imageBase64 ? { imageBase64: sig.imageBase64, imageType: sig.imageType, name: sig.text } : { text: sig.text },
                fields: fieldVals, ...(code ? { accessCode: code } : {}),
              };
          const r = await fetch(EP.submit, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) });
          const j = await r.json().catch(() => ({}));
          if (!r.ok) throw new Error(j.error || 'Could not complete the request.');
          if (decline) { setState('closed'); setEnv({ ...env, status: 'declined' }); notifyHost('declined'); return; }
          if (j.status === 'signed') { setDone({ partial: true, waitingFor: j.waitingFor }); setState('done'); notifyHost('signed'); return; }
          let url = null;
          if (j.pdf) {
            const bin = atob(j.pdf); const u = new Uint8Array(bin.length);
            for (let i = 0; i < bin.length; i++) u[i] = bin.charCodeAt(i);
            url = URL.createObjectURL(new Blob([u], { type: 'application/pdf' }));
          }
          setDone({ sealed: !!j.sealed, url });
          setState('done');
          notifyHost('completed');
        } catch (e) { setErrMsg(e.message); setState('ready'); }
      };

      const card = 'max-width:680px;margin:0 auto;padding:24px;';
      const shell = (body) => h('div', { style: S('min-height:100vh;background:var(--bg);color:var(--fg);font-family:var(--font-sans);padding:' + (embed ? '14px 12px' : '34px 20px 60px') + ';') },
        !embed && h('div', { style: S('max-width:680px;margin:0 auto 22px;display:flex;align-items:center;gap:10px;') },
          h('span', { style: S('font-family:var(--font-display);font-weight:600;font-size:19px;letter-spacing:-0.04em;') }, 'Mostly', h('span', { style: S('color:var(--accent);') }, 'PDF')),
          h('span', { style: S('font-size:12px;color:var(--fg-subtle);') }, '· secure signing')),
        body,
        !embed && h('p', { style: S('max-width:680px;margin:18px auto 0;font-size:11.5px;color:var(--fg-subtle);text-align:center;') },
          'Signing activity (time, IP address) is recorded in the document’s audit certificate.'));

      if (state === 'loading') return shell(h('div', { className: 'forge-card', style: S(card + 'text-align:center;color:var(--fg-muted);') }, 'Loading your document…'));
      if (state === 'error') return shell(h('div', { className: 'forge-card', style: S(card) }, h('strong', null, 'Signing link problem'), h('p', { style: S('color:var(--fg-muted);font-size:13.5px;') }, errMsg)));
      if (state === 'code') return shell(h('div', { className: 'forge-card', style: S(card) },
        h('div', { style: S('font-family:var(--font-display);font-size:19px;font-weight:600;') }, 'Access code required'),
        h('p', { style: S('color:var(--fg-muted);font-size:13.5px;margin:8px 0 12px;') },
          'The sender protected “' + ((env && env.title) || 'this document') + '” with an access code. Enter it to view and sign.'),
        h('input', { className: 'forge-input', value: code, onChange: (ev) => setCode(ev.target.value), placeholder: 'Access code', style: S('width:100%;margin-bottom:10px;') }),
        h('button', { className: 'forge-btn forge-btn--primary', disabled: !code.trim(), onClick: () => load(code.trim()) }, 'Unlock document')));
      if (state === 'waiting') return shell(h('div', { className: 'forge-card', style: S(card) },
        h('strong', null, env && env.status === 'waiting-others' ? 'You have signed — waiting for the other parties.' : 'Not your turn yet'),
        h('p', { style: S('color:var(--fg-muted);font-size:13.5px;margin:8px 0 0;') },
          env && env.status === 'waiting-others'
            ? 'You will receive the final sealed copy by email when everyone has signed.'
            : 'This document is signed in order' + (env && env.position ? ' — you are signer #' + env.position : '') + '. We will email you when it is your turn.')));
      if (state === 'closed') return shell(h('div', { className: 'forge-card', style: S(card) },
        h('strong', null, env && env.status === 'voided' ? 'This request was cancelled by the sender.'
          : env && env.status === 'expired' ? 'This request expired before everyone signed.'
          : 'This request was declined.'),
        h('p', { style: S('color:var(--fg-muted);font-size:13.5px;margin:8px 0 0;') }, (env && env.title) || '')));
      if (state === 'done') return shell(h('div', { className: 'forge-card', style: S(card) },
        h('div', { style: S('font-family:var(--font-display);font-size:20px;font-weight:600;') }, 'Signed ✓'),
        h('p', { style: S('color:var(--fg-muted);font-size:13.5px;margin:8px 0 14px;') },
          done && done.partial
            ? 'Thanks — your signature is recorded. ' + (done.waitingFor === 1 ? 'One other party still needs to sign.' : done.waitingFor + ' other parties still need to sign.') + ' Everyone gets the final sealed copy by email once complete.'
            : done && done.sealed
              ? 'Your signed copy carries a certificate of completion and is digitally sealed by ' + BRAND.name + ' — any later modification invalidates the seal.'
              : 'Your signed copy carries a certificate of completion. A download link was also emailed to you.'),
        done && done.url && h('a', { href: done.url, download: ((env && env.title) || 'signed') + '.pdf', className: 'forge-btn forge-btn--primary' }, 'Download signed PDF')));

      const busy = state === 'working';
      const myInputs = ((env && env.placements) || []).filter((p) => (p.kind === 'text' && !p.value) || p.kind === 'checkbox');
      return shell(h('div', null,
        h('div', { className: 'forge-card', style: S(card + 'margin-bottom:14px;') },
          h('div', { style: S('font-family:var(--font-display);font-size:20px;font-weight:600;letter-spacing:-0.02em;') }, (env && env.title) || 'Document'),
          h('p', { style: S('color:var(--fg-muted);font-size:13.5px;margin:6px 0 0;') },
            ((env && env.sender && (env.sender.name || env.sender.email)) || 'Someone') + ' asked you to review and sign this document.'),
          env && env.message && h('p', { style: S('font-size:13px;color:var(--fg);background:var(--bg-chip);border-radius:var(--radius);padding:10px 12px;margin:10px 0 0;') }, '“' + env.message + '”')),
        h('div', { className: 'forge-card', style: S(card + 'margin-bottom:14px;') },
          h(PagePlacer, { bytes, placements: (env && env.placements) || [], onPlacements: () => {}, readOnly: true })),
        h('div', { className: 'forge-card', style: S(card) },
          h('div', { style: S('font-weight:600;font-size:14.5px;margin-bottom:10px;') }, 'Your signature'),
          h(SignatureInput, { value: sig, onChange: setSig }),
          myInputs.length > 0 && h('div', { style: S('margin-top:14px;display:flex;flex-direction:column;gap:8px;') },
            h('div', { style: S('font-weight:600;font-size:13px;') }, 'Your fields'),
            myInputs.map((p) => p.kind === 'checkbox'
              ? h('label', { key: p.idx, style: S('display:flex;gap:8px;align-items:center;font-size:13px;cursor:pointer;') },
                  h('input', { type: 'checkbox', checked: !!fieldVals[p.idx], onChange: (ev) => setFieldVals({ ...fieldVals, [p.idx]: ev.target.checked }), style: S('accent-color:var(--accent);') }),
                  'Checkbox on page ' + p.page)
              : h('input', { key: p.idx, className: 'forge-input', placeholder: 'Text field (page ' + p.page + ')', value: fieldVals[p.idx] || '', onChange: (ev) => setFieldVals({ ...fieldVals, [p.idx]: ev.target.value }), style: S('width:100%;') }))),
          h('label', { style: S('display:flex;gap:9px;align-items:flex-start;margin:14px 0;cursor:pointer;font-size:12.5px;color:var(--fg-muted);line-height:1.5;') },
            h('input', { type: 'checkbox', checked: consent, onChange: (ev) => setConsent(ev.target.checked), style: S('margin-top:2px;accent-color:var(--accent);') }),
            'I agree to sign this document electronically, and I understand my electronic signature is as legally binding as an ink signature.'),
          errMsg && h('div', { style: S('font-size:12.5px;color:var(--bad);margin-bottom:10px;') }, errMsg),
          h('div', { style: S('display:flex;gap:10px;align-items:center;flex-wrap:wrap;') },
            h('button', { disabled: busy || !consent || !sig || !(sig.imageBase64 || (sig.text || '').trim()), onClick: () => submit(false), className: 'forge-btn forge-btn--primary forge-btn--lg' }, busy ? 'Signing…' : 'Sign document'),
            !declineOpen && h('button', { disabled: busy, onClick: () => setDeclineOpen(true), className: 'forge-btn forge-btn--ghost' }, 'Decline')),
          declineOpen && h('div', { style: S('margin-top:12px;') },
            h('textarea', { value: reason, onChange: (ev) => setReason(ev.target.value), placeholder: 'Why are you declining? (optional)', className: 'forge-input', style: S('width:100%;min-height:64px;padding:10px 12px;') }),
            h('button', { disabled: busy, onClick: () => submit(true), className: 'forge-btn forge-btn--secondary forge-btn--sm', style: S('margin-top:8px;') }, 'Decline to sign')))));
    }

    return { SignatureInput, SignaturePad, PagePlacer, SignerApp, loadPdfJs, S, fileToB64, chip, RCOLORS };
  };
})();
