// OS Builder — Phases 7 through 12.

/* ============================================================
   PHASE 7 — COMPLIANCE & RISK
   ============================================================ */
function OSPhase7({ state, set }) {
  const comp = state.compliance || {};
  const u = (cat, item, v) => set('compliance', { ...comp, [`${cat}|${item}`]: v });

  const totalActive = Object.values(comp).filter(Boolean).length;

  return (
    <>
      <OSSection num="7.0" kicker="The infrastructure that prevents shutdowns" title="One expired policy can shut down a job site." sub="Track every license, certificate, insurance policy, and credential. Alerts fire at 90 / 60 / 30 days — never miss a renewal.">
        <div style={{ display:'grid', gridTemplateColumns:'repeat(3,1fr)', gap:10, padding:'14px 16px', background:'var(--lilac-100)', borderRadius:14, color:'var(--lilac-800)' }}>
          <Mini2 label="Active trackers" value={totalActive} tone="lilac"/>
          <Mini2 label="Alert cadence" value="90 · 60 · 30" tone="lilac"/>
          <Mini2 label="Audit-ready" value={totalActive > 15 ? 'Yes' : 'Building'} tone="lilac"/>
        </div>
      </OSSection>

      {COMPLIANCE_ITEMS.map(group => (
        <OSSection key={group.cat} kicker={group.cat} title={group.cat + '.'}>
          <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:8 }}>
            {group.items.map(item => {
              const key = `${group.cat}|${item}`;
              return (
                <OSToggleRow key={item} title={item} value={!!comp[key]} onChange={v=>u(group.cat, item, v)} tone="lilac"/>
              );
            })}
          </div>
        </OSSection>
      ))}

      <OSSection num="7.6" kicker="Continuity plan" title="What happens if something happens to you?">
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:14 }}>
          <OSField label="Backup operator · runs the business" value={state.contin?.backup} onChange={v=>set('contin',{ ...(state.contin||{}), backup:v })} placeholder="Name"/>
          <OSField label="Bank signing authority · secondary" value={state.contin?.bank} onChange={v=>set('contin',{ ...(state.contin||{}), bank:v })} placeholder="Name"/>
          <OSField label="Where critical credentials are stored" value={state.contin?.vault} onChange={v=>set('contin',{ ...(state.contin||{}), vault:v })} placeholder="HomePro Vault · 1Password · etc"/>
          <OSField label="Emergency contact · attorney or CPA" value={state.contin?.legal} onChange={v=>set('contin',{ ...(state.contin||{}), legal:v })} placeholder="Name · firm · number"/>
        </div>
      </OSSection>
    </>
  );
}

function Mini2({ label, value, tone='lilac' }) {
  return (
    <div>
      <div style={{ fontSize:10, fontWeight:700, letterSpacing:'0.12em', textTransform:'uppercase', opacity:0.7 }}>{label}</div>
      <div style={{ fontFamily:'var(--font-display)', fontSize:22, fontWeight:500, marginTop:3, letterSpacing:'-0.02em' }}>{value}</div>
    </div>
  );
}

/* ============================================================
   PHASE 8 — TEAM & PERMISSIONS
   ============================================================ */
