/* Top-level App for the Monolit CRM prototype. */
const { useState: useStateApp } = React;

const MONOLIT_TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "role": "Admin",
  "density": "regular",
  "dark": false,
  "bulkLock": false
}/*EDITMODE-END*/;

function App() {
  const data = window.MonolitData;
  const RB = window.MonolitRBAC;
  const params = new URLSearchParams(window.location.search);
  const deep = params.get('screen') || window.__MN_SCREEN__ || null;
  const deepId = params.get('id') || window.__MN_ID__ || null;
  const deepTab = params.get('tab') || null; // deep-link to a Lead Card tab (AC-LC-008)

  const [t, setTweak] = useTweaks(MONOLIT_TWEAK_DEFAULTS);
  const role = RB.ROLES.includes(t.role) ? t.role : 'Admin';

  // --- Lead store: lift leads into state so create / status / archive writes persist.
  // is_archived is a separate boolean layer from status (lead-lifecycle §2.1).
  const [leads, setLeads] = useStateApp(() => data.leads.map(l => ({ is_archived: false, disqualifiedReason: null, disqualifiedReasonText: '', ...l })));
  function updateLead(id, patch) { setLeads(ls => ls.map(l => l.id === id ? { ...l, ...patch, updatedAt: data.NOW } : l)); }
  function nextLeadCounter(ls) { return ls.reduce((m, l) => { const x = parseInt((String(l.id).match(/(\d+)\s*$/) || [])[1] || '0', 10); return x > m ? x : m; }, 0); }
  function buildLead(id, f) {
    const statusMap = { New: 'new', 'In progress': 'in_progress', Qualified: 'qualified' };
    return {
      id, name: (f.first + ' ' + (f.last || '')).trim(), company: f.company || '',
      email: f.email || '', phone: f.phone || '', status: statusMap[f.status] || 'new',
      score: null, owner: data.owners.find(o => o.id === f.owner) || null,
      nextStep: f.nextStep ? { text: f.nextStep, due: data.NOW } : null,
      country: f.country || '', city: '', source: { type: 'manual', name: f.sourceName || 'manual' },
      tags: f.tags || [], createdAt: data.NOW, updatedAt: data.NOW,
      activities: 0, isNew: true, problem: false,
      is_archived: false, disqualifiedReason: null, disqualifiedReasonText: '',
    };
  }
  function createLead(f) {
    const id = 'mon-' + String(nextLeadCounter(leads) + 1).padStart(5, '0');
    setLeads(ls => [buildLead(id, f), ...ls]);
    return id;
  }
  function importLeads(rows) {
    if (!rows || !rows.length) return 0;
    setLeads(ls => { let n = nextLeadCounter(ls); const created = rows.map(f => buildLead('mon-' + String(++n).padStart(5, '0'), f)); return [...created, ...ls]; });
    return rows.length;
  }
  function restoreLead(id) { updateLead(id, { is_archived: false }); }

  // --- Client store: lets Lead→Client conversion actually create a client.
  const [clients, setClients] = useStateApp(data.clients);
  function convertLead(lead, form) {
    const f = form || {};
    const maxN = clients.reduce((m, c) => { const x = parseInt((String(c.id).match(/(\d+)\s*$/) || [])[1] || '0', 10); return x > m ? x : m; }, 0);
    const clientId = 'mon-c-' + String(maxN + 1).padStart(5, '0');
    const owner = data.owners.find(o => o.id === f.owner) || lead.owner || null;
    const name = ((f.first || '') + ' ' + (f.last || '')).trim() || lead.name;
    const client = {
      ...data.clients[0], // template for field-completeness; overridden below
      id: clientId, name, account: f.accountName || lead.company || '',
      email: f.email || lead.email || '', phone: f.phone || lead.phone || '',
      country: lead.country || '', city: lead.city || '', tzOffset: 2, jobTitle: '', website: '',
      // Conversion makes the client a Prospect; Customer only after first Won deal (lead-conversion §9.4).
      owner, businessStatus: 'prospect', activityStatus: 'active', systemStatus: 'active',
      source: { type: 'lead_conversion', name: (lead.source && lead.source.name) || 'lead' },
      tags: lead.tags || [], createdAt: data.NOW, updatedAt: data.NOW, lastActivity: data.NOW,
      activeDeals: 0, openDealsValue: 0, totalRevenue: 0, totalDeals: 0, wonDeals: 0, activityCount: 0,
      createdFromLead: true, originalLeadId: lead.id,
    };
    setClients(cs => [client, ...cs]);
    // Re-link ALL this lead's deals to the new client — incl. Lost/Won as-is (lead-conversion AC-17/EC-13).
    if (data.deals) data.deals.forEach(d => { if (d.leadId === lead.id) { d.clientId = clientId; d.leadId = null; } });
    // Converted lead is read-only and its Next Step is cleared (lead-conversion §7.4).
    updateLead(lead.id, { status: 'converted', convertedTo: clientId, converted_at: data.NOW, nextStep: null });
    return clientId;
  }
  // Possible duplicates of a lead = other active leads sharing exact email or phone.
  function normEmail(s) { return (s || '').toLowerCase().trim(); }
  function normPhone(s) { return (s || '').replace(/[^\d]/g, ''); }
  function duplicatesOf(lead) {
    if (!lead) return [];
    const e = normEmail(lead.email), p = normPhone(lead.phone);
    return leads.filter(o => o.id !== lead.id && !o.is_archived &&
      ((e && normEmail(o.email) === e) || (p && p.length > 6 && normPhone(o.phone) === p)));
  }

  const [signedIn, setSignedIn] = useStateApp(deep && deep !== 'login' ? true : false);
  const [nav, setNav] = useStateApp(
    deep === 'admin' ? 'admin-users' :
    deep === 'dashboard' ? 'dashboard' :
    deep === 'clients' || deep === 'client-card' ? 'clients' :
    deep === 'deals' || deep === 'deal-card' ? 'deals' :
    deep === 'tasks' ? 'tasks' :
    deep === 'webhooks' ? 'webhooks' :
    deep === 'api-keys' ? 'api-keys' :
    deep === 'settings' ? 'settings' :
    deep === 'reports' ? 'reports' : 'leads'
  );
  const [openLeadId, setOpenLeadId] = useStateApp(deep === 'lead-card' ? (deepId || 'mon-00142') : null);
  const [openClientId, setOpenClientId] = useStateApp(deep === 'client-card' ? (deepId || 'mon-c-00064') : null);
  const [openDealId, setOpenDealId] = useStateApp(deep === 'deal-card' ? (deepId || 'deal-00112') : null);

  // overlay layer + toast
  const [overlay, setOverlay] = useStateApp(null); // { kind, props }
  const [toast, setToast] = useStateApp(null);
  function showToast(msg) { setToast(msg); clearTimeout(window.__mnToastT); window.__mnToastT = setTimeout(() => setToast(null), 2600); }

  // --- Bulk executor + Jobs / Operations state (prd-leads-bulk-actions) -----
  // Sync ≤50 records, async job above (BR-BA-006); chunked progress + one simulated
  // transient retry (BR-BA-008/009); partial failures isolated per lead (BR-BA-007).
  const [jobs, setJobs] = useStateApp([]);
  const [jobsOpen, setJobsOpen] = useStateApp(true);
  function patchJob(id, patch) { setJobs(js => js.map(j => (j.id === id ? { ...j, ...patch } : j))); }
  function addJob(job) { setJobs(js => [job, ...js]); setJobsOpen(true); }
  function nextJobId() { window.__mnJobSeq = (window.__mnJobSeq || 0) + 1; return 'job-' + window.__mnJobSeq; }
  // In-app notification channel (BR-BA-026) — feeds the top-bar Notifications drawer.
  function pushNotification(n) { data.notifications.unshift({ id: 'nb' + Date.now(), type: 'bulk', unread: true, icon: 'list-checks', at: 'just now', link: null, ...n }); }

  function runBulk(spec) {
    if (t.bulkLock) { showToast('Bulk operations are locked — emergency lock active'); return; } // BR-BA-027
    if (spec.action === 'export') return runExportJob(spec);
    const results = spec.items.map(l => ({ l, r: spec.apply(l) }));
    const failures = results.filter(x => !x.r.ok).map(x => ({ id: x.l.id, name: x.l.name, reason: x.r.reason, category: x.r.category || 'validation' }));
    const total = results.length, okCount = total - failures.length;
    if (total <= 50) {
      results.forEach(x => { if (x.r.ok && x.r.patch && Object.keys(x.r.patch).length) updateLead(x.l.id, x.r.patch); });
      showToast(spec.doneLabel(okCount) + (failures.length ? ' · ' + failures.length + ' failed' : ''));
      if (failures.length) addJob({ id: nextJobId(), label: spec.label, total, processed: total, failed: failures.length, failures, state: 'partial', retries: 0, etaMs: 0 });
      return;
    }
    const id = nextJobId();
    addJob({ id, label: spec.label, total, processed: 0, failed: 0, failures, state: 'running', retries: 0, etaMs: total * 25 });
    const tickMs = 320, chunk = Math.max(3, Math.ceil(total / 14));
    let i = 0, retried = total < 120; // simulate one transient infra retry on big batches only
    const iv = setInterval(() => {
      if (!retried && i >= Math.floor(total * 0.55)) { retried = true; patchJob(id, { state: 'retrying', retries: 1 }); return; }
      const slice = results.slice(i, i + chunk); i += slice.length;
      slice.forEach(x => { if (x.r.ok && x.r.patch && Object.keys(x.r.patch).length) updateLead(x.l.id, x.r.patch); });
      const failedSoFar = results.slice(0, i).filter(x => !x.r.ok).length;
      const done = i >= total;
      patchJob(id, { state: done ? (failures.length ? 'partial' : 'completed') : 'running', processed: i, failed: failedSoFar, etaMs: Math.ceil((total - i) / chunk) * tickMs });
      if (done) {
        clearInterval(iv);
        showToast(spec.doneLabel(okCount) + (failures.length ? ' · ' + failures.length + ' failed' : ''));
        pushNotification({ title: 'Bulk action finished', body: spec.label + ' — ' + okCount + ' succeeded' + (failures.length ? ', ' + failures.length + ' failed' : '') });
      }
    }, tickMs);
  }

  function runExportJob(spec) {
    // ≤10k + direct download → immediate; email delivery (or 10k+) → async job (BR-BA-018).
    if (spec.delivery === 'download' && spec.count <= 10000) {
      mnDownloadFile(spec.file);
      showToast('Exported ' + spec.count + ' lead' + (spec.count === 1 ? '' : 's') + ' · logged as lead.exported');
      return;
    }
    const id = nextJobId(), total = spec.count;
    addJob({ id, label: spec.label, total, processed: 0, failed: 0, failures: [], state: 'running', retries: 0, etaMs: 3000 });
    const tickMs = 300, chunk = Math.max(5, Math.ceil(total / 10));
    let i = 0;
    const iv = setInterval(() => {
      i = Math.min(total, i + chunk);
      const done = i >= total;
      patchJob(id, { processed: i, state: done ? 'completed' : 'running', etaMs: Math.ceil((total - i) / chunk) * tickMs, file: done ? spec.file : undefined });
      if (done) {
        clearInterval(iv);
        showToast('Export ready — link sent to your email');
        pushNotification({ title: 'Export ready', body: spec.label + ' — download link sent by email (expires in 7 days)', icon: 'download' });
      }
    }, tickMs);
  }

  React.useEffect(() => { document.documentElement.dataset.theme = t.dark ? 'dark' : 'light'; }, [t.dark]);

  // Keep the URL in sync with the current screen so a browser reload restores
  // the same page (and stays signed in) instead of bouncing back to Login.
  React.useEffect(() => {
    let qs = '';
    if (signedIn) {
      const p = new URLSearchParams();
      if (openDealId) { p.set('screen', 'deal-card'); p.set('id', openDealId); }
      else if (openLeadId) { p.set('screen', 'lead-card'); p.set('id', openLeadId); }
      else if (openClientId) { p.set('screen', 'client-card'); p.set('id', openClientId); }
      else { p.set('screen', nav === 'admin-users' ? 'admin' : nav); }
      qs = '?' + p.toString();
    }
    window.history.replaceState(null, '', window.location.pathname + qs);
  }, [signedIn, nav, openLeadId, openClientId, openDealId]);

  function openRecord(link) {
    if (!link) return;
    setOverlay(null); setOpenLeadId(null); setOpenClientId(null); setOpenDealId(null);
    if (link.kind === 'lead') { setNav('leads'); setOpenLeadId(link.id); }
    else if (link.kind === 'client') { setNav('clients'); setOpenClientId(link.id); }
    else if (link.kind === 'deal') { setNav('deals'); setOpenDealId(link.id); }
    else if (link.kind === 'task') { setNav('tasks'); }
    else if (link.kind) { setNav(link.kind); }
  }
  function quickCreate(type) {
    setOverlay({ kind: 'create-' + type, props: { mode: type === 'deal' || type === 'activity' ? undefined : 'quick' } });
  }

  if (!signedIn) return <Login onSuccess={() => setSignedIn(true)} />;

  let view = null;
  if (openDealId) {
    const deal = data.deals.find(d => d.id === openDealId);
    view = <DealCard deal={deal} role={role} onBack={() => setOpenDealId(null)}
                     onConvertLead={deal && deal.leadId ? () => { const l = leads.find(x => x.id === deal.leadId); if (l) setOverlay({ kind: 'convert', props: { lead: l } }); else { setOpenDealId(null); setNav('leads'); setOpenLeadId(deal.leadId); } } : undefined}
                     onOpenParent={() => { setOpenDealId(null); if (deal.clientId) { setNav('clients'); setOpenClientId(deal.clientId); } else { setNav('leads'); setOpenLeadId(deal.leadId); } }} />;
  } else if (openLeadId) {
    const lead = leads.find(l => l.id === openLeadId);
    if (!lead) {
      // Existence-leakage-safe: missing / out-of-scope lead → back to list (sidebar-and-edit-rules §Not found).
      view = (
        <React.Fragment>
          <div className="mn-page-h" style={{ paddingBottom: 0 }}><button className="mn-drawer-back" onClick={() => setOpenLeadId(null)} type="button"><Icon name="arrow-left" size="xs" /> Back to leads</button></div>
          <div className="mn-empty" style={{ paddingTop: 100 }}>
            <Icon name="search-x" size="lg" />
            <div className="mn-empty-msg">Lead not found, or outside your access. It may have been archived or reassigned.</div>
            <Button variant="primary" size="sm" onClick={() => setOpenLeadId(null)}>Back to leads</Button>
          </div>
        </React.Fragment>
      );
    } else {
      view = <LeadCard lead={lead} activity={data.activity} role={role} initialTab={deepTab} clients={clients} onBack={() => setOpenLeadId(null)}
                     onConvert={() => setOverlay({ kind: 'convert', props: { lead } })}
                     onAssign={() => setOverlay({ kind: 'assign', props: { lead } })}
                     onUnassign={() => setOverlay({ kind: 'unassign', props: { entityName: lead.name, lead } })}
                     onLifecycle={(action) => setOverlay({ kind: 'lifecycle', props: { lead, action } })}
                     onUpdate={updateLead}
                     onRestore={() => restoreLead(lead.id)}
                     duplicates={duplicatesOf(lead)}
                     onAddActivity={(presetType) => setOverlay({ kind: 'create-activity', props: { entityLabel: lead.name, entityEmail: lead.email, presetType: typeof presetType === 'string' ? presetType : undefined } })}
                     onEditDetails={() => setOverlay({ kind: 'edit-lead', props: { lead } })}
                     onNewDeal={() => setOverlay({ kind: 'create-deal', props: { presetParentKind: 'lead', presetParentId: lead.id } })}
                     onOpenClient={(id) => openRecord({ kind: 'client', id })}
                     onOpenLead={(id) => { setOpenLeadId(id); }}
                     onToast={showToast} />;
    }
  } else if (openClientId) {
    const client = clients.find(c => c.id === openClientId);
    view = <ClientCard client={client} role={role} onBack={() => setOpenClientId(null)}
                       onOpenDeal={(id) => setOpenDealId(id)}
                       onAddActivity={() => setOverlay({ kind: 'create-activity', props: { entityLabel: client.name, entityEmail: client.email } })}
                       onToast={showToast} />;
  } else if (nav === 'dashboard') {
    view = <Dashboard leads={data.leads} activity={data.activity} />;
  } else if (nav === 'leads') {
    view = <LeadsList leads={leads} role={role} onOpenLead={(id) => setOpenLeadId(id)}
                      onCreate={() => setOverlay({ kind: 'create-lead', props: { mode: 'full' } })} onToast={showToast}
                      onUpdate={updateLead}
                      onAssign={(id) => setOverlay({ kind: 'assign', props: { lead: leads.find(l => l.id === id) } })}
                      onDisqualify={(id) => setOverlay({ kind: 'lifecycle', props: { lead: leads.find(l => l.id === id), action: 'disqualify' } })}
                      onArchive={(id) => setOverlay({ kind: 'lifecycle', props: { lead: leads.find(l => l.id === id), action: 'archive' } })}
                      onRestore={restoreLead}
                      onImport={importLeads}
                      bulkLock={!!t.bulkLock} onRunBulk={runBulk} />;
  } else if (nav === 'clients') {
    view = <ClientsList clients={clients} role={role} onOpenClient={(id) => setOpenClientId(id)} onCreate={() => setOverlay({ kind: 'create-client', props: { mode: 'full' } })} />;
  } else if (nav === 'deals') {
    view = <DealsList deals={data.deals} role={role} onOpenDeal={(id) => setOpenDealId(id)} onCreate={() => setOverlay({ kind: 'create-deal', props: {} })} />;
  } else if (nav === 'tasks') {
    view = <Activities tasks={data.tasks} role={role} onCreate={() => setOverlay({ kind: 'create-activity', props: {} })} />;
  } else if (nav === 'webhooks') {
    view = <Webhooks role={role} onToast={showToast} />;
  } else if (nav === 'api-keys') {
    view = <ApiKeys role={role} onToast={showToast} />;
  } else if (nav === 'admin-users') {
    view = RB.can(role, 'users.read')
      ? <AdminUsers users={data.users} role={role} onToast={showToast} />
      : <NoAccessView label="Users & access" perm="users.read" />;
  } else if (nav === 'settings') {
    view = <Settings role={role} dark={t.dark} onToggleDark={(v) => setTweak('dark', v)} onToast={showToast} />;
  } else if (nav === 'reports') {
    view = <Reports role={role} />;
  } else {
    view = <ComingSoon nav={nav} />;
  }

  const scopedClients = RB.scopeClients(role, clients).filter(c => c.systemStatus !== 'archived');
  const myOpenTasks = data.tasks.filter(tk => tk.status === 'open' && tk.owner && tk.owner.id === RB.ME);
  const scopedActiveDeals = scopeDeals(role, data.deals).filter(dealIsActive);
  const activeLeadCount = leads.filter(l => !l.is_archived).length;

  return (
    <React.Fragment>
      <Shell currentNav={openDealId ? 'deals' : openLeadId ? 'leads' : openClientId ? 'clients' : nav}
             onNav={(id) => { setOpenLeadId(null); setOpenClientId(null); setOpenDealId(null); setNav(id); }}
             currentUser={{ initials: 'ML', color: 'teal', name: 'Maria Lis' }}
             role={role}
             onLogout={() => { setSignedIn(false); setOpenLeadId(null); setOpenClientId(null); setOpenDealId(null); setNav('leads'); }}
             onQuickCreate={quickCreate} onOpenRecord={openRecord} onOpenSettings={() => { setOpenLeadId(null); setOpenClientId(null); setOpenDealId(null); setNav('settings'); }}
             dark={t.dark} onToggleDark={(v) => setTweak('dark', v)}
             counts={{ leads: activeLeadCount, clients: scopedClients.length, tasks: myOpenTasks.length, deals: scopedActiveDeals.length }}>
        {view}
      </Shell>

      <OverlayHost overlay={overlay} role={role} onClose={() => setOverlay(null)} onToast={showToast} onOpenRecord={openRecord} onCreateLead={createLead} onUpdateLead={updateLead} onConvertLead={convertLead} onOpenConvert={(leadId) => setOverlay({ kind: 'convert', props: { lead: leads.find(l => l.id === leadId) } })} />

      {toast ? <div className="mn-toast"><Icon name="check-circle" size="sm" />{toast}</div> : null}

      <JobsPanel jobs={jobs} open={jobsOpen} onToggle={setJobsOpen} onDismiss={(id) => setJobs(js => js.filter(j => j.id !== id))} />

      <TweaksPanel>
        <TweakSection label="RBAC" />
        <TweakSelect label="Role" value={role} options={RB.ROLES} onChange={(v) => setTweak('role', v)} />
        <TweakSection label="Operations" />
        <TweakToggle label="Emergency bulk lock" value={!!t.bulkLock} onChange={(v) => setTweak('bulkLock', v)} />
        <TweakSection label="Theme" />
        <TweakToggle label="Dark mode" value={t.dark} onChange={(v) => setTweak('dark', v)} />
      </TweaksPanel>
    </React.Fragment>
  );
}

