// Page stubs — Franchisee Hub, Customer Intelligence, Network Reports, Talent Network, AI Insights, Settings

// ═══════════════════════════════════════════════════════════════════════
// FRANCHISEE HUB — operator communications, support tickets, agreement compliance
// ═══════════════════════════════════════════════════════════════════════

const FRANCHISEE_THREADS = [
  { id:'FT-082', location:'HB010', loc:'Scarborough',         operator:'K. Manderson',     subject:'Response to CASL incident notice',     lastMsg:'I understand. Will complete the training today.', when:'12m ago', unread:true,  priority:'critical' },
  { id:'FT-081', location:'HB009', loc:'Richmond Hill',          operator:'G. Latham',     subject:'NPS coaching plan — barber A. Russell',  lastMsg:'Plan attached. Reviewing with team Friday.',       when:'1h ago',  unread:false, priority:'high' },
  { id:'FT-080', location:'HB002', loc:'Mississauga',         operator:'S. Davidson',     subject:'Q3 growth — second chair request',     lastMsg:'Sending lease docs by EOD.',                       when:'3h ago',  unread:true,  priority:'standard' },
  { id:'FT-079', location:'HB007', loc:'Markham',    operator:'S. Fitzgerald',    subject:'Vendor switch request — Maple Grooming', lastMsg:'Submitting alternative supplier docs.',         when:'5h ago',  unread:false, priority:'standard' },
  { id:'FT-078', location:'HB005', loc:'Hamilton',           operator:'W. Underhill',    subject:'Reopening campaign approval',          lastMsg:'Translation fixed. Resubmitting.',                 when:'1d ago',  unread:false, priority:'standard' },
];

const BROADCASTS = [
  { id:'BC-031', title:'Q3 Brand Standards Update',  audience:'All franchisees', sentAt:'2026-09-08', delivered:10, read:9, ack:7, type:'mandatory' },
  { id:'BC-030', title:'New Father\u2019s Day template available', audience:'All locations', sentAt:'2026-09-05', delivered:10, read:10, ack:10, type:'standard' },
  { id:'BC-029', title:'CASL training reminder',     audience:'4 locations',     sentAt:'2026-09-01', delivered:4, read:3, ack:2, type:'compliance' },
];

const AGREEMENT_COMPLIANCE = [
  { location:'HB010', loc:'Scarborough',      brandStds:62, casl:76, pipeda:92, royaltyPaid:'on time', daysToRenewal: 198, riskLevel:'high', flags:['CASL','PIPEDA','Brand'] },
  { location:'HB009', loc:'Richmond Hill',       brandStds:78, casl:82, pipeda:98, royaltyPaid:'on time', daysToRenewal: 264, riskLevel:'medium', flags:['CASL'] },
  { location:'HB008', loc:'Brampton',     brandStds:84, casl:94, pipeda:96, royaltyPaid:'on time', daysToRenewal: 422, riskLevel:'medium', flags:[] },
  { location:'HB005', loc:'Hamilton',        brandStds:91, casl:98, pipeda:100, royaltyPaid:'on time', daysToRenewal: 312, riskLevel:'low', flags:[] },
];

// Document Vault (gap #6)
const FRANCHISEE_DOCS = {
  'HB010': {
    shop: 'Scarborough',
    operator: 'K. Manderson',
    docs: [
      { type:'Franchise Agreement', name:'HB010 Franchise Agreement.pdf',  expires:'2030-02-15', status:'active', sensitive:true,  uploaded:'2023-02-15' },
      { type:'Agreement Amendment', name:'Amendment #1 — territory revision.pdf', expires:null, status:'active', uploaded:'2024-06-01' },
      { type:'Notice of Default',   name:'§12.3 NoD — CASL violation (May 12, 2026).pdf', expires:null, status:'active', sensitive:true, uploaded:'2026-09-12' },
      { type:'Insurance',           name:'General liability — 2026.pdf',    expires:'2027-01-31', status:'active', uploaded:'2026-01-15' },
      { type:'Insurance',           name:'WCB coverage — 2026.pdf',          expires:'2026-12-31', status:'active', uploaded:'2026-01-15' },
      { type:'Training Cert',       name:'Brand standards 2024.pdf',          expires:'2025-06-01', status:'expired',  uploaded:'2024-06-01' },
      { type:'Training Cert',       name:'CASL certification 2023.pdf',       expires:'2025-04-01', status:'expired', uploaded:'2023-04-01' },
      { type:'Compliance Notice',   name:'CASL violation notice INC-2026-031.pdf', expires:null, status:'active', sensitive:true, uploaded:'2026-09-06' },
      { type:'Inspection',          name:'Brand-standards audit Q1 2026.pdf', expires:null, status:'archived', uploaded:'2026-03-15' },
    ],
  },
  'HB009': {
    shop: 'Richmond Hill',
    operator: 'G. Latham',
    docs: [
      { type:'Franchise Agreement', name:'HB009 Franchise Agreement.pdf',   expires:'2029-08-22', status:'active', sensitive:true, uploaded:'2022-08-22' },
      { type:'Insurance',           name:'General liability — 2026.pdf',     expires:'2026-09-30', status:'active', uploaded:'2025-09-15' },
      { type:'Training Cert',       name:'Brand standards 2025.pdf',           expires:'2026-06-01', status:'expiring', uploaded:'2025-06-01' },
      { type:'Vendor Exception',    name:'Maple Grooming approval.pdf',     expires:null, status:'active', uploaded:'2024-11-04' },
      { type:'Cure Letter',         name:'NPS coaching plan — A. Russell.pdf',  expires:null, status:'active', uploaded:'2026-09-11' },
    ],
  },
  'HB008': {
    shop: 'Brampton',
    operator: 'V. Brennan',
    docs: [
      { type:'Franchise Agreement', name:'HB008 Franchise Agreement.pdf',   expires:'2027-01-15', status:'active',   sensitive:true, uploaded:'2022-01-15' },
      { type:'Renewal Request',     name:'Renewal intent — 2027.pdf',         expires:null, status:'active',         uploaded:'2026-08-01' },
      { type:'Insurance',           name:'General liability — 2026.pdf',     expires:'2026-10-15', status:'active',   uploaded:'2025-10-15' },
    ],
  },
};

