// form.jsx — Form step. Collects all deal details with coaching + completeness sidebar.

const { useState: useFormState, useEffect: useFormEffect, useMemo: useFormMemo } = React;

function FormStep({ docId, initialValues, onSubmit, onBack, showCompleteness, showCoaching }) {
  const schema = window.getSchema(docId);
  const doc = window.DOC_BY_ID[docId];
  const [values, setValues] = useFormState(() => applyAutoFills(initialValues || window.DEMO_VALUES[docId] || {}, schema));
  const [touched, setTouched] = useFormState({});
  const [activeSection, setActiveSection] = useFormState(schema.sections[0].id);
  const [notes, setNotes] = useFormState('');

  // ─── LOI pre-fill state (Purchase Agreement only) ───────────────────
  const [loiBusy, setLoiBusy] = useFormState(false);
  const [loiError, setLoiError] = useFormState(null);
  const [loiResult, setLoiResult] = useFormState(null);

  // Field-id → friendly label map for the "pre-filled" success summary
  const fieldLabel = (id) => {
    for (const sec of schema.sections) {
      for (const f of sec.fields) {
        if (f.id === id) return f.label;
      }
    }
    return id;
  };

  const handleLoiUpload = async (file) => {
    if (!file) return;
    setLoiBusy(true); setLoiError(null);
    try {
      const fd = new FormData();
      fd.append('file', file);
      const res = await window.authedFetch('/api/extract-loi', {
        method: 'POST',
        body: fd,
      });
      if (!res.ok) {
        const errBody = await res.json().catch(() => ({ error: res.statusText }));
        throw new Error(errBody.error || `Extraction failed (HTTP ${res.status})`);
      }
      const data = await res.json();
      // Merge non-null extracted values into form state
      const filled = [];
      const newValues = { ...values };
      for (const [k, v] of Object.entries(data.fields || {})) {
        if (v !== null && v !== undefined && v !== '') {
          newValues[k] = v;
          filled.push(k);
        }
      }
      setValues(newValues);
      setLoiResult({
        filename: file.name,
        filledFields: filled,
        notes: data.notes || '',
      });
    } catch (e) {
      console.error('LOI extraction failed:', e);
      setLoiError(String(e.message || e));
    } finally {
      setLoiBusy(false);
    }
  };

  useFormEffect(() => { if (window.lucide) window.lucide.createIcons(); });

  const setField = (id, val) => {
    setValues(v => {
      const next = {...v, [id]: val};
      // Auto-compute expiration when effective date changes (1 year + 1 month, rounded to end of month)
      if (id === 'effectiveDate' && val) {
        const exp = computeExpiration(val);
        if (exp) next.expirationDate = exp;
      }
      // Cascade defaults from select fields (e.g. leaseStructure -> Option 1/2 defaults)
      const fld = findField(schema, id);
      if (fld && fld.cascade && fld.cascade[val]) {
        Object.assign(next, fld.cascade[val]);
      }
      return next;
    });
    setTouched(t => ({...t, [id]: true}));
  };

  // ─── Completeness logic ─────────────────────────────────────────────
  const { allFields, requiredFields, filledRequired, missingRequired, completeness, warnings } = useFormMemo(() => {
    const all = schema.sections.flatMap(s => s.fields.filter(f => shouldShow(f, values)).map(f => ({...f, sectionTitle: s.title})));
    const required = all.filter(f => f.required);
    const filled = required.filter(f => isFilled(values[f.id]));
    const missing = required.filter(f => !isFilled(values[f.id]));
    const optional = all.filter(f => !f.required);
    const filledOpt = optional.filter(f => isFilled(values[f.id]));
    const totalScore = (filled.length * 1.0) + (filledOpt.length * 0.5);
    const maxScore = (required.length * 1.0) + (optional.length * 0.5);
    const pct = Math.round((totalScore / maxScore) * 100);

    // warnings — domain-aware checks
    const warns = [];
    const commVal = parseFloat(values.commissionPct || values.commission);
    if (docId === 'tenant-rep' && commVal && (commVal < 4 || commVal > 6)) {
      warns.push({ field: 'commissionPct', label: 'Commission outside CEG standard 4–6%', sev: 'warn' });
    }
    if (docId === 'list-lease' && commVal && (commVal < 4 || commVal > 6)) {
      warns.push({ field: 'commission', label: 'Listing commission outside CEG standard 4–6%', sev: 'warn' });
    }
    if (docId === 'buyer-rep' && commVal && (commVal < 2 || commVal > 3)) {
      warns.push({ field: 'commissionPct', label: 'Buyer commission outside 2–3% range', sev: 'warn' });
    }
    if (values.termMonths === 'Custom') {
      warns.push({ field: 'termMonths', label: 'Custom term — requires Jeff to review', sev: 'warn' });
    }

    return {
      allFields: all, requiredFields: required,
      filledRequired: filled, missingRequired: missing,
      completeness: Math.min(pct, 100),
      warnings: warns,
    };
  }, [values, docId]);

  const canSubmit = missingRequired.length === 0;

  // section completion
  const sectionStatus = (sec) => {
    const visible = sec.fields.filter(f => shouldShow(f, values));
    const reqs = visible.filter(f => f.required);
    const done = reqs.filter(f => isFilled(values[f.id]));
    return { total: reqs.length, done: done.length, complete: done.length === reqs.length };
  };

  return (
    <div className="canvas-pad fade-in">
      <div className="page-head">
        <div>
          <div className="eyebrow-sm">Step 03 · Fill in the details</div>
          <h2 style={{marginTop:6}}>{schema.title}</h2>
          <div className="lead">{schema.subtitle}. We’ll merge these into approved CEG boilerplate language — fields marked <span style={{color:'var(--danger)', fontWeight:600}}>*</span> are required for a valid first draft.</div>
        </div>
        <div className="right">
          <button className="btn btn-ghost btn-sm" onClick={() => setValues(applyAutoFills(window.DEMO_VALUES[docId] || {}, schema))}>
            <i data-lucide="zap"></i> Prefill demo data
          </button>
        </div>
      </div>

      {/* ─── LOI pre-fill card (Purchase Agreement only) ─────────────── */}
      {docId === 'purchase-agreement' && (
        <LoiUploadCard
          loiBusy={loiBusy}
          loiError={loiError}
          loiResult={loiResult}
          fieldLabel={fieldLabel}
          onUpload={handleLoiUpload}
          onClear={() => { setLoiResult(null); setLoiError(null); }}
        />
      )}

      <div className="form-layout">
        {/* Main column */}
        <div>
          {schema.sections.map((sec, si) => {
            const st = sectionStatus(sec);
            return (
              <div key={sec.id} className={`section-card ${activeSection === sec.id ? 'is-active' : ''}`}>
                <div
                  className={`section-head ${st.complete ? 'complete' : ''}`}
                  onClick={() => setActiveSection(activeSection === sec.id ? null : sec.id)}
                >
                  <div className="sec-num">
                    {st.complete ? <i data-lucide="check" style={{width:13, height:13, strokeWidth:3}}></i> : (si + 1)}
                  </div>
                  <i data-lucide={sec.icon} style={{width:18, height:18, color:'var(--cyan-700)', strokeWidth:1.75}}></i>
                  <div className="sec-title">{sec.title}</div>
                  <div className="sec-meta">
                    <span style={{fontVariantNumeric:'tabular-nums'}}>{st.done}/{st.total} required</span>
                    <i data-lucide={activeSection === sec.id ? 'chevron-up' : 'chevron-down'} style={{width:16, height:16, color:'var(--ink-500)'}}></i>
                  </div>
                </div>
                {activeSection === sec.id && (
                  <div className="section-body">
                    <div className="grid-2">
                      {sec.fields.filter(f => shouldShow(f, values)).map(f => (
                        <Field
                          key={f.id}
                          field={f}
                          value={values[f.id] || ''}
                          touched={!!touched[f.id]}
                          onChange={v => setField(f.id, v)}
                          showCoaching={showCoaching}
                        />
                      ))}
                    </div>
                  </div>
                )}
              </div>
            );
          })}

          {/* Notes box */}
          <div className="section-card" style={{borderColor:'var(--cyan-300)', background: 'linear-gradient(180deg, #fff, var(--cyan-50))'}}>
            <div className="section-head" style={{background:'transparent', borderBottom:'none'}}>
              <div className="sec-num" style={{background:'var(--cyan-400)', color:'var(--ceg-navy)'}}>
                <i data-lucide="sparkles" style={{width:13, height:13, strokeWidth:2.5}}></i>
              </div>
              <div className="sec-title" style={{flex:1}}>Anything else we should know about this deal?</div>
              <div className="sec-meta">
                <span style={{color:'var(--cyan-700)', fontWeight:600}}>AI-assisted</span>
              </div>
            </div>
            <div className="section-body" style={{paddingTop: 0}}>
              <textarea
                className="field"
                placeholder="e.g. Eric mentioned they’re also evaluating two warehouses through CBRE. Closing pressure from their landlord — current lease expires Oct 2026. Wants flexibility on expansion option. Owner is a referral from Mark Allen.&#10;&#10;The AI will use these notes when drafting — and will flag anything that needs Jeff or Halie to weigh in."
                rows={5}
                value={notes}
                onChange={e => setNotes(e.target.value)}
                style={{background:'#fff'}}
              />
              <div className="coach" style={{marginTop: 10}}>
                <i data-lucide="info"></i>
                <div>
                  <b>Notes pull approved language only.</b> If you describe a clause the AI can’t handle from boilerplate, it will tell you to loop in Jeff or Halie before sending. Nothing custom slips through.
                </div>
              </div>
            </div>
          </div>
        </div>

        {/* Side column */}
        <div className="form-side">
          {showCompleteness && (
            <div className="completeness fade-in">
              <div className="ttl">
                <span>Completeness</span>
                {canSubmit
                  ? <span style={{color:'var(--success)', fontWeight:700}}>Ready</span>
                  : <span style={{color:'var(--warning)', fontWeight:700, fontFamily:'var(--font-mono)', letterSpacing:'0.04em'}}>{missingRequired.length} TO GO</span>}
              </div>
              <div className="pct">{completeness}%</div>
              <div className="bar"><div style={{width: completeness + '%'}}></div></div>

              <ul>
                {schema.sections.map(sec => {
                  const st = sectionStatus(sec);
                  return (
                    <li key={sec.id} className={st.complete ? 'done' : 'todo'}>
                      <i data-lucide={st.complete ? 'check-circle-2' : 'circle'}></i>
                      <span style={{flex:1}}>{sec.title}</span>
                      <span style={{fontFamily:'var(--font-mono)', fontSize:11, color:'var(--ink-500)'}}>{st.done}/{st.total}</span>
                    </li>
                  );
                })}
              </ul>

              {warnings.length > 0 && (
                <>
                  <div className="divider"></div>
                  <div className="ttl" style={{display:'flex', alignItems:'center', gap:6}}>
                    <i data-lucide="alert-triangle" style={{width:13, height:13, color:'var(--warning)', strokeWidth:2}}></i>
                    Needs attention
                  </div>
                  <ul style={{marginTop: 8}}>
                    {warnings.map((w, i) => (
                      <li key={i} className="warn">
                        <i data-lucide="alert-triangle"></i>
                        <span>{w.label}</span>
                      </li>
                    ))}
                  </ul>
                </>
              )}
            </div>
          )}

          <div className="ai-side fade-in">
            <div className="ttl"><i data-lucide="sparkles"></i> Boilerplate Assistant</div>
            <h4>Routes to {doc?.approver || 'Halie'} for review after you generate.</h4>
            <p>This document uses CEG-approved language. Once you generate a draft, you’ll review it section-by-section and request edits in chat — the assistant will only use language Jeff & Halie have signed off on.</p>
          </div>
        </div>
      </div>

      <div className="action-bar">
        <div className="left">
          <button className="btn btn-ghost" onClick={onBack}>
            <i data-lucide="arrow-left"></i> Back
          </button>
          <div className="status">
            <i data-lucide={canSubmit ? "check-circle-2" : "circle-dot"} style={{color: canSubmit ? 'var(--success)' : 'var(--warning)'}}></i>
            {canSubmit
              ? 'All required fields complete — ready to generate'
              : `${missingRequired.length} required field${missingRequired.length === 1 ? '' : 's'} remaining`}
          </div>
        </div>
        <div className="right">
          <button className="btn btn-ghost btn-sm">
            <i data-lucide="save"></i> Save draft
          </button>
          <button
            className="btn btn-accent btn-lg"
            disabled={!canSubmit}
            onClick={() => onSubmit(values, notes)}
          >
            <i data-lucide="sparkles"></i> Generate first draft <i data-lucide="arrow-right"></i>
          </button>
        </div>
      </div>
    </div>
  );
}