function OSPhase8({ state, set }) {
  const team = state.team || [];
  const perms = state.perms || {};
  const addMember = () => set('team', [...team, { id:'m'+Date.now(), name:'', role:'tech', email:'' }]);
  const updateMember = (id, patch) => set('team', team.map(m => m.id === id ? { ...m, ...patch } : m));
  const removeMember = (id) => set('team', team.filter(m => m.id !== id));

  // Default a few rows
  React.useEffect(() => {
    if (!state.team) set('team', [
      { id:'m1', name:'You', role:'owner', email:'' },
      { id:'m2', name:'', role:'office', email:'' },
      { id:'m3', name:'', role:'lead', email:'' },
    ]);
    // eslint-disable-next-line
  }, []);

  const setPerm = (role, feature, level) => {
    const key = `${role}|${feature}`;
    set('perms', { ...perms, [key]: level });
  };
  const getPerm = (role, feature) => perms[`${role}|${feature}`] ?? defaultPerm(role, feature);

  return (
    <>
      <OSSection num="8.1" kicker="Roster" title="Who's on the team?">
        <div style={{ display:'grid', gap:8 }}>
          {team.map(m => (
            <div key={m.id} style={{ display:'grid', gridTemplateColumns:'1fr 180px 1fr 40px', gap:10, alignItems:'center', padding:'10px 12px', background:'var(--paper)', border:'1px solid var(--line)', borderRadius:10 }}>
              <input value={m.name} onChange={e=>updateMember(m.id,{ name:e.target.value })} placeholder="Name" style={inputBare}/>
              <select value={m.role} onChange={e=>updateMember(m.id,{ role:e.target.value })} style={{ ...inputBare, paddingRight:30, cursor:'pointer' }}>
                {ROLES.map(r => <option key={r.id} value={r.id}>{r.name}</option>)}
              </select>
              <input value={m.email} onChange={e=>updateMember(m.id,{ email:e.target.value })} placeholder="email@" style={inputBare}/>
              <button type="button" onClick={()=>removeMember(m.id)} style={{ background:'transparent', border:0, color:'var(--mute-2)', cursor:'pointer', fontSize:16 }}>✕</button>
            </div>
          ))}
        </div>
        <button type="button" onClick={addMember} style={{ ...btnTinyGhost, marginTop:10 }}>+ Add team member</button>
      </OSSection>

      <OSSection num="8.2" kicker="Permission matrix" title="Who sees what, who can do what." sub="Three states per cell: full access, view-only, no access. Click to cycle.">
        <div style={{ overflowX:'auto', border:'1px solid var(--line)', borderRadius:12 }}>
          <table style={{ width:'100%', borderCollapse:'collapse', fontSize:12 }}>
            <thead>
              <tr>
                <th style={thStyle}>Feature</th>
                {['owner','gm','office','lead','tech','book'].map(r => (
                  <th key={r} style={{ ...thStyle, textAlign:'center', minWidth:80 }}>
                    {ROLES.find(x => x.id === r)?.name}
                  </th>
                ))}
              </tr>
            </thead>
            <tbody>
              {PERM_FEATURES.map((f, i) => (
                <tr key={f} style={{ background: i%2 ? 'var(--paper-3)' : 'var(--paper)' }}>
                  <td style={{ ...tdStyle, fontWeight:500 }}>{f}</td>
                  {['owner','gm','office','lead','tech','book'].map(r => {
                    const lvl = getPerm(r, f);
                    const tone = lvl === 'full' ? { bg:'var(--chart-300)', dot:'var(--chart-700)' } :
                                 lvl === 'view' ? { bg:'var(--lilac-200)', dot:'var(--lilac-700)' } :
                                                  { bg:'var(--paper-3)', dot:'var(--mute-2)' };
                    const next = lvl === 'full' ? 'view' : lvl === 'view' ? 'none' : 'full';
                    return (
                      <td key={r} style={{ ...tdStyle, textAlign:'center', padding:'4px' }}>
                        <button onClick={()=>setPerm(r,f,next)} type="button" style={{
                          width:32, height:24, borderRadius:6, border:0, cursor:'pointer',
                          background: tone.bg, color: tone.dot, fontSize:10, fontWeight:700,
                        }}>{lvl === 'full' ? '●' : lvl === 'view' ? '◐' : '○'}</button>
                      </td>
                    );
                  })}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
        <div style={{ display:'flex', gap:14, marginTop:10, fontSize:11.5, color:'var(--mute-1)' }}>
          <span><span style={{ color:'var(--chart-700)' }}>●</span> Full access</span>
          <span><span style={{ color:'var(--lilac-700)' }}>◐</span> View only</span>
          <span><span style={{ color:'var(--mute-2)' }}>○</span> No access</span>
        </div>
      </OSSection>

      <OSSection num="8.5" kicker="Alert routing" title="Who gets pinged for what.">
        <div style={{ display:'grid', gap:8 }}>
          {[
            ['Cash flow warnings','Owner only'],
            ['Schedule changes','Dispatcher + Office'],
            ['Customer complaints','Office + Owner'],
            ['New reviews','Office + Marketing'],
            ['Permit / inspection dates','Office + Project Manager'],
            ['Tech certification expiring','Office Manager + HR'],
            ['Anomaly detection','Owner only'],
            ['Estimate signed over $10K','Owner + Sales lead'],
          ].map(([what, who]) => (
            <div key={what} style={{ display:'grid', gridTemplateColumns:'1fr auto', alignItems:'center', padding:'12px 14px', background:'var(--paper)', border:'1px solid var(--line)', borderRadius:10, gap:14 }}>
              <span style={{ fontSize:13.5, color:'var(--ink)' }}>{what}</span>
              <span style={{ fontFamily:'var(--font-mono)', fontSize:11.5, color:'var(--lilac-700)', background:'var(--lilac-100)', padding:'3px 10px', borderRadius:99, fontWeight:600 }}>{who}</span>
            </div>
          ))}
        </div>
      </OSSection>
    </>
  );
}

function defaultPerm(role, feature) {
  if (role === 'owner') return 'full';
  if (role === 'gm') return 'full';
  if (role === 'office') return ['Edit pricing & margin','View business valuation','Edit team & permissions'].includes(feature) ? 'view' : 'full';
  if (role === 'book') return ['See financial dashboards','Run reports & export','View business valuation'].includes(feature) ? 'full' : 'view';
  return 'none';
}

const inputBare = { width:'100%', padding:'8px 10px', border:'1px solid var(--line-2)', borderRadius:8, fontFamily:'var(--font-body)', fontSize:13, outline:'none', background:'var(--paper-2)', color:'var(--ink)' };
const thStyle = { padding:'10px 14px', textAlign:'left', background:'var(--ink)', color:'var(--chart-300)', fontSize:10, letterSpacing:'0.1em', textTransform:'uppercase', fontWeight:700, fontFamily:'var(--font-mono)' };
const tdStyle = { padding:'10px 14px', borderTop:'1px solid var(--line-2)' };

/* ============================================================
   PHASE 9 — GROWTH & MARKETING
   ============================================================ */
function OSPhase9({ state, set }) {
  const g = state.growth || {};
  const u = (patch) => set('growth', { ...g, ...patch });

  return (
    <>
      <OSSection num="9.1" kicker="Brand voice" title="How HomePro talks on your behalf.">
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:14 }}>
          <OSField label="Brand name" value={g.brand} onChange={v=>u({ brand:v })} placeholder="Chapman's A/C & Heating"/>
          <OSField label="Tagline" value={g.tag} onChange={v=>u({ tag:v })} placeholder="Comfort done right since 1998"/>
        </div>
        <div style={{ marginTop:14 }}>
          <div style={{ fontSize:12, fontWeight:600, color:'var(--mute-1)', textTransform:'uppercase', letterSpacing:'0.08em', marginBottom:8 }}>Tone</div>
          <OSCardPicker tone="lilac" cols={4} items={[
            { id:'pro',   label:'Professional & formal' },
            { id:'warm',  label:'Friendly & warm' },
            { id:'bold',  label:'Bold & confident' },
            { id:'plain', label:'Plain & direct' },
          ]} value={g.tone} onChange={v=>u({ tone:v })} minH={60}/>
        </div>
        <div style={{ marginTop:14 }}>
          <OSField label="Sample message · write it in your own voice" value={g.sample} onChange={v=>u({ sample:v })} placeholder="Hey Sarah — your AC tune-up is on the calendar Tuesday at 9. Reply STOP to cancel."/>
        </div>
      </OSSection>

      <OSSection num="9.2" kicker="Lead sources" title="Where leads actually come from.">
        <div style={{ display:'grid', gridTemplateColumns:'repeat(4,1fr)', gap:8 }}>
          {['Google organic','Google Ads','Local Service Ads','Meta Ads','Angi','HomeAdvisor','Thumbtack','Nextdoor','Yard sign','Door hanger','Truck wrap','Customer referral','Partner referral','Real-estate agent','Home inspector','Repeat customer'].map(s => {
            const active = (g.sources || []).includes(s);
            return (
              <button key={s} type="button" onClick={()=>u({ sources: active ? g.sources.filter(x => x !== s) : [...(g.sources||[]), s] })} style={{
                textAlign:'left', padding:'9px 12px',
                background: active ? 'var(--chart-100)' : 'var(--paper)',
                color: active ? 'var(--chart-900)' : 'var(--ink)',
                border:'1px solid', borderColor: active ? 'var(--chart-500)' : 'var(--line)',
                borderRadius:9, fontSize:12.5, fontWeight: active ? 600 : 500, cursor:'pointer', fontFamily:'var(--font-body)',
              }}>{active && '✓ '}{s}</button>
            );
          })}
        </div>
      </OSSection>

      <OSSection num="9.3" kicker="Customer segments" title="Who you market to — and how differently.">
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:8 }}>
          {[
            ['New homeowners','First-job-in-the-house outreach'],
            ['Long-term loyal','Annual recognition + early access'],
            ['High-value commercial','Account-rep treatment'],
            ['Home warranty','Capped pricing + admin flow'],
            ['Maintenance agreement holders','Recurring touchpoints'],
            ['Lapsed 18+ months','Reactivation engine target'],
          ].map(([s, desc]) => (
            <OSToggleRow key={s} title={s} desc={desc} value={!!g.segments?.[s]} onChange={v=>u({ segments: { ...(g.segments||{}), [s]:v } })} tone="lilac"/>
          ))}
        </div>
      </OSSection>

      <OSSection num="9.4" kicker="12-month campaign calendar" title="Plan the year. Run automatically." sub="One row per month. We pre-populate based on your trade — you tune from there.">
        <div style={{ display:'grid', gap:6 }}>
          {[
            ['Jan','Post-holiday tune-up push','Maintenance'],
            ['Feb','Heating system check-up','Service'],
            ['Mar','Spring AC inspection sale','Install pre-season'],
            ['Apr','Pre-summer install push','Install'],
            ['May','Peak season — referral activation','Growth'],
            ['Jun','Mid-season maintenance reminders','Service'],
            ['Jul','Peak season — review velocity push','Reputation'],
            ['Aug','Back-to-school comfort campaign','Service'],
            ['Sep','Fall heating prep','Install pre-season'],
            ['Oct','Winter prep + maintenance agreements','Recurring'],
            ['Nov','Holiday prep + referrals','Growth'],
            ['Dec','Year-end recap + 2027 planning','Owner'],
          ].map(([mo, name, type]) => (
            <div key={mo} style={{ display:'grid', gridTemplateColumns:'60px 1fr 130px 60px', alignItems:'center', gap:10, padding:'10px 14px', background:'var(--paper)', border:'1px solid var(--line)', borderRadius:10 }}>
              <span style={{ fontFamily:'var(--font-mono)', fontSize:12, fontWeight:700, color:'var(--lilac-700)' }}>{mo}</span>
              <span style={{ fontSize:13, color:'var(--ink)' }}>{name}</span>
              <span style={{ fontSize:11, color:'var(--mute-1)', fontFamily:'var(--font-mono)' }}>{type}</span>
              <OSSwitch value={!!g.cal?.[mo]} onChange={v=>u({ cal: { ...(g.cal||{}), [mo]:v } })} tone="chart"/>
            </div>
          ))}
        </div>
      </OSSection>

      <OSSection num="9.5" kicker="Referral program" title="Built once · runs forever.">
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:14 }}>
          <OSField label="Reward for the referrer" value={g.refReferrer} onChange={v=>u({ refReferrer:v })} placeholder="$75 credit on next service"/>
          <OSField label="Reward for the new customer" value={g.refNew} onChange={v=>u({ refNew:v })} placeholder="$25 off first job"/>
        </div>
      </OSSection>

      <OSSection num="9.6" kicker="Review strategy" title="Get more 5-stars without asking.">
        <div style={{ display:'grid', gap:10 }}>
          <OSToggleRow title="Auto-request after every service call" desc="2 hours after a quick job, 48 hours after a big install" value={!!g.rev?.auto} onChange={v=>u({ rev: { ...(g.rev||{}), auto:v } })} tone="chart"/>
          <OSToggleRow title="Negative experience catch" desc="Flag low-NPS surveys before they post publicly" value={!!g.rev?.neg} onChange={v=>u({ rev: { ...(g.rev||{}), neg:v } })} tone="chart"/>
          <OSToggleRow title="Auto-respond to every review" desc="Personalized templates within 24 hours" value={!!g.rev?.respond} onChange={v=>u({ rev: { ...(g.rev||{}), respond:v } })} tone="chart"/>
          <OSToggleRow title="Owner alert below 4 stars" desc="Instant push the moment it hits" value={g.rev?.alert ?? true} onChange={v=>u({ rev: { ...(g.rev||{}), alert:v } })} tone="lilac"/>
        </div>
      </OSSection>
    </>
  );
}