function OverlayHost({ overlay, role, onClose, onToast, onOpenRecord, onCreateLead, onUpdateLead, onConvertLead, onOpenConvert }) {
  if (!overlay) return null;
  const k = overlay.kind, p = overlay.props || {};
  if (k === 'create-lead')   return <CreateLeadForm   mode={p.mode || 'full'} role={role} onClose={onClose} onToast={onToast} onOpenRecord={onOpenRecord} onCreate={onCreateLead} />;
  if (k === 'create-client') return <CreateClientForm mode={p.mode || 'full'} role={role} onClose={onClose} onToast={onToast} onOpenRecord={onOpenRecord} />;
  if (k === 'create-deal')   return <CreateDealForm   role={role} presetParentKind={p.presetParentKind} presetParentId={p.presetParentId} onConvertLead={p.presetParentKind === 'lead' && p.presetParentId && onOpenConvert ? () => onOpenConvert(p.presetParentId) : undefined} onClose={onClose} onToast={onToast} />;
  if (k === 'create-activity') return <AddActivityForm role={role} entityLabel={p.entityLabel} entityEmail={p.entityEmail} presetType={p.presetType} onClose={onClose} onToast={onToast} />;
  if (k === 'edit-lead') return <EditLeadDetailsModal lead={p.lead} onClose={onClose} onSave={(patch) => { onClose(); onUpdateLead(p.lead.id, patch); onToast('Details updated'); }} />;
  if (k === 'convert')   return <ConversionModal lead={p.lead} role={role} onClose={onClose}
                                  onConverted={(lead, form) => { const cid = onConvertLead ? onConvertLead(lead, form) : (lead.convertedTo || 'mon-c-00064'); onClose(); onToast('Lead converted → Client'); onOpenRecord({ kind: 'client', id: cid }); }} />;
  if (k === 'lifecycle') {
    if (p.action === 'disqualify') return <DisqualifyModal lead={p.lead} onClose={onClose}
                                  onConfirm={(reason, text) => { onClose(); onUpdateLead(p.lead.id, { status: 'disqualified', disqualifiedReason: reason, disqualifiedReasonText: text || '' }); onToast('Lead disqualified'); }} />;
    return <LeadLifecycleModal lead={p.lead} action={p.action} onClose={onClose}
                                  onConfirm={() => { onClose(); onUpdateLead(p.lead.id, { is_archived: true, archived_at: window.MonolitData.NOW, archive_reason: 'manual' }); onToast('Lead archived'); }} />;
  }
  if (k === 'assign')    return <AssignOwnerModal lead={p.lead} role={role} onClose={onClose}
                                  onConfirm={(ownerId) => { onClose(); onUpdateLead(p.lead.id, { owner: window.MonolitData.owners.find(o => o.id === ownerId) || null }); onToast('Owner assigned'); }} />;
  if (k === 'unassign')  return <UnassignModal entityName={p.entityName} onClose={onClose}
                                  onConfirm={() => { onClose(); if (p.lead) onUpdateLead(p.lead.id, { owner: null }); onToast('Owner unassigned · logged'); }} />;
  return null;
}

function NoAccessView({ label, perm }) {
  return (
    <React.Fragment>
      <div className="mn-page-h"><div className="mn-page-title"><h1 className="title-1">{label}</h1></div></div>
      <div className="mn-empty" style={{ paddingTop: 100 }}>
        <Icon name="shield" size="lg" />
        <div className="mn-empty-msg">You don’t have access to this area. Requires the <span className="mn-mono">{perm}</span> permission.</div>
      </div>
    </React.Fragment>
  );
}

function ComingSoon({ nav }) {
  return (
    <React.Fragment>
      <div className="mn-page-h"><div className="mn-page-title"><h1 className="title-1">{nav}</h1></div></div>
      <div className="mn-empty" style={{ paddingTop: 120 }}>
        <Icon name="construction" size="lg" />
        <div className="mn-empty-msg">This surface is documented in the PRDs but not built in this kit.</div>
      </div>
    </React.Fragment>
  );
}

ReactDOM.createRoot(document.getElementById('app')).render(<App />);