function Field({ field, value, touched, onChange, showCoaching }) {
  const isEmpty = !isFilled(value);
  const locked = !!field.locked;
  const showError = field.required && !locked && touched && isEmpty;
  const showCoach = showCoaching && field.coach && !locked;
  const span = field.span === 2 ? 'span-2' : '';
  const dis = locked ? { disabled: true } : {};
  const cls = `${showError ? 'is-error' : ''} ${locked ? 'is-locked' : ''}`.trim();

  let input;
  if (field.type === 'select') {
    input = (
      <select className={`field ${cls}`} value={value} {...dis} onChange={e => onChange(e.target.value)}>
        <option value="">Select…</option>
        {field.options.map(o => <option key={o} value={o}>{o}</option>)}
      </select>
    );
  } else if (field.type === 'textarea') {
    input = <textarea className={`field ${cls}`} rows={3} value={value} placeholder={field.placeholder} {...dis} onChange={e => onChange(e.target.value)} />;
  } else if (field.type === 'currency') {
    input = (
      <div className="field-shell has-prefix has-suffix">
        <span className="prefix">$</span>
        <input className={`field ${cls}`} value={value} placeholder={field.placeholder || '0.00'} {...dis} onChange={e => onChange(e.target.value)} />
        <span className="suffix">{field.suffix || 'USD'}</span>
      </div>
    );
  } else if (field.type === 'sf') {
    input = (
      <div className="field-shell has-suffix">
        <input className={`field field-mono ${cls}`} value={value} placeholder={field.placeholder || '0'} {...dis} onChange={e => onChange(e.target.value)} />
        <span className="suffix">SF</span>
      </div>
    );
  } else if (field.type === 'percent') {
    input = (
      <div className="field-shell has-suffix">
        <input className={`field field-mono ${cls}`} value={value} placeholder={field.placeholder || '0.0'} {...dis} onChange={e => onChange(e.target.value)} />
        <span className="suffix">%</span>
      </div>
    );
  } else if (field.type === 'date') {
    input = <input type="date" className={`field ${cls}`} value={value} {...dis} onChange={e => onChange(e.target.value)} />;
  } else if (field.type === 'email') {
    input = (
      <div className="field-shell has-icon">
        <i className="field-icon" data-lucide="mail"></i>
        <input type="email" className={`field ${cls}`} value={value} placeholder={field.placeholder} {...dis} onChange={e => onChange(e.target.value)} />
      </div>
    );
  } else if (field.type === 'tel') {
    input = (
      <div className="field-shell has-icon">
        <i className="field-icon" data-lucide="phone"></i>
        <input type="tel" className={`field ${cls}`} value={value} placeholder={field.placeholder} {...dis} onChange={e => onChange(e.target.value)} />
      </div>
    );
  } else if (field.type === 'image') {
    input = value ? (
      <div className="image-preview">
        <img src={value} alt="" />
        <button type="button" className="remove-btn" onClick={() => onChange('')}>
          <i data-lucide="x" style={{width:11, height:11, strokeWidth:2.5, verticalAlign:'-1px', marginRight:3}}></i>Remove
        </button>
      </div>
    ) : (
      <label className="image-drop">
        <input type="file" accept="image/*" style={{display:'none'}} onChange={e => {
          const f = e.target.files && e.target.files[0];
          if (!f) return;
          const reader = new FileReader();
          reader.onload = ev => onChange(ev.target.result);
          reader.readAsDataURL(f);
        }} />
        <i data-lucide="image-plus"></i>
        <div className="ttl">Drop or click to upload property photo</div>
        <div className="hint">JPG or PNG · optional — add to the Word version before sending if skipped</div>
      </label>
    );
  } else {
    input = <input type="text" className={`field ${cls}`} value={value} placeholder={field.placeholder} {...dis} onChange={e => onChange(e.target.value)} />;
  }

  return (
    <div className={`field-row ${span}`}>
      <label className="field-label">
        <span style={{flex:1}}>{field.label}</span>
        {field.required && !locked && <span className="req">*</span>}
        {!field.required && !locked && field.type !== 'image' && <span className="opt">— optional</span>}
        {locked && <span className="locked-pill"><i data-lucide="lock"></i>Locked</span>}
      </label>
      {input}
      {field.help && !showError && <div className="field-help">{field.help}</div>}
      {showError && <div className="field-error"><i data-lucide="alert-circle" style={{width:13, height:13, strokeWidth:2}}></i>This field is required.</div>}
      {showCoach && !showError && (
        <div className="coach">
          <i data-lucide="lightbulb"></i>
          <div>
            <b>{field.coach.tip}</b>
            {field.coach.example && <span className="example">{field.coach.example}</span>}
          </div>
        </div>
      )}
    </div>
  );
}