/* ============================================================
   PHASE 10 — ADVANCED INTELLIGENCE
   ============================================================ */
function OSPhase10({ state, set }) {
  const intel = state.intel || {};
  const u = (patch) => set('intel', { ...intel, ...patch });

  return (
    <>
      <OSSection num="10.1" kicker="Anomaly detection" title="What should we flag — and how loudly?">
        <div style={{ display:'grid', gap:10 }}>
          {ANOMALY_CATEGORIES.map(a => (
            <div key={a} style={{ display:'grid', gridTemplateColumns:'1fr 220px 100px', gap:14, alignItems:'center', padding:'12px 16px', background:'var(--paper)', border:'1px solid var(--line)', borderRadius:10 }}>
              <span style={{ fontSize:13.5, color:'var(--ink)' }}>{a}</span>
              <OSSlider value={intel.thresholds?.[a] ?? 50} onChange={v=>u({ thresholds:{ ...(intel.thresholds||{}), [a]:v } })} min={0} max={100} suffix="%" tone="lilac"/>
              <OSSwitch value={intel.on?.[a] ?? true} onChange={v=>u({ on:{ ...(intel.on||{}), [a]:v } })} tone="lilac"/>
            </div>
          ))}
        </div>
      </OSSection>

      <OSSection num="10.2" kicker="Predictive models" title="What can we see before it happens?" sub="Each model needs 60–90 days of clean data to fire. Turn them on now so they start learning.">
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:10 }}>
          {PREDICTIVE_MODELS.map(m => (
            <OSToggleRow key={m.id} title={m.name} desc={m.desc} value={!!intel.pred?.[m.id]} onChange={v=>u({ pred: { ...(intel.pred||{}), [m.id]:v } })} tone="chart"/>
          ))}
        </div>
      </OSSection>

      <OSSection num="10.3" kicker="Dynamic pricing" title="What inputs influence the recommended price?">
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:14 }}>
          {[
            ['Schedule density', 30],
            ['Job urgency', 20],
            ['Customer history', 15],
            ['Neighborhood', 10],
            ['Competitor pricing', 10],
            ['Day of week', 5],
            ['Time of day', 5],
            ['Season', 5],
          ].map(([factor, def]) => (
            <div key={factor} style={{ padding:'12px 14px', background:'var(--paper)', border:'1px solid var(--line)', borderRadius:10 }}>
              <div style={{ fontSize:13, color:'var(--ink)', fontWeight:500, marginBottom:6 }}>{factor}</div>
              <OSSlider value={intel.priceWeight?.[factor] ?? def} onChange={v=>u({ priceWeight: { ...(intel.priceWeight||{}), [factor]:v } })} min={0} max={50} suffix="% weight" tone="chart"/>
            </div>
          ))}
        </div>
        <div style={{ marginTop:14, padding:'14px 16px', background:'var(--chart-50)', border:'1px solid var(--chart-200)', borderRadius:12, fontSize:13, color:'var(--chart-900)' }}>
          <strong>Price floor & ceiling</strong> per service type configured per-service in your Operations dashboard. HomePro never goes outside these bounds.
        </div>
      </OSSection>

      <OSSection num="10.4" kicker="Knowledge capture" title="The institutional memory project.">
        <div style={{ display:'grid', gap:10 }}>
          <OSToggleRow title="Ask 'why' on every AI override" desc="Capture the reasoning. Model adjusts." value={intel.kc?.why ?? true} onChange={v=>u({ kc:{ ...(intel.kc||{}), why:v } })} tone="lilac"/>
          <OSToggleRow title="Capture pricing deviations with notes" desc="Why we went above or below the recommendation" value={intel.kc?.price ?? true} onChange={v=>u({ kc:{ ...(intel.kc||{}), price:v } })} tone="lilac"/>
          <OSToggleRow title="Owner-only knowledge entries" desc="Neighborhood quirks · vendor preferences · customer handling rules" value={intel.kc?.owner ?? true} onChange={v=>u({ kc:{ ...(intel.kc||{}), owner:v } })} tone="lilac"/>
        </div>
        <div style={{ marginTop:14, padding:'14px 16px', background:'var(--ink)', color:'var(--paper)', borderRadius:12 }}>
          <div style={{ fontSize:11, fontWeight:700, letterSpacing:'0.1em', textTransform:'uppercase', color:'var(--chart-300)', marginBottom:4 }}>Why this matters at exit</div>
          <div style={{ fontSize:13, lineHeight:1.5, color:'var(--mute-3)' }}>
            A business whose knowledge lives in the system, not just the owner's head, is worth multiples more than one where the value walks out the door at 5pm.
          </div>
        </div>
      </OSSection>

      <OSSection num="10.5" kicker="Benchmarks" title="Compare against what.">
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:10 }}>
          {[
            ['Industry averages for your trade','Trade-specific'],
            ['Revenue-tier peers','Operators your size'],
            ['Top performers in your market','Hyper-local'],
            ['Your own historical performance','Self-compared'],
          ].map(([what, why]) => (
            <OSToggleRow key={what} title={what} desc={why} value={intel.bench?.[what] ?? true} onChange={v=>u({ bench: { ...(intel.bench||{}), [what]:v } })} tone="chart"/>
          ))}
        </div>
      </OSSection>
    </>
  );
}