// Growth pipeline (gap #7)
const GROWTH_PIPELINE = [
  { id:'GR-024', operator:'S. Davidson',    shop:'Mississauga (HB002)',     kind:'Second chair',           stage:'Approved · build',   capital: 38000, roi: 14, submitted:'2026-08-12', notes:'Lease signed; build May 28–Jun 14.', priority:'high' },
  { id:'GR-023', operator:'I. Manderson',    shop:'Toronto Downtown (HB001)',     kind:'Remodel',                stage:'Approved · funded',  capital: 64000, roi: 22, submitted:'2026-03-04', notes:'Floor + signage refresh. Closed Aug 12.',  priority:'standard' },
  { id:'GR-022', operator:'S. Drummond',     shop:'Burlington (HB004)',      kind:'Territory expansion',    stage:'HQ review',          capital:120000, roi: 28, submitted:'2026-08-22', notes:'Proposes 2nd shop in Coal Harbour.',     priority:'high' },
  { id:'GR-021', operator:'G. Latham',    shop:'Richmond Hill (HB009)',      kind:'Relocation',             stage:'On hold',            capital: 84000, roi: 18, submitted:'2026-08-08', notes:'Blocked pending compliance review.',     priority:'standard' },
  { id:'GR-020', operator:'W. Underhill',   shop:'Hamilton (HB005)',       kind:'Remodel',                stage:'Field Ops scoping',  capital: 42000, roi: 16, submitted:'2026-08-29', notes:'Awaiting site assessment.',              priority:'standard' },
  { id:'GR-CAND-004', operator:'NEW · S. Costa', shop:'Kitchener-Waterloo (TBD)', kind:'New franchise candidate', stage:'Discovery Day',  capital:175000, roi: 30, submitted:'2026-09-02', notes:'Beauty-industry background; SBA pre-approved.', priority:'high' },
];

const GROWTH_STAGES = ['Submitted','HQ review','Discovery Day','Field Ops scoping','Approved · build','Approved · funded','On hold','Declined'];