function isFilled(v) {
  if (v == null) return false;
  if (typeof v === 'string') return v.trim().length > 0;
  return true;
}

function shouldShow(field, values) {
  if (!field.showIf) return true;
  return Object.entries(field.showIf).every(([k, v]) => {
    if (Array.isArray(v)) return v.includes(values[k]);
    return values[k] === v;
  });
}

function findField(schema, id) {
  for (const sec of schema.sections) {
    for (const f of sec.fields) if (f.id === id) return f;
  }
  return null;
}

// Auto-set expiration to 1 year + 1 month after effective date, rounded to end of month.
// e.g. effective 2026-05-13 → expiration 2027-06-30
function computeExpiration(iso) {
  if (!iso) return '';
  const d = new Date(iso + 'T00:00:00');
  if (isNaN(d.getTime())) return '';
  let yr = d.getFullYear() + 1;
  let mo = d.getMonth() + 1; // 0-indexed +1 month
  if (mo > 11) { mo -= 12; yr += 1; }
  // Last day of (yr, mo): day 0 of next month
  const last = new Date(yr, mo + 1, 0);
  const yy = last.getFullYear();
  const mm = String(last.getMonth() + 1).padStart(2, '0');
  const dd = String(last.getDate()).padStart(2, '0');
  return `${yy}-${mm}-${dd}`;
}