/* ============================================================
   PHASE 11 — TECHNICAL SETUP
   ============================================================ */
function OSPhase11({ state, set }) {
  const tech = state.tech || {};
  const u = (patch) => set('tech', { ...tech, ...patch });

  return (
    <>
      <OSSection num="11.1" kicker="Website integration" title="The line of code that lets us see everything.">
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:14 }}>
          <OSField label="Your website URL" value={tech.url} onChange={v=>u({ url:v })} placeholder="https://chapmansac.com"/>
          <OSField label="Platform" value={tech.platform} onChange={v=>u({ platform:v })} placeholder="WordPress / Squarespace / custom"/>
        </div>
        <div style={{ marginTop:12, padding:'14px 16px', background:'var(--ink)', color:'var(--chart-200)', borderRadius:12, fontFamily:'var(--font-mono)', fontSize:12 }}>
          {`<script src="https://homepro.ai/c/${(tech.url||'YOUR-ID').replace(/[^a-z0-9]/gi,'').slice(0,12).toLowerCase() || 'install-id'}.js" async></script>`}
        </div>
      </OSSection>

      <OSSection num="11.2" kicker="Phone system" title="Where calls come in.">
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap:14 }}>
          <OSField label="Main business number" value={tech.phone} onChange={v=>u({ phone:v })} placeholder="(512) 555-0140" mono/>
          <OSField label="After-hours number" value={tech.phoneAh} onChange={v=>u({ phoneAh:v })} placeholder="same / different"/>
          <OSField label="Emergency line" value={tech.phoneE} onChange={v=>u({ phoneE:v })} placeholder="optional" mono/>
        </div>
        <div style={{ marginTop:14, display:'grid', gridTemplateColumns:'1fr 1fr', gap:10 }}>
          <OSToggleRow title="AI answers business hours" desc="Qualify → book → handoff if needed" value={tech.aiBh ?? true} onChange={v=>u({ aiBh:v })} tone="chart"/>
          <OSToggleRow title="AI answers after-hours" desc="Triage emergencies · book non-urgent" value={tech.aiAh ?? true} onChange={v=>u({ aiAh:v })} tone="chart"/>
        </div>
      </OSSection>

      <OSSection num="11.3" kicker="Email" title="Where automated emails come from.">
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:14 }}>
          <OSField label="From name" value={tech.fromName} onChange={v=>u({ fromName:v })} placeholder="Chapman's HVAC"/>
          <OSField label="Reply-to address" value={tech.reply} onChange={v=>u({ reply:v })} placeholder="hello@chapmansac.com"/>
        </div>
        <div style={{ marginTop:10 }}>
          <OSField label="Email signature" value={tech.sig} onChange={v=>u({ sig:v })} placeholder="— The Chapman's team · (512) 555-0140 · chapmansac.com"/>
        </div>
      </OSSection>

      <OSSection num="11.4" kicker="SMS" title="Texts go out from here.">
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:14 }}>
          <OSField label="SMS number type" value={tech.smsType} onChange={v=>u({ smsType:v })} placeholder="Dedicated HomePro number"/>
          <OSField label="Opt-in language" value={tech.smsOpt} onChange={v=>u({ smsOpt:v })} placeholder="By booking, you agree to receive service-related texts."/>
        </div>
      </OSSection>

      <OSSection num="11.5" kicker="Apps & devices" title="Send setup invites to your team."  sub="One invite per team member. Each is customized for the role with exact instructions.">
        <div style={{ padding:'16px', background:'var(--paper-3)', border:'1px solid var(--line)', borderRadius:12 }}>
          <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:10 }}>
            <span style={{ fontSize:13, color:'var(--ink)', fontWeight:600 }}>{(state.team || []).length} team members ready to invite</span>
            <button type="button" style={btnTinyDark}>Send all invites →</button>
          </div>
          <div style={{ display:'grid', gap:6 }}>
            {(state.team || []).map(m => (
              <div key={m.id} style={{ display:'flex', justifyContent:'space-between', padding:'8px 12px', background:'var(--paper)', border:'1px solid var(--line-2)', borderRadius:8, fontSize:12.5 }}>
                <span style={{ color:'var(--ink)' }}>{m.name || '(unnamed)'} · <span style={{ color:'var(--mute-1)' }}>{ROLES.find(r => r.id === m.role)?.name}</span></span>
                <span style={{ color:'var(--mute-1)', fontFamily:'var(--font-mono)' }}>{m.email || '— no email —'}</span>
              </div>
            ))}
          </div>
        </div>
      </OSSection>
    </>
  );
}