const FranchiseesPage = ({ onOpenLoc, onOpenCasl }) => {
  const [tab, setTab] = React.useState('operators');
  const [openDoc, setOpenDoc] = React.useState('HB010');
  const [broadcasts, setBroadcasts] = React.useState(BROADCASTS);
  const [bcOpen, setBcOpen] = React.useState(false);
  const [bc, setBc] = React.useState({ title:'', audience:'All franchisees', type:'standard' });
  const setB = (k, v) => setBc(d => ({ ...d, [k]: v }));
  const sendBroadcast = () => {
    if (!bc.title.trim()) { hbToast('Broadcast needs a title', 'Add a title before sending'); return; }
    setBroadcasts(bs => [{ id:'BC-' + String(32 + bs.length - BROADCASTS.length + 0).padStart(3, '0'), title: bc.title.trim(), audience: bc.audience, sentAt:'2026-09-14', delivered: 10, read: 0, ack: 0, type: bc.type }, ...bs]);
    setBcOpen(false);
    setBc(d => ({ ...d, title:'' }));
    setTab('broadcasts');
    hbToast('Broadcast sent', 'Delivered to 10 locations · acknowledgement tracking live');
  };
  return (
  <div className="page">
    <div className="pageheader">
      <div>
        <h1 className="pageheader-title">Franchisee Hub</h1>
        <p className="pageheader-sub">Operator communications, broadcasts, agreement compliance, document vault, and the network growth pipeline.</p>
      </div>
      <div className="pageheader-tools">
        <button className="primary-btn" data-live="1" onClick={() => setBcOpen(true)}><Icon name="plus" size={12} stroke={2.4}/> New broadcast</button>
      </div>
    </div>

    <div className="cat-kpis">
      <div className="cat-kpi cat-kpi-urgent"><div className="cat-kpi-l">Unread from operators <InfoDot tip="Direct messages from franchise operators that you haven't opened yet."/></div><div className="cat-kpi-v">3</div><div className="cat-kpi-sub">1 critical · Scarborough</div></div>
      <div className="cat-kpi"><div className="cat-kpi-l">Active broadcasts <InfoDot tip="One-to-many announcements you've sent to the network in the last 30 days."/></div><div className="cat-kpi-v">3</div><div className="cat-kpi-sub">1 mandatory awaiting ack</div></div>
      <div className="cat-kpi cat-kpi-warn"><div className="cat-kpi-l">Agreement risk <InfoDot tip="Shops at risk of breaching their franchise agreement (compliance violations, brand-standards score below threshold, missed royalty payments)."/></div><div className="cat-kpi-v">1 high · 2 medium</div><div className="cat-kpi-sub">Scarborough 1 violation from §12.3</div></div>
      <div className="cat-kpi"><div className="cat-kpi-l">Document vault <InfoDot tip="Total documents stored across all franchisees. Sensitive items are flagged."/></div><div className="cat-kpi-v">147</div><div className="cat-kpi-sub">3 expiring · 2 expired</div></div>
      <div className="cat-kpi"><div className="cat-kpi-l">Growth pipeline <InfoDot tip="Open expansion / remodel / new-candidate requests across the network."/></div><div className="cat-kpi-v">6 active</div><div className="cat-kpi-sub">2 high priority</div></div>
    </div>

    <div className="cat-tabs">
      {[
        ['operators',  'Operators',     'message',   FRANCHISEE_THREADS.filter(t => t.unread).length],
        ['broadcasts', 'Broadcasts',    'megaphone', 0],
        ['compliance', 'Agreement',     'shield',    AGREEMENT_COMPLIANCE.filter(a => a.riskLevel !== 'low').length],
        ['documents',  'Document vault','box',       0],
        ['growth',     'Growth pipeline','trend',    GROWTH_PIPELINE.filter(g => g.stage === 'HQ review' || g.stage === 'Discovery Day').length],
      ].map(([id, label, icon, count]) => (
        <button key={id} className={'cat-tab' + (tab === id ? ' is-on' : '')} onClick={() => setTab(id)}>
          <Icon name={icon} size={14} stroke={2}/>
          <span>{label}</span>
          {count > 0 && <span className="cat-tab-count">{count}</span>}
        </button>
      ))}
    </div>

    {tab === 'operators' && (
      <section className="card">
        <header className="card-head">
          <div className="card-head-left">
            <Icon name="message" size={16} stroke={2}/>
            <h2>Operator threads</h2>
            <InfoDot tip="Direct conversations with franchise operators. Critical = tied to an open compliance or contract incident."/>
          </div>
          <div className="card-head-right">
            <button className="ghost-btn small">All threads</button>
          </div>
        </header>
        <ul className="thread-list">
          {FRANCHISEE_THREADS.map(t => (
            <li key={t.id} className={'thread-row thread-' + t.priority + (t.unread ? ' is-unread' : '')} onClick={() => { const loc = window.FRANCHISE_DATA.LOCATIONS.find(l => l.id === t.location); if (loc) onOpenLoc(loc); }}>
              <div className="thread-avatar">{t.operator.split(' ').map(s => s[0]).join('')}</div>
              <div className="thread-body">
                <div className="thread-head-row">
                  <span className="thread-operator">{t.operator}</span>
                  <span className="thread-loc">· {t.loc}</span>
                  {t.priority === 'critical' && <span className="thread-tag thread-tag-critical">CRITICAL</span>}
                  {t.priority === 'high' && <span className="thread-tag thread-tag-high">HIGH</span>}
                  <span className="thread-when">{t.when}</span>
                </div>
                <div className="thread-subject">{t.subject}</div>
                <div className="thread-preview">{t.lastMsg}</div>
              </div>
              {t.unread && <div className="thread-unread"/>}
            </li>
          ))}
        </ul>
      </section>
    )}

    {tab === 'broadcasts' && (
      <section className="card">
        <header className="card-head">
          <div className="card-head-left">
            <Icon name="megaphone" size={16} stroke={2}/>
            <h2>Recent broadcasts</h2>
            <InfoDot tip="One-to-many messages from HQ. Mandatory broadcasts require acknowledgement before the operator's dashboard unlocks."/>
          </div>
          <div className="card-head-right">
            <button className="primary-btn" data-live="1" onClick={() => setBcOpen(true)}><Icon name="plus" size={12} stroke={2.4}/> New broadcast</button>
          </div>
        </header>
        <ul className="broadcast-list">
          {broadcasts.map(b => (
            <li key={b.id} className={'broadcast-row broadcast-' + b.type}>
              <div className="broadcast-tag">{b.type === 'mandatory' ? 'MANDATORY' : b.type === 'compliance' ? 'COMPLIANCE' : 'BROADCAST'}</div>
              <div className="broadcast-body">
                <div className="broadcast-title">{b.title}</div>
                <div className="broadcast-meta">{b.audience} · sent {b.sentAt}</div>
                <div className="broadcast-stats">
                  <div className="broadcast-stat"><span>Delivered</span><b>{b.delivered}/10</b></div>
                  <div className="broadcast-stat"><span>Read</span><b>{b.read}/10</b></div>
                  <div className="broadcast-stat"><span>Acknowledged</span><b className={b.ack < b.delivered ? 'is-bad' : 'is-good'}>{b.ack}/10</b></div>
                </div>
              </div>
            </li>
          ))}
        </ul>
      </section>
    )}

    {tab === 'compliance' && (
      <section className="card">
        <header className="card-head">
          <div className="card-head-left">
            <Icon name="shield" size={16} stroke={2}/>
            <h2>Agreement compliance</h2>
            <InfoDot tip="Roll-up of each franchisee's standing against the agreement: brand standards score, CASL/PIPEDA, royalty payment cadence, renewal window."/>
            <span className="card-head-count">{AGREEMENT_COMPLIANCE.length} at-risk shops shown</span>
          </div>
        </header>
        <div className="lb-table-wrap">
          <table className="lb-table cat-table">
            <thead>
              <tr>
                <th>Location</th>
                <th>Risk level</th>
                <th>Brand standards <InfoDot tip="This shop's score against the brand-standards audit checklist."/></th>
                <th>CASL <InfoDot tip="Canadian Anti-Spam Law. % of email sends going only to clients who gave consent."/></th>
                <th>PIPEDA <InfoDot tip="Canadian privacy law. % of client records handled with required consent stamps."/></th>
                <th>Royalty payments <InfoDot tip="Whether the operator is paying royalties on time per the agreement."/></th>
                <th className="num">Days to renewal <InfoDot tip="Days remaining until this shop's franchise agreement comes up for renewal."/></th>
                <th>Open flags</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {AGREEMENT_COMPLIANCE.map(a => (
                <tr key={a.location} onClick={() => { const loc = window.FRANCHISE_DATA.LOCATIONS.find(l => l.id === a.location); if (loc) onOpenLoc(loc); }} className="lb-row">
                  <td><div className="lb-name">{a.loc}</div><div className="lb-sub">{a.location}</div></td>
                  <td>
                    <span className="pill" style={{
                      background: a.riskLevel === 'high' ? '#FEE2E2' : a.riskLevel === 'medium' ? '#FEF3C7' : '#DCFCE7',
                      color:      a.riskLevel === 'high' ? '#B91C1C' : a.riskLevel === 'medium' ? '#92400E' : '#166534',
                    }}>{a.riskLevel.toUpperCase()}</span>
                  </td>
                  <td>
                    <div className="cat-meter">
                      <div className="cat-meter-bar"><div className="cat-meter-fill" style={{ width: a.brandStds + '%', background: a.brandStds >= 85 ? '#16A34A' : a.brandStds >= 70 ? '#F59E0B' : '#EF4444' }}/></div>
                      <span>{a.brandStds}%</span>
                    </div>
                  </td>
                  <td><span className={'nps-chip ' + (a.casl >= 95 ? 'good' : a.casl >= 85 ? 'mid' : 'low')}>{a.casl}%</span></td>
                  <td><span className={'nps-chip ' + (a.pipeda >= 95 ? 'good' : a.pipeda >= 85 ? 'mid' : 'low')}>{a.pipeda}%</span></td>
                  <td><span className="pill" style={{ background:'#DCFCE7', color:'#166534' }}>{a.royaltyPaid}</span></td>
                  <td className="num">{a.daysToRenewal}</td>
                  <td>
                    {a.flags.length === 0 && <span className="muted">—</span>}
                    {a.flags.map(f => <span key={f} className="pill pill-flag" style={{ marginRight: 4 }}>{f}</span>)}
                  </td>
                  <td className="lb-open"><Icon name="arrow-right" size={14} stroke={2}/></td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </section>
    )}

    {tab === 'documents' && (
      <div className="vault-grid">
        <aside className="vault-sidebar">
          {Object.entries(FRANCHISEE_DOCS).map(([id, v]) => (
            <button key={id} className={'vault-shop' + (openDoc === id ? ' is-on' : '')} onClick={() => setOpenDoc(id)}>
              <div className="vault-shop-id">{id}</div>
              <div>
                <div className="vault-shop-name">{v.shop}</div>
                <div className="vault-shop-meta">{v.operator} · {v.docs.length} docs</div>
              </div>
            </button>
          ))}
        </aside>
        <section className="card vault-main">
          {(() => {
            const v = FRANCHISEE_DOCS[openDoc];
            const expiring = v.docs.filter(d => d.status === 'expiring').length;
            const expired = v.docs.filter(d => d.status === 'expired').length;
            const sensitive = v.docs.filter(d => d.sensitive).length;
            return (
              <React.Fragment>
                <header className="card-head">
                  <div className="card-head-left">
                    <Icon name="box" size={16} stroke={2}/>
                    <h2>{v.shop} — Document Vault</h2>
                    <InfoDot tip="Every document HQ holds on this franchisee: agreement, amendments, insurance, training certs, compliance notices, cure letters, inspection reports."/>
                    <span className="card-head-count">{v.docs.length} docs · {sensitive} sensitive · {expiring} expiring · {expired} expired</span>
                  </div>
                  <div className="card-head-right">
                    <button className="ghost-btn small"><Icon name="plus" size={12} stroke={2.4}/> Upload</button>
                    <button className="ghost-btn small">Export all</button>
                  </div>
                </header>
                <div className="lb-table-wrap">
                  <table className="lb-table cat-table">
                    <thead>
                      <tr>
                        <th>Type</th>
                        <th>Document</th>
                        <th>Uploaded</th>
                        <th>Expires</th>
                        <th>Status</th>
                        <th></th>
                      </tr>
                    </thead>
                    <tbody>
                      {v.docs.map((d, i) => (
                        <tr key={i} className="lb-row">
                          <td><span className="pill" style={{ background:'#F1F5F9', color:'#475569' }}>{d.type}</span></td>
                          <td>
                            <div className="lb-name">{d.name}</div>
                            {d.sensitive && <div className="cat-flag">🔒 Sensitive — HQ Legal access only</div>}
                          </td>
                          <td>{d.uploaded}</td>
                          <td>{d.expires || <span className="muted">—</span>}</td>
                          <td>
                            {d.status === 'active'   && <span className="pill pill-live"><span className="pill-dot" style={{ background:'#16A34A' }}/>Active</span>}
                            {d.status === 'expiring' && <span className="pill" style={{ background:'#FEF3C7', color:'#92400E' }}><span className="pill-dot" style={{ background:'#F59E0B' }}/>Expiring</span>}
                            {d.status === 'expired'  && <span className="pill" style={{ background:'#FEE2E2', color:'#B91C1C' }}><span className="pill-dot" style={{ background:'#DC2626' }}/>Expired</span>}
                            {d.status === 'archived' && <span className="pill" style={{ background:'#F1F5F9', color:'#64748B' }}>Archived</span>}
                          </td>
                          <td className="lb-open"><Icon name="arrow-right" size={14} stroke={2}/></td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              </React.Fragment>
            );
          })()}
        </section>
      </div>
    )}

    {tab === 'growth' && (
      <React.Fragment>
        <section className="card">
          <header className="card-head">
            <div className="card-head-left">
              <Icon name="trend" size={16} stroke={2}/>
              <h2>Growth pipeline</h2>
              <InfoDot tip="New shops, second-chair expansions, remodels, relocations, and new-franchisee candidates. Tracks stage, capital, expected ROI, and compliance prerequisites."/>
              <span className="card-head-count">{GROWTH_PIPELINE.length} active</span>
            </div>
            <div className="card-head-right">
              <button className="ghost-btn small">Pipeline funnel</button>
              <button className="primary-btn"><Icon name="plus" size={12} stroke={2.4}/> New request</button>
            </div>
          </header>
          <div className="lb-table-wrap">
            <table className="lb-table cat-table">
              <thead>
                <tr>
                  <th>Request</th>
                  <th>Operator · Shop</th>
                  <th>Kind</th>
                  <th>Stage</th>
                  <th className="num">Capital</th>
                  <th className="num">Est. ROI (mo)</th>
                  <th>Priority</th>
                  <th></th>
                </tr>
              </thead>
              <tbody>
                {GROWTH_PIPELINE.map(g => (
                  <tr key={g.id} className="lb-row">
                    <td>
                      <div className="lb-name">{g.id}</div>
                      <div className="lb-sub">Submitted {g.submitted}</div>
                    </td>
                    <td>
                      <div className="lb-name">{g.operator}</div>
                      <div className="lb-sub">{g.shop}</div>
                    </td>
                    <td><span className="pill" style={{ background:'#E0E7FF', color:'#3730A3' }}>{g.kind}</span></td>
                    <td>
                      <div className="growth-stage">
                        <span>{g.stage}</span>
                        <div className="growth-stage-bar">
                          {GROWTH_STAGES.slice(0,5).map((s, i) => {
                            const idx = GROWTH_STAGES.indexOf(g.stage);
                            const me = i;
                            const on = me <= idx && g.stage !== 'On hold' && g.stage !== 'Declined';
                            return <div key={s} className={'growth-stage-dot' + (on ? ' is-on' : '')}/>;
                          })}
                        </div>
                        <div className="growth-stage-notes">{g.notes}</div>
                      </div>
                    </td>
                    <td className="num">${(g.capital/1000).toFixed(0)}K</td>
                    <td className="num">{g.roi}mo</td>
                    <td>
                      {g.priority === 'high' && <span className="pill" style={{ background:'#FEE2E2', color:'#B91C1C' }}>HIGH</span>}
                      {g.priority === 'standard' && <span className="pill" style={{ background:'#F1F5F9', color:'#475569' }}>STANDARD</span>}
                    </td>
                    <td className="lb-open"><Icon name="arrow-right" size={14} stroke={2}/></td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </section>

        <div className="three-grid">
          <section className="card stub-card">
            <header className="card-head"><div className="card-head-left"><Icon name="trend" size={16} stroke={2}/><h2>By stage</h2></div></header>
            <ul className="bar-list">
              {[['HQ review', 2, '#F59E0B'],['Discovery Day', 1, '#0EA5E9'],['Field Ops scoping', 1, '#A855F7'],['Approved · build', 1, '#16A34A'],['On hold', 1, '#94A3B8']].map(([lbl, n, c]) => (
                <li key={lbl}>
                  <div className="bar-list-head"><div><div className="bar-list-name">{lbl}</div></div><div className="bar-list-val">{n}</div></div>
                  <div className="bar-list-bar"><div className="bar-list-fill" style={{ width: (n/3*100) + '%', background: c }}/></div>
                </li>
              ))}
            </ul>
          </section>
          <section className="card stub-card">
            <header className="card-head"><div className="card-head-left"><Icon name="dollar" size={16} stroke={2}/><h2>Capital required</h2></div></header>
            <ul className="stub-list">
              <li><b>Q2 2026 total</b> · $523K committed pipeline</li>
              <li><b>Approved (funded)</b> · $102K</li>
              <li><b>HQ review</b> · $204K</li>
              <li><b>On hold</b> · $84K (Richmond Hill — pending compliance)</li>
              <li><b>Candidate pipeline</b> · $175K (Kitchener-Waterloo (TBD))</li>
            </ul>
          </section>
          <section className="card stub-card">
            <header className="card-head"><div className="card-head-left"><Icon name="shield" size={16} stroke={2}/><h2>Compliance prerequisites</h2></div></header>
            <ul className="stub-list">
              <li>Richmond Hill relocation <b style={{ color:'#B91C1C' }}>blocked</b> — open CASL flag</li>
              <li>Mississauga expansion <b style={{ color:'#16A34A' }}>clear</b></li>
              <li>Kitchener-Waterloo (TBD) candidate · Discovery Day next</li>
              <li>Auto-checks: brand-standards ≥85%, no open §12.3 flags</li>
            </ul>
          </section>
        </div>
      </React.Fragment>
    )}

    {bcOpen && (
      <HBModal
        title="New broadcast"
        sub="One-to-many announcement to operators. Mandatory broadcasts require acknowledgement."
        onClose={() => setBcOpen(false)}
        footer={<>
          <button className="ghost-btn" onClick={() => setBcOpen(false)}>Cancel</button>
          <button className="primary-btn" onClick={sendBroadcast}><Icon name="megaphone" size={12} stroke={2.4}/> Send broadcast</button>
        </>}
      >
        <HBField label="Title"><input autoFocus placeholder="e.g. Q4 Brand Standards Update" value={bc.title} onChange={e => setB('title', e.target.value)}/></HBField>
        <div className="hb-row-2">
          <HBField label="Audience">
            <select value={bc.audience} onChange={e => setB('audience', e.target.value)}>
              {['All franchisees','All locations','Franchised shops only','Corporate shops only','Flagged locations (2)'].map(o => <option key={o}>{o}</option>)}
            </select>
          </HBField>
          <HBField label="Type">
            <select value={bc.type} onChange={e => setB('type', e.target.value)}>
              <option value="standard">Standard</option>
              <option value="mandatory">Mandatory (requires ack)</option>
              <option value="compliance">Compliance</option>
            </select>
          </HBField>
        </div>
        <HBField label="Message"><textarea placeholder="Write the announcement operators will see…"/></HBField>
      </HBModal>
    )}
  </div>
  );
};

// ═══════════════════════════════════════════════════════════════════════
// CUSTOMER INTELLIGENCE — network-wide customer health
// ═══════════════════════════════════════════════════════════════════════

const CUSTOMER_KPIS = {
  totalCustomers: 38640,
  activeMembers: 15840,
  loyaltyValue: 1240800,
  avgCLV: 412,
  multiShop: 2840,
  churnRate: 6.8,
};

const CHURN_BY_LOC = [
  { loc:'Scarborough',      churn: 18.4, segment:'high' },
  { loc:'Richmond Hill',       churn: 14.2, segment:'high' },
  { loc:'Brampton',     churn: 10.6, segment:'medium' },
  { loc:'Markham', churn:  9.8, segment:'medium' },
  { loc:'Hamilton',        churn:  7.4, segment:'low' },
  { loc:'Vaughan',     churn:  6.8, segment:'low' },
  { loc:'Oakville',churn:  5.4, segment:'low' },
  { loc:'Burlington',       churn:  4.8, segment:'low' },
  { loc:'Mississauga',      churn:  4.2, segment:'low' },
  { loc:'Toronto Downtown',      churn:  3.6, segment:'low' },
];

const CustomersPage = () => {
  const maxChurn = Math.max(...CHURN_BY_LOC.map(c => c.churn));
  return (
    <div className="page">
      <div className="pageheader">
        <div>
          <h1 className="pageheader-title">Customer Intelligence</h1>
          <p className="pageheader-sub">Network-wide view of customer health, lifetime value, loyalty penetration, churn, and cross-shop activity.</p>
        </div>
      </div>

      <div className="cat-kpis">
        <div className="cat-kpi"><div className="cat-kpi-l">Total clients <InfoDot tip="Total unique clients across all 10 shops."/></div><div className="cat-kpi-v">{CUSTOMER_KPIS.totalCustomers.toLocaleString()}</div><div className="cat-kpi-sub">+1,240 this month</div></div>
        <div className="cat-kpi"><div className="cat-kpi-l">Loyalty members <InfoDot tip="Clients currently signed up to the loyalty program."/></div><div className="cat-kpi-v">{CUSTOMER_KPIS.activeMembers.toLocaleString()}</div><div className="cat-kpi-sub">41% penetration</div></div>
        <div className="cat-kpi"><div className="cat-kpi-l">Loyalty sales (YTD) <InfoDot tip="Revenue generated from loyalty members year-to-date."/></div><div className="cat-kpi-v">{fmtMoneyFull(CUSTOMER_KPIS.loyaltyValue)}</div><div className="cat-kpi-sub">YTD generated</div></div>
        <div className="cat-kpi"><div className="cat-kpi-l">Avg client value <InfoDot tip="Average lifetime spend per client — how much each client spends over the time they stay with us."/></div><div className="cat-kpi-v">${CUSTOMER_KPIS.avgCLV}</div><div className="cat-kpi-sub">+8% YoY</div></div>
        <div className="cat-kpi"><div className="cat-kpi-l">Multi-shop clients <InfoDot tip="Clients who've visited 2 or more of your shops. These are your most loyal — the brand, not the chair, is what brings them in."/></div><div className="cat-kpi-v">{CUSTOMER_KPIS.multiShop.toLocaleString()}</div><div className="cat-kpi-sub">Visit 2+ locations</div></div>
        <div className="cat-kpi cat-kpi-warn"><div className="cat-kpi-l">Clients we've lost <InfoDot tip="% of clients who haven't come back in 90+ days. Anything over 10% is a retention problem worth investigating."/></div><div className="cat-kpi-v">{CUSTOMER_KPIS.churnRate}%</div><div className="cat-kpi-sub">2 shops above 10%</div></div>
      </div>

      <div className="three-grid">
        <section className="card">
          <header className="card-head"><div className="card-head-left"><Icon name="warn" size={16} stroke={2}/><h2>Clients lost by shop</h2><InfoDot tip="% of clients per shop who haven't come back in 90 days. Above 10% (red) means that shop is bleeding regulars — worth a retention campaign."/></div></header>
          <ul className="bar-list">
            {CHURN_BY_LOC.map(c => (
              <li key={c.loc}>
                <div className="bar-list-head">
                  <div><div className="bar-list-name">{c.loc}</div><div className="bar-list-sub">{c.segment === 'high' ? 'fix first' : c.segment === 'medium' ? 'keep an eye' : 'healthy'}</div></div>
                  <div className="bar-list-val">{c.churn.toFixed(1)}%</div>
                </div>
                <div className="bar-list-bar"><div className="bar-list-fill" style={{ width: (c.churn/maxChurn*100).toFixed(0) + '%', background: c.churn >= 10 ? '#DC2626' : c.churn >= 7 ? '#F59E0B' : '#16A34A' }}/></div>
              </li>
            ))}
          </ul>
        </section>

        <section className="card stub-card">
          <header className="card-head"><div className="card-head-left"><Icon name="users" size={16} stroke={2}/><h2>Client groups</h2><InfoDot tip="Network-level segmentation. Each segment can drive a targeted brand campaign or a per-location campaign with consistent brand framing."/></div></header>
          <div className="stub-segments">
            <div className="seg-card"><div className="seg-card-l">VIPs (top 5%)</div><div className="seg-card-v">1,932</div><div className="seg-card-sub">{fmtMoneyFull(842000)} LTV · spend 8× avg</div></div>
            <div className="seg-card"><div className="seg-card-l">Regulars</div><div className="seg-card-v">11,460</div><div className="seg-card-sub">3+ visits in the last 90 days</div></div>
            <div className="seg-card"><div className="seg-card-l">Drifting away</div><div className="seg-card-v">3,248</div><div className="seg-card-sub">60–180d since last visit · win-back target</div></div>
            <div className="seg-card"><div className="seg-card-l">New (last 30d)</div><div className="seg-card-v">1,240</div><div className="seg-card-sub">First visit · onboarding flow</div></div>
            <div className="seg-card"><div className="seg-card-l">Brand champions</div><div className="seg-card-v">820</div><div className="seg-card-sub">Visit 3+ shops · your strongest advocates</div></div>
          </div>
        </section>

        <section className="card stub-card">
          <header className="card-head"><div className="card-head-left"><Icon name="gift" size={16} stroke={2}/><h2>Loyalty roll-up</h2><InfoDot tip="Aggregate of every shop's loyalty program. Points-to-revenue ratio tracks the program's marginal cost vs revenue lift."/></div></header>
          <div className="stub-loyalty">
            <div className="loyalty-stat"><div>Points issued (MTD)</div><b>1.6M</b></div>
            <div className="loyalty-stat"><div>Points redeemed</div><b>443K · 28%</b></div>
            <div className="loyalty-stat"><div>Redemption revenue</div><b>{fmtMoneyFull(77120)}</b></div>
            <div className="loyalty-stat"><div>Active members</div><b>15,840</b></div>
            <div className="loyalty-stat"><div>Tier distribution</div><b>Silver 62% · Gold 28% · Platinum 10%</b></div>
            <div className="loyalty-stat"><div>Highest-redemption location</div><b>Toronto Downtown · 184/mo</b></div>
          </div>
        </section>
      </div>
    </div>
  );
};

// ═══════════════════════════════════════════════════════════════════════
// NETWORK REPORTS — moved to page-reports.jsx
// ═══════════════════════════════════════════════════════════════════════
// (The full Reports & Insights page now lives in page-reports.jsx — keep
//  this comment so the file ordering / cross-references stay obvious.)

// ═══════════════════════════════════════════════════════════════════════
// TALENT NETWORK — cross-shop staff performance
// ═══════════════════════════════════════════════════════════════════════

const TOP_TALENT = [
  { name:'Kai Ricci',      loc:'Toronto Downtown',      role:'Senior Barber', util: 84, revPerHr: 78, nps: 84, rebook: 82, tenure: '4yr 2mo', flag:'top' },
  { name:'Mei Gonzalez',   loc:'Mississauga',      role:'Master Stylist', util: 81, revPerHr: 74, nps: 81, rebook: 78, tenure: '3yr 8mo', flag:'top' },
  { name:'Maya Morozov',   loc:'Oakville',role:'Senior Barber', util: 79, revPerHr: 72, nps: 78, rebook: 76, tenure: '3yr 1mo', flag:'top' },
  { name:'Imogen Manderson',loc:'Burlington',      role:'Master Stylist', util: 77, revPerHr: 71, nps: 76, rebook: 74, tenure: '2yr 9mo', flag:'top' },
  { name:'Evan Evans',     loc:'Hamilton',        role:'Senior Barber', util: 74, revPerHr: 68, nps: 74, rebook: 72, tenure: '2yr 4mo' },
];

const TeamPage = () => (
  <div className="page">
    <div className="pageheader">
      <div>
        <h1 className="pageheader-title">Talent Network</h1>
        <p className="pageheader-sub">Top performers across all 10 shops, payroll roll-up, training completion, and cross-shop talent mobility.</p>
      </div>
    </div>

    <div className="cat-kpis">
      <div className="cat-kpi"><div className="cat-kpi-l">Total team <InfoDot tip="Active team members across all 10 shops."/></div><div className="cat-kpi-v">112</div><div className="cat-kpi-sub">98 barbers · 14 front-of-house</div></div>
      <div className="cat-kpi"><div className="cat-kpi-l">Avg chair time used <InfoDot tip="Across the network, what % of available chair-hours are actually booked. Target 75%."/></div><div className="cat-kpi-v">71.4%</div><div className="cat-kpi-sub">Target 75%</div></div>
      <div className="cat-kpi"><div className="cat-kpi-l">Payroll (this month) <InfoDot tip="Total wages + commissions + tips paid out across the network, month-to-date."/></div><div className="cat-kpi-v">$284K</div><div className="cat-kpi-sub">35% of net sales</div></div>
      <div className="cat-kpi cat-kpi-warn"><div className="cat-kpi-l">Open roles to fill <InfoDot tip="Job openings posted across the network and not yet filled."/></div><div className="cat-kpi-v">7</div><div className="cat-kpi-sub">3 critical (Scarborough, Richmond Hill, Brampton)</div></div>
      <div className="cat-kpi"><div className="cat-kpi-l">Training completion <InfoDot tip="% of staff who've finished the latest brand-standards training module."/></div><div className="cat-kpi-v">86%</div><div className="cat-kpi-sub">Brand standards module</div></div>
    </div>

    <section className="card">
      <header className="card-head">
        <div className="card-head-left">
          <Icon name="star" size={16} stroke={2}/>
          <h2>Top performers — network</h2>
          <InfoDot tip="Top barbers across the network by revenue/hour + NPS + rebook rate. Identifies talent for mentoring and cross-shop coaching."/>
          <span className="card-head-count">Top 5 of 98</span>
        </div>
      </header>
      <div className="lb-table-wrap">
        <table className="lb-table cat-table">
          <thead><tr><th>Name</th><th>Role</th><th>Location</th><th className="num">Chair time % <InfoDot tip="Booked chair-hours ÷ available chair-hours. Higher means a busier barber."/></th><th className="num">$ / hr <InfoDot tip="Service revenue this barber generates per booked chair-hour."/></th><th className="num">Client score <InfoDot tip="Net Promoter Score — how clients rate the experience after a visit. 70+ is excellent."/></th><th className="num">Rebook rate <InfoDot tip="% of clients who book another visit with this barber after their appointment."/></th><th>Tenure</th><th></th></tr></thead>
          <tbody>
            {TOP_TALENT.map((t, i) => (
              <tr key={t.name} className="lb-row">
                <td>
                  <div className="lb-name">
                    {i < 3 && <span className="cat-medal">{['🥇','🥈','🥉'][i]}</span>}
                    {t.name}
                  </div>
                </td>
                <td>{t.role}</td>
                <td>{t.loc}</td>
                <td className="num">{t.util}%</td>
                <td className="num">${t.revPerHr}</td>
                <td className="num"><span className={'nps-chip ' + (t.nps >= 70 ? 'good' : 'mid')}>{t.nps}</span></td>
                <td className="num">{t.rebook}%</td>
                <td>{t.tenure}</td>
                <td className="lb-open"><Icon name="arrow-right" size={14} stroke={2}/></td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </section>

    <div className="three-grid">
      <section className="card stub-card">
        <header className="card-head"><div className="card-head-left"><Icon name="warn" size={16} stroke={2}/><h2>Open requisitions</h2></div></header>
        <ul className="stub-list">
          <li><b>Senior Barber</b> · Scarborough · 22d open · 4 applicants</li>
          <li><b>Front of House</b> · Richmond Hill · 14d open · 2 applicants</li>
          <li><b>Master Stylist</b> · Brampton · 9d open · 1 applicant</li>
          <li><b>Junior Barber</b> · Hamilton · 4d open · 7 applicants</li>
        </ul>
      </section>
      <section className="card stub-card">
        <header className="card-head"><div className="card-head-left"><Icon name="check" size={16} stroke={2}/><h2>Training completion</h2></div></header>
        <ul className="stub-list">
          <li>Brand standards · <b>86%</b> · 2 shops below 75%</li>
          <li>CASL compliance · <b>71%</b> · Scarborough & Richmond Hill re-cert required</li>
          <li>POS / new menu · <b>94%</b> · Healthy</li>
          <li>Customer service · <b>89%</b> · On track</li>
        </ul>
      </section>
      <section className="card stub-card">
        <header className="card-head"><div className="card-head-left"><Icon name="users" size={16} stroke={2}/><h2>Cross-shop opportunities</h2></div></header>
        <ul className="stub-list">
          <li><b>Mentorship match</b> · Kai R. (Toronto Downtown) → Scarborough barbers</li>
          <li><b>Coaching detail</b> · Mei G. (Mississauga) → Richmond Hill, 1 week</li>
          <li><b>Open transfer</b> · 2 applicants Markham → Vaughan</li>
        </ul>
      </section>
    </div>
  </div>
);

// ═══════════════════════════════════════════════════════════════════════
// AI INSIGHTS — network-level intelligence
// ═══════════════════════════════════════════════════════════════════════

const AI_INSIGHTS = [
  {
    kind:'risk',
    title:'Scarborough — pattern matches prior high-risk franchisee cases',
    detail:'Two open compliance flags, 30+ days of underperformance, declining NPS. Pattern resembles 4 of 4 franchisee cases that ultimately moved to formal HQ review.',
    confidence: 0.91,
    action:'Recommend HQ review',
    icon:'warn',
    tone:'red',
    evidence: [
      'CASL incident INC-2026-031 (Aug 18) — 12 non-consenting recipients',
      'NPS dropped 12pts week-over-week (3 detractor reviews cite same provider)',
      'Revenue trailing network by 28% for 4 consecutive weeks',
      'Brand-standards audit score 62% (below 70% threshold)',
    ],
    basis: 'Trained on 4 prior franchisee escalations (2022–2025). 4/4 had ≥2 compliance flags and ≥30 days of compounding underperformance before HQ intervened.',
    legal: 'Recommendation only. Final review and any contract action requires HQ Legal + Compliance sign-off per franchise agreement §12.3 (cure-period rights preserved).',
    requiresHumanReview: true,
  },
  {
    kind:'opportunity',
    title:'Loyalty program is leaking $34K/month',
    detail:'7 shops have redemption rates above 35%; 3 shops below 15%. Aligning the 3 low shops to network avg unlocks ~$34K/mo in repeat revenue and lifts cross-shop visits.',
    confidence: 0.84,
    action:'Run uplift simulation',
    icon:'gift',
    tone:'green',
    evidence: [
      'Scarborough: 8% redemption (vs 38% network avg)',
      'Richmond Hill: 12% redemption',
      'Markham: 14% redemption',
      'Modeled lift assumes parity with the 25th-percentile shop',
    ],
    basis: 'Simulated against the last 90 days of loyalty-member visit-frequency data.',
  },
  {
    kind:'opportunity',
    title:'Spring Refresh template ready for SMS port',
    detail:'Current Spring Refresh (Email) is the network\'s top performer at 38% open. Porting to SMS for the 4 shops with high SMS-consent rates could lift Q2 net sales by an estimated $42K.',
    confidence: 0.78,
    action:'Build SMS variant',
    icon:'megaphone',
    tone:'blue',
    evidence: [
      'Email open rate 38% — 1.6× network avg',
      '4 shops have >85% SMS consent (Toronto Downtown, Mississauga, Oakville, Burlington)',
      'Modeled lift uses observed SMS-vs-email response from Father\'s Day Combo',
    ],
    basis: 'Channel-port modeling on observed Father\'s Day Combo SMS performance.',
  },
  {
    kind:'risk',
    title:'Vendor concentration risk — Northbridge',
    detail:'Northbridge Beauty Wholesale serves 10 of 10 shops; supplies 6 of top 10 SKUs. Single-vendor risk is high. SLA recent miss on Beard Balm already cost ~$8K.',
    confidence: 0.86,
    action:'Open vendor diversification',
    icon:'box',
    tone:'amber',
    evidence: [
      '10 of 10 shops sourced from Northbridge',
      '6 of top 10 SKUs by revenue',
      '14-day cover SLA missed May 8 — affected 4 shops',
      'Estimated $8K cost from stockouts',
    ],
    basis: 'Single-vendor risk score = adoption × SKU concentration × recent SLA performance.',
  },
  {
    kind:'opportunity',
    title:'Father\u2019s Day Combo upsell window',
    detail:'Last year\'s "Wash, Cut & Style" delivered 4.7% incremental revenue. Currently active at only 4 of 10 shops. Push template at network level for 2026.',
    confidence: 0.81,
    action:'Push template to all shops',
    icon:'sparkle',
    tone:'blue',
    evidence: [
      '2025 lift: +4.7% incremental revenue at participating shops',
      '4 of 10 shops have the template enabled for 2026',
      '6 shops eligible (kids-services menu present)',
    ],
    basis: '2025 same-campaign retrospective.',
  },
];

const AIPage = ({ onOpenLoc, onOpenCasl }) => (
  <div className="page">
    <div className="pageheader">
      <div>
        <h1 className="pageheader-title">AI Insights</h1>
        <p className="pageheader-sub">Network-level intelligence — risks, opportunities, and recommended actions ranked by impact and confidence.</p>
      </div>
      <div className="pageheader-tools">
        <div className="seg-group small">
          {['All','Risks','Opportunities','Compliance','Financial'].map(s => (
            <button key={s} className={'seg' + (s === 'All' ? ' is-on' : '')}>{s}</button>
          ))}
        </div>
      </div>
    </div>

    <div className="ai-insights">
      {AI_INSIGHTS.map((a, i) => (
        <article key={i} className={'ai-card ai-' + a.tone}>
          <div className="ai-card-head">
            <div className="ai-card-icon" style={{ color: a.tone === 'red' ? '#DC2626' : a.tone === 'amber' ? '#B45309' : a.tone === 'green' ? '#16A34A' : '#1E40AF' }}><Icon name={a.icon} size={20} stroke={2}/></div>
            <div>
              <div className="ai-card-kind">{a.kind === 'risk' ? 'RISK' : 'OPPORTUNITY'}{a.requiresHumanReview && <span className="ai-human-pill">REQUIRES HUMAN REVIEW</span>}</div>
              <div className="ai-card-title">{a.title}</div>
            </div>
            <div className="ai-card-conf">
              <div className="ai-conf-bar"><div className="ai-conf-fill" style={{ width: (a.confidence*100) + '%' }}/></div>
              <span>{(a.confidence*100).toFixed(0)}% confidence</span>
            </div>
          </div>
          <p className="ai-card-detail">{a.detail}</p>
          {a.evidence && (
            <div className="ai-evidence">
              <div className="ai-evidence-label">Supporting evidence</div>
              <ul>{a.evidence.map((e, j) => <li key={j}>{e}</li>)}</ul>
            </div>
          )}
          {a.basis && (
            <div className="ai-basis">
              <span className="ai-basis-label">Historical basis</span>
              <span className="ai-basis-text">{a.basis}</span>
            </div>
          )}
          {a.legal && (
            <div className="ai-legal">
              <Icon name="shield" size={12} stroke={2.2}/> {a.legal}
            </div>
          )}
          <div className="ai-card-foot">
            <button className="primary-btn">{a.action} <Icon name="arrow-right" size={12} stroke={2.2}/></button>
            <button className="ghost-btn small">Convert to task</button>
            <button className="ghost-btn small">Dismiss (logged)</button>
            <button className="ghost-btn small">Why this?</button>
          </div>
        </article>
      ))}
    </div>
  </div>
);

// ═══════════════════════════════════════════════════════════════════════
// FRANCHISE SETTINGS — brand standards, RBAC, agreement parameters
// ═══════════════════════════════════════════════════════════════════════

const SettingsPage = () => (
  <div className="page">
    <div className="pageheader">
      <div>
        <h1 className="pageheader-title">Franchise Settings</h1>
        <p className="pageheader-sub">Brand standards, agreement parameters, role-based access controls, and approval thresholds.</p>
      </div>
    </div>

    <div className="settings-grid">
      {[
        { icon:'shield', title:'Brand Standards', items:[
          ['Service menu', '32 services · 24 locked at brand price'],
          ['Price drift threshold', '±5% before flag · ±10% before lock'],
          ['Visual identity assets', 'Logo · color · tone · 18 templates'],
          ['Required POS modules', '4 enabled brand-wide'],
        ]},
        { icon:'dollar', title:'Royalty & Fees', items:[
          ['Royalty rate (default)', '6.5% of net sales'],
          ['Per-franchisee overrides', '3 active overrides'],
          ['Marketing fund contribution', '2% of net sales'],
          ['Late payment penalty', '1.5% / month after 14d'],
        ]},
        { icon:'users', title:'Role-Based Access', items:[
          ['HQ roles', 'Franchise Owner · Regional · Brand Auditor · Compliance'],
          ['Operator roles', 'Franchisee · GM · Front Desk · Provider'],
          ['Pending invitations', '2 awaiting acceptance'],
          ['Audit log retention', '7 years'],
        ]},
        { icon:'warn', title:'Approval Thresholds', items:[
          ['PO approval over', '$1,500'],
          ['Campaign requires HQ', 'Email > 500 recipients · all SMS'],
          ['Vendor onboarding', 'HQ approval required'],
          ['Service price change', 'HQ approval required for locked items'],
        ]},
        { icon:'message', title:'Communications', items:[
          ['Email-from address', 'hq@groomelite.com'],
          ['Operator-app deep links', 'Enabled'],
          ['Slack integration', 'Not connected'],
          ['Weekly executive digest', 'Mondays 7am · Owner + Regional'],
        ]},
        { icon:'gear', title:'Integrations', items:[
          ['Stripe (royalty collection)', 'Connected'],
          ['Google Business Profiles', '10 / 10 connected'],
          ['Meta Business', '8 / 10 connected'],
          ['Accounting (QuickBooks)', 'Connected · corporate only'],
        ]},
      ].map(s => (
        <section key={s.title} className="card settings-card">
          <header className="card-head">
            <div className="card-head-left">
              <Icon name={s.icon} size={16} stroke={2}/>
              <h2>{s.title}</h2>
            </div>
            <button className="ghost-btn small">Edit</button>
          </header>
          <ul className="settings-list">
            {s.items.map(([k, v]) => (
              <li key={k}><span>{k}</span><b>{v}</b></li>
            ))}
          </ul>
        </section>
      ))}
    </div>
  </div>
);

Object.assign(window, { FranchiseesPage, CustomersPage, TeamPage, AIPage, SettingsPage });