// Apply auto-fills to a values object: default effective date to today, compute expiration,
// and pre-fill any locked fields that have a `default` value.
function applyAutoFills(vals, schema) {
  const next = {...vals};
  if (!isFilled(next.effectiveDate)) {
    const t = new Date();
    const yy = t.getFullYear();
    const mm = String(t.getMonth() + 1).padStart(2, '0');
    const dd = String(t.getDate()).padStart(2, '0');
    next.effectiveDate = `${yy}-${mm}-${dd}`;
  }
  // Always re-compute expiration to keep them in sync
  if (next.effectiveDate) {
    next.expirationDate = computeExpiration(next.effectiveDate);
  }
  // Fill locked defaults
  if (schema) {
    const flds = schema.sections.flatMap(s => s.fields);
    for (const f of flds) {
      if (f.default !== undefined && !isFilled(next[f.id])) {
        next[f.id] = f.default;
      }
    }
  }
  return next;
}

// ─── LOI Upload Card ──────────────────────────────────────────────────
// Renders at the top of the Purchase Agreement form. Broker drops in an
// LOI (PDF or DOCX); we extract structured deal data and pre-fill the form.
function LoiUploadCard({ loiBusy, loiError, loiResult, fieldLabel, onUpload, onClear }) {
  const [dragOver, setDragOver] = useFormState(false);
  const fileInputRef = React.useRef(null);

  useFormEffect(() => { if (window.lucide) window.lucide.createIcons(); }, [loiBusy, loiError, loiResult, dragOver]);

  const handleFile = (file) => {
    if (!file) return;
    const ext = (file.name.split('.').pop() || '').toLowerCase();
    if (!['pdf', 'docx', 'doc'].includes(ext)) {
      alert('Please upload a PDF or Word document.');
      return;
    }
    onUpload(file);
  };

  const onDrop = (e) => {
    e.preventDefault();
    setDragOver(false);
    const file = e.dataTransfer.files[0];
    handleFile(file);
  };

  // Show success state after extraction
  if (loiResult) {
    return (
      <div style={{
        background: 'var(--cyan-50)',
        border: '1px solid var(--cyan-200, #b3e5fc)',
        borderRadius: 'var(--radius-lg, 12px)',
        padding: '20px 24px',
        marginBottom: 24,
      }}>
        <div style={{display: 'flex', alignItems: 'center', gap: 10, marginBottom: 10}}>
          <span style={{fontSize: 20, color: 'var(--cyan-700)'}}>✓</span>
          <h4 style={{margin: 0, color: 'var(--ceg-navy)', fontSize: 15}}>
            Pre-filled {loiResult.filledFields.length} field{loiResult.filledFields.length === 1 ? '' : 's'} from <span style={{fontFamily: 'var(--font-mono)', fontSize: 13}}>{loiResult.filename}</span>
          </h4>
        </div>
        <div style={{fontSize: 13, color: 'var(--ink-700)', lineHeight: 1.5, marginBottom: 12}}>
          {loiResult.filledFields.map(f => fieldLabel(f)).join(' · ')}
        </div>
        {loiResult.notes && (
          <div style={{
            marginTop: 12, padding: '12px 14px',
            background: '#fff', borderRadius: 8,
            fontSize: 12.5, color: 'var(--ink-600)', lineHeight: 1.5,
            borderLeft: '3px solid var(--cyan-500, #29b6f6)',
          }}>
            <div style={{fontWeight: 600, marginBottom: 4, color: 'var(--ink-700)'}}>Notes from extraction (worth reviewing):</div>
            {loiResult.notes}
          </div>
        )}
        <div style={{marginTop: 14, fontSize: 12, color: 'var(--ink-500)'}}>
          Review the pre-filled values below — edit anything that looks wrong, fill in any blanks.{' '}
          <button onClick={onClear} style={{
            background: 'none', border: 'none', color: 'var(--cyan-700)',
            textDecoration: 'underline', cursor: 'pointer', fontSize: 12, padding: 0,
          }}>
            Upload a different LOI →
          </button>
        </div>
      </div>
    );
  }

  // Show upload UI
  return (
    <div style={{
      background: dragOver ? 'var(--cyan-50)' : '#fff',
      border: `${dragOver ? '2px' : '1px'} dashed ${dragOver ? 'var(--cyan-500, #29b6f6)' : 'var(--border-strong, #d4d8e0)'}`,
      borderRadius: 'var(--radius-lg, 12px)',
      padding: '24px 28px',
      marginBottom: 24,
      transition: 'all 120ms',
    }}
    onDragOver={(e) => { e.preventDefault(); setDragOver(true); }}
    onDragLeave={() => setDragOver(false)}
    onDrop={onDrop}
    >
      <div style={{display: 'flex', alignItems: 'flex-start', gap: 16}}>
        <div style={{
          width: 44, height: 44, borderRadius: 'var(--radius-md, 8px)',
          background: 'var(--cyan-50)', display: 'flex',
          alignItems: 'center', justifyContent: 'center',
          flexShrink: 0,
        }}>
          <span style={{fontSize: 22}}>📄</span>
        </div>
        <div style={{flex: 1}}>
          <h4 style={{margin: '0 0 6px', fontSize: 15, color: 'var(--ceg-navy)'}}>
            Have an LOI?
          </h4>
          <p style={{margin: '0 0 14px', fontSize: 13, color: 'var(--ink-600)', lineHeight: 1.55}}>
            Upload a signed or final Letter of Intent (PDF or Word) and we'll pre-fill property,
            parties, price, earnest money, and key dates from it. You'll review and fill in the rest.
          </p>
          <div style={{display: 'flex', gap: 12, alignItems: 'center', flexWrap: 'wrap'}}>
            <input
              ref={fileInputRef}
              type="file"
              accept=".pdf,.docx,.doc"
              style={{display: 'none'}}
              onChange={(e) => handleFile(e.target.files[0])}
            />
            <button
              type="button"
              className="btn btn-primary btn-sm"
              disabled={loiBusy}
              onClick={() => fileInputRef.current && fileInputRef.current.click()}
            >
              {loiBusy ? <>Reading LOI… <span style={{display: 'inline-block', animation: 'spin 1s linear infinite', marginLeft: 6}}>⟳</span></> : <>📎 Choose file</>}
            </button>
            <span style={{fontSize: 12, color: 'var(--ink-500)'}}>
              or drag &amp; drop here · PDF or Word, up to 5MB
            </span>
          </div>
          {loiError && (
            <div style={{
              marginTop: 12, padding: '10px 14px',
              background: 'rgba(220, 38, 38, 0.08)',
              border: '1px solid rgba(220, 38, 38, 0.25)',
              borderRadius: 8, color: '#991B1B', fontSize: 13,
            }}>
              <strong>Couldn't extract:</strong> {loiError}
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { FormStep, Field, isFilled, shouldShow, computeExpiration, applyAutoFills });