/* ============================================================
   PHASE 12 — LAUNCH PLAN
   ============================================================ */
function computeProjections(state) {
  const tier = state.identity?.revenue || 'r3';
  const tierIdx = REVENUE_TIERS.findIndex(t => t.id === tier);
  const i = Math.max(0, tierIdx);
  const revBase = [180000, 360000, 720000, 1500000, 2500000, 4000000, 7000000, 14000000][i];
  const closeBase   = [38, 42, 47, 54, 57, 60, 63, 65][i];
  const closeTarget = Math.min(80, closeBase + 14);
  const cplBase     = [120, 110, 99, 91, 87, 82, 78, 74][i];
  const cplTarget   = Math.round(cplBase * 0.42);
  const reactRev    = Math.round(revBase * 0.031 / 1000) * 1000;
  const dormant     = Math.max(40, Math.round(revBase / 4800));
  const teamMap     = { 'Just me':1, '2 – 5':3, '6 – 10':8, '11 – 25':18, '26 – 50':38, '50+':60 };
  const teamSize    = teamMap[state.identity?.team] || 5;
  const reviews     = Math.max(12, Math.round(teamSize * 7.5));
  return { closeBase, closeTarget, cplBase, cplTarget, reactRev, dormant, reviews };
}

function OSPhase12({ state, set }) {
  const pricing  = osBuilderPricing(state);
  const proj     = computeProjections(state);
  const ident    = state.identity || {};
  const tradeName = ident.trades?.length ? TRADES.filter(t => ident.trades.includes(t.id)).map(t => t.name).join(' · ') : 'your trade';

  const ownerMember = (state.team || []).find(m => m.role === 'owner');
  const [stage,   setStage]   = React.useState('idle');
  const [contact, setContact] = React.useState({
    name:  ownerMember?.name  || '',
    email: ownerMember?.email || state.tech?.reply || '',
    phone: state.tech?.phone  || '',
  });

  const handleLaunch = async (e) => {
    e.preventDefault();
    setStage('sending');
    const _SB_HDR = {
      'Content-Type': 'application/json',
      'apikey': 'sb_publishable_zjIBmAqBIlUTEEz2wS3eVw_W7_bCJZK',
      'Authorization': 'Bearer sb_publishable_zjIBmAqBIlUTEEz2wS3eVw_W7_bCJZK',
    };
    const existingOpId = (() => { try { return localStorage.getItem('hp-operator-id'); } catch { return null; } })();
    try {
      if (existingOpId) {
        await fetch(`https://gbwadswhrvsxorbivjjc.supabase.co/rest/v1/operators?id=eq.${existingOpId}`, {
          method: 'PATCH',
          headers: _SB_HDR,
          body: JSON.stringify({
            email:      contact.email || null,
            owner_name: contact.name  || null,
            phone:      contact.phone || null,
            biz_name:   ident.bizName || null,
            trade:      tradeName     || null,
            plan_tier:  'full',
            os_state:   state,
            status:     'active',
          }),
        });
      } else {
        const res = await fetch('https://gbwadswhrvsxorbivjjc.supabase.co/rest/v1/operators', {
          method: 'POST',
          headers: { ..._SB_HDR, 'Prefer': 'return=representation' },
          body: JSON.stringify({
            email:              contact.email || null,
            owner_name:         contact.name  || null,
            phone:              contact.phone || null,
            biz_name:           ident.bizName || null,
            trade:              tradeName     || null,
            plan_tier:          'full',
            onboarding_answers: {},
            os_state:           state,
            status:             'active',
          }),
        });
        if (res.ok) {
          const [op] = await res.json();
          if (op?.id) { try { localStorage.setItem('hp-operator-id', op.id); } catch {} }
        }
      }
    } catch {}
    try {
      fetch('/api/send-osbuilder', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          contact,
          bizName:         ident.bizName,
          trade:           tradeName,
          revenue:         REVENUE_TIERS.find(r => r.id === ident.revenue)?.label,
          team:            ident.team,
          moduleCount:     pricing.moduleCount,
          automationCount: pricing.automationCount,
          setup:           pricing.setup,
          retainer:        pricing.retainer,
          state,
        }),
      }).catch(() => {});
    } catch {}
    setStage('done');
  };

  return (
    <>
      <OSSection num="12.1" kicker="Your custom OS · summary" title={`This is the ${ident.bizName || 'business'} operating system.`} sub="Everything you built, in one view. Departments. Modules. Automations. Integrations. Compliance. Team.">
        <div style={{ display:'grid', gridTemplateColumns:'repeat(4,1fr)', gap:10 }}>
          <OSStat label="Data sources" value={pricing.connectionCount} sub={`+${pricing.bi} BI`} tone="chart"/>
          <OSStat label="AI modules" value={pricing.moduleCount} sub="across 6 depts" tone="lilac"/>
          <OSStat label="Automations" value={pricing.automationCount} sub="live on launch" tone="chart"/>
          <OSStat label="Team members" value={(state.team || []).length} sub="invited" tone="lilac"/>
        </div>
        <div style={{ marginTop:14, padding:'18px 22px', background:'var(--ink)', borderRadius:16, color:'var(--paper)' }}>
          <div style={{ display:'flex', alignItems:'baseline', justifyContent:'space-between', gap:14, flexWrap:'wrap' }}>
            <div>
              <div style={{ fontSize:10.5, fontWeight:700, letterSpacing:'0.14em', textTransform:'uppercase', color:'var(--chart-300)' }}>Built for</div>
              <div style={{ fontFamily:'var(--font-display)', fontSize:28, fontWeight:500, letterSpacing:'-0.025em', marginTop:2 }}>{ident.bizName || 'your business'}</div>
              <div style={{ fontSize:13, color:'var(--mute-3)', marginTop:2 }}>{tradeName} · {REVENUE_TIERS.find(r => r.id === ident.revenue)?.label} · {(ident.team || '—')} team</div>
            </div>
            <div style={{ display:'flex', gap:18, flexWrap:'wrap' }}>
              <DarkStat label="Setup" value={`$${pricing.setup.toLocaleString()}`}/>
              <DarkStat label="Monthly" value={`$${pricing.retainer.toLocaleString()}`}/>
              <DarkStat label="12-mo ROI" value={`+$${Math.round(pricing.liftDollars/1000)}K`}/>
            </div>
          </div>
        </div>
      </OSSection>

      <OSSection num="12.2" kicker="The model · pay per outcome" title="The only software that only charges when it works.">
        <div style={{ padding:'24px 28px', background:'var(--ink)', borderRadius:20, color:'var(--paper)', marginBottom:14 }}>
          <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap:24 }}>
            <div>
              <div style={{ fontFamily:'var(--font-display)', fontSize:52, fontWeight:500, color:'var(--chart-300)', letterSpacing:'-0.04em', lineHeight:1 }}>$0</div>
              <div style={{ fontSize:12.5, color:'var(--mute-3)', marginTop:6, lineHeight:1.5 }}>What you pay if HomePro does not generate growth. The success fee does not apply.</div>
            </div>
            <div>
              <div style={{ fontFamily:'var(--font-display)', fontSize:52, fontWeight:500, color:'var(--chart-300)', letterSpacing:'-0.04em', lineHeight:1 }}>5%</div>
              <div style={{ fontSize:12.5, color:'var(--mute-3)', marginTop:6, lineHeight:1.5 }}>Of revenue HomePro provably creates beyond your day-one baseline. Tracked to the dollar. Fully transparent.</div>
            </div>
            <div>
              <div style={{ fontFamily:'var(--font-display)', fontSize:52, fontWeight:500, color:'var(--chart-300)', letterSpacing:'-0.04em', lineHeight:1 }}>10x</div>
              <div style={{ fontSize:12.5, color:'var(--mute-3)', marginTop:6, lineHeight:1.5 }}>ROI most clients see in year one. The average HomePro client generates $80K–$200K in provable new revenue.</div>
            </div>
          </div>
          <div style={{ marginTop:20, paddingTop:20, borderTop:'1px solid rgba(255,255,255,.08)', fontSize:13.5, color:'var(--mute-3)', lineHeight:1.6 }}>
            Most software charges whether it works or not. HomePro connects your bank on day one and sets a baseline. Every dollar it generates after that is tracked, proved, and shared at 5%. If it does not grow your business, you do not pay the performance fee. The bank is the referee.
          </div>
        </div>
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap:10 }}>
          <div style={{ padding:'16px', background:'var(--paper)', border:'1px solid var(--line)', borderRadius:14 }}>
            <div style={{ fontSize:10.5, fontWeight:700, letterSpacing:'0.12em', textTransform:'uppercase', color:'var(--mute-1)' }}>Setup · one-time</div>
            <div style={{ fontFamily:'var(--font-display)', fontSize:28, fontWeight:500, color:'var(--ink)', letterSpacing:'-0.025em', marginTop:4 }}>${pricing.setup.toLocaleString()}</div>
            <div style={{ fontSize:11.5, color:'var(--mute-1)', marginTop:4, lineHeight:1.5 }}>Deep onboarding · diagnosis · configuration · training.</div>
          </div>
          <div style={{ padding:'16px', background:'var(--paper)', border:'1px solid var(--line)', borderRadius:14 }}>
            <div style={{ fontSize:10.5, fontWeight:700, letterSpacing:'0.12em', textTransform:'uppercase', color:'var(--mute-1)' }}>Monthly retainer</div>
            <div style={{ fontFamily:'var(--font-display)', fontSize:28, fontWeight:500, color:'var(--ink)', letterSpacing:'-0.025em', marginTop:4 }}>${pricing.retainer.toLocaleString()}</div>
            <div style={{ fontSize:11.5, color:'var(--mute-1)', marginTop:4, lineHeight:1.5 }}>Base + {pricing.moduleCount} modules + {pricing.automationCount} automations.</div>
          </div>
          <div style={{ padding:'16px', background:'var(--chart-100)', border:'2px solid var(--chart-500)', borderRadius:14 }}>
            <div style={{ fontSize:10.5, fontWeight:700, letterSpacing:'0.12em', textTransform:'uppercase', color:'var(--chart-900)' }}>Success fee</div>
            <div style={{ fontFamily:'var(--font-display)', fontSize:28, fontWeight:500, color:'var(--chart-900)', letterSpacing:'-0.025em', marginTop:4 }}>5% of growth</div>
            <div style={{ fontSize:11.5, color:'var(--chart-700)', marginTop:4, lineHeight:1.5 }}>On data-proven new revenue only. Zero if we don't perform.</div>
          </div>
        </div>
      </OSSection>

      <OSSection num="12.3" kicker="Launch sequence" title="What happens — by when." sub="Specific activations from your configuration, not a generic roadmap.">
        <div style={{ display:'grid', gap:8 }}>
          {[
            ['Day 1','Business Health Biomarkers go live on your dashboard. Close rate, cash runway, review velocity, team retention, valuation — all reading from your connected data.','Live'],
            ['Week 1','Every module you activated turns on. Automations start firing. CRM, bank, and review platform data flows in automatically.','Active'],
            ['Week 2','Integrations deepen. CRM and bank reconcile job revenue to the dollar. First gaps and opportunities surface.','Diagnosing'],
            ['Week 3','Dashboards fully populated with your data. First growth recommendations arrive. Owner morning briefings begin.','Reading'],
            ['Month 1','Equipment Health Monitoring builds health profiles for every customer. Proactive outreach starts — your team calls customers before competitors do.','Predicting'],
            ['Month 2','Weekly technician coaching briefs go out every Monday, personalized to each tech's prior week. Reactivation campaigns generate first new revenue.','Coaching'],
            ['Month 3','First full business diagnosis complete. Every metric benchmarked against trade peers. 90-day plan updates with real numbers — not projections.','Compounding'],
          ].map(([when, what, status], i) => (
            <div key={when} style={{ display:'grid', gridTemplateColumns:'100px 1fr 120px', alignItems:'center', gap:14, padding:'14px 18px', background: i%2 ? 'var(--paper-3)' : 'var(--paper)', border:'1px solid var(--line)', borderRadius:12 }}>
              <span style={{ fontFamily:'var(--font-mono)', fontSize:11, fontWeight:700, color:'var(--lilac-700)' }}>{when}</span>
              <span style={{ fontSize:13, color:'var(--ink)', lineHeight:1.45 }}>{what}</span>
              <span style={{ fontSize:10.5, fontWeight:700, letterSpacing:'0.07em', textTransform:'uppercase', color:'var(--chart-900)', background:'var(--chart-200)', padding:'4px 10px', borderRadius:99, textAlign:'center' }}>{status}</span>
            </div>
          ))}
        </div>
      </OSSection>

      <OSSection num="12.4" kicker="90-day targets" title="The numbers we move first." sub="Projections from your revenue tier and team size. These become your baseline on day one.">
        <div style={{ display:'grid', gridTemplateColumns:'repeat(4,1fr)', gap:10 }}>
          <OSStat label="Close rate" value={`${proj.closeBase}% → ${proj.closeTarget}%`} sub={`+${proj.closeTarget - proj.closeBase}pts`} tone="chart"/>
          <OSStat label="Cost per lead" value={`$${proj.cplBase} → $${proj.cplTarget}`} sub={`-${Math.round((1 - proj.cplTarget / proj.cplBase) * 100)}%`} tone="chart"/>
          <OSStat label="Reactivation revenue" value={`+$${Math.round(proj.reactRev / 1000)}K`} sub={`from ${proj.dormant} dormant`} tone="lilac"/>
          <OSStat label="Reviews captured" value={`+${proj.reviews}`} sub="60 days" tone="lilac"/>
        </div>
      </OSSection>

      <OSSection num="12.6" kicker="Launch" title={stage === 'done' ? "You're in." : "One button."}>
        {stage === 'done' ? (
          <div style={{ padding:'36px 32px', background:'var(--ink)', borderRadius:20, textAlign:'center', color:'var(--paper)' }}>
            <div style={{ width:52, height:52, borderRadius:99, background:'var(--chart-300)', display:'flex', alignItems:'center', justifyContent:'center', margin:'0 auto 18px' }}>
              <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="var(--ink)" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
            </div>
            <div style={{ fontFamily:'var(--font-display)', fontSize:26, fontWeight:500, letterSpacing:'-0.02em', marginBottom:8 }}>Your build is submitted.</div>
            <div style={{ fontSize:13.5, color:'var(--mute-3)', lineHeight:1.6, maxWidth:380, margin:'0 auto' }}>Expect a call within 24 hours. Your full configuration — {pricing.moduleCount} modules, {pricing.automationCount} automations — is already in your file.</div>
          </div>
        ) : stage === 'form' ? (
          <div style={{ padding:'28px 28px 24px', background:'var(--ink)', borderRadius:20, color:'var(--paper)' }}>
            <div style={{ fontSize:13, color:'var(--mute-3)', marginBottom:20 }}>You've made {countDecisions(state)} decisions across 12 phases. Let's get your install scheduled.</div>
            <form onSubmit={handleLaunch}>
              <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap:12, marginBottom:16 }}>
                {[
                  { label:'Your name', key:'name', placeholder:'Jordan Chapman', type:'text' },
                  { label:'Best email', key:'email', placeholder:'you@yourbiz.com', type:'email' },
                  { label:'Best phone', key:'phone', placeholder:'(512) 555-0140', type:'tel' },
                ].map(({ label, key, placeholder, type }) => (
                  <div key={key}>
                    <div style={{ fontSize:10.5, fontWeight:700, letterSpacing:'0.12em', textTransform:'uppercase', color:'var(--chart-200)', marginBottom:6 }}>{label}</div>
                    <input
                      type={type} required value={contact[key]}
                      onChange={e => setContact(c => ({ ...c, [key]: e.target.value }))}
                      placeholder={placeholder}
                      style={{ width:'100%', padding:'10px 12px', border:'1px solid rgba(255,255,255,0.12)', borderRadius:9, background:'rgba(255,255,255,0.07)', color:'var(--paper)', fontFamily:'var(--font-body)', fontSize:13, outline:'none' }}
                    />
                  </div>
                ))}
              </div>
              <div style={{ display:'flex', gap:10, alignItems:'center' }}>
                <button type="submit" style={{ background:'var(--chart-300)', color:'var(--ink)', border:0, padding:'14px 32px', borderRadius:99, fontFamily:'var(--font-display)', fontWeight:600, fontSize:16, letterSpacing:'-0.015em', cursor:'pointer', boxShadow:'0 8px 30px rgba(196,240,0,0.35)' }}>
                  Send my build →
                </button>
                <button type="button" onClick={() => setStage('idle')} style={{ background:'transparent', border:'1px solid rgba(255,255,255,0.15)', color:'var(--mute-3)', padding:'14px 20px', borderRadius:99, fontSize:13, cursor:'pointer', fontFamily:'var(--font-body)' }}>
                  Back
                </button>
              </div>
              <div style={{ fontSize:11.5, color:'var(--mute-2)', marginTop:12 }}>Opens your email client. We'll reach out within 24 hours to schedule your install call.</div>
            </form>
          </div>
        ) : (
          <div style={{ padding:'32px', background:'var(--ink)', borderRadius:20, textAlign:'center', color:'var(--paper)' }}>
            <div style={{ fontSize:13, color:'var(--mute-3)', marginBottom:14 }}>You've made {countDecisions(state)} decisions across 12 phases. This is your operating system, not ours.</div>
            <button type="button" onClick={() => setStage('form')} style={{
              background:'var(--chart-300)', color:'var(--ink)', border:0,
              padding:'18px 42px', borderRadius:99,
              fontFamily:'var(--font-display)', fontWeight:600, fontSize:18, letterSpacing:'-0.015em',
              cursor:'pointer', boxShadow:'0 16px 50px rgba(196,240,0,0.4)',
            }}>Launch my business →</button>
            <div style={{ fontSize:12, color:'var(--mute-3)', marginTop:14 }}>Modules turn on. Automations fire. Data flows. Your install team is already on the way.</div>
          </div>
        )}
      </OSSection>
    </>
  );
}

function DarkStat({ label, value }) {
  return (
    <div>
      <div style={{ fontSize:10.5, fontWeight:700, letterSpacing:'0.12em', textTransform:'uppercase', color:'var(--chart-200)', opacity:0.7 }}>{label}</div>
      <div style={{ fontFamily:'var(--font-display)', fontSize:24, fontWeight:500, color:'var(--chart-300)', letterSpacing:'-0.025em', marginTop:2 }}>{value}</div>
    </div>
  );
}

function countDecisions(state) {
  let n = 0;
  const walk = (o) => {
    if (o == null) return;
    if (Array.isArray(o)) { n += o.length; return; }
    if (typeof o === 'object') { Object.values(o).forEach(walk); return; }
    if (typeof o === 'boolean' && o) n += 1;
    else if (typeof o === 'string' && o.length > 0) n += 1;
    else if (typeof o === 'number') n += 1;
  };
  walk(state);
  return n;
}

Object.assign(window, { OSPhase7, OSPhase8, OSPhase9, OSPhase10, OSPhase11, OSPhase12 });